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 \
789 DO_FUNC(cupsGetPPD3);
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 );
836 HeapFree( GetProcessHeap(), 0, unix_name );
838 if (http_status == HTTP_OK) return TRUE;
840 TRACE( "failed to get ppd for printer %s from cups, calling fallback\n", debugstr_a(printer_name) );
841 return get_fallback_ppd( printer_name, ppd );
844 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
850 value = pcupsGetOption( name, num_options, options );
851 if (!value) return NULL;
853 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
854 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
855 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
860 static cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
862 WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
863 cups_ptype_t ret = 0;
867 ret = (cups_ptype_t)strtoulW( type, &end, 10 );
870 HeapFree( GetProcessHeap(), 0, type );
874 static BOOL CUPS_LoadPrinters(void)
877 BOOL hadprinter = FALSE, haddefault = FALSE;
880 WCHAR *port, *ppd_dir = NULL, *ppd;
881 HKEY hkeyPrinter, hkeyPrinters;
883 WCHAR nameW[MAX_PATH];
884 HANDLE added_printer;
885 cups_ptype_t printer_type;
887 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
889 TRACE("%s\n", loaderror);
892 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
894 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
897 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 );
901 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
903 ERR("Can't create Printers key\n");
907 nrofdests = pcupsGetDests(&dests);
908 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
909 for (i=0;i<nrofdests;i++) {
910 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
911 printer_type = get_cups_printer_type( dests + i );
913 TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
915 if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
917 TRACE( "skipping scanner-only device\n" );
921 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
922 lstrcpyW(port, CUPS_Port);
923 lstrcatW(port, nameW);
925 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
926 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
927 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
929 TRACE("Printer already exists\n");
930 /* overwrite old LPR:* port */
931 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
932 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
933 /* flag that the PPD file should be checked for an update */
934 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
935 RegCloseKey(hkeyPrinter);
937 BOOL added_driver = FALSE;
939 if (!ppd_dir) ppd_dir = get_ppd_dir();
940 ppd = get_ppd_filename( ppd_dir, nameW );
941 if (get_cups_ppd( dests[i].name, ppd ))
943 added_driver = add_printer_driver( nameW, ppd );
946 HeapFree( GetProcessHeap(), 0, ppd );
947 if (!added_driver) continue;
949 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
950 pi2.pPrinterName = nameW;
951 pi2.pDatatype = rawW;
952 pi2.pPrintProcessor = WinPrintW;
953 pi2.pDriverName = nameW;
954 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
955 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
956 pi2.pPortName = port;
957 pi2.pParameters = emptyStringW;
958 pi2.pShareName = emptyStringW;
959 pi2.pSepFile = emptyStringW;
961 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
962 if (added_printer) ClosePrinter( added_printer );
963 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
964 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
966 HeapFree( GetProcessHeap(), 0, pi2.pComment );
967 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
969 HeapFree( GetProcessHeap(), 0, port );
972 if (dests[i].is_default) {
973 SetDefaultPrinterW(nameW);
980 RemoveDirectoryW( ppd_dir );
981 HeapFree( GetProcessHeap(), 0, ppd_dir );
984 if (hadprinter && !haddefault) {
985 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
986 SetDefaultPrinterW(nameW);
988 pcupsFreeDests(nrofdests, dests);
989 RegCloseKey(hkeyPrinters);
995 static char *get_queue_name( HANDLE printer, BOOL *cups )
997 WCHAR *port, *name = NULL;
998 DWORD err, needed, type;
1004 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1005 if (err) return NULL;
1006 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1008 port = HeapAlloc( GetProcessHeap(), 0, needed );
1009 if (!port) goto end;
1010 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1012 if (!strncmpW( port, CUPS_Port, sizeof(CUPS_Port) / sizeof(WCHAR) -1 ))
1014 name = port + sizeof(CUPS_Port) / sizeof(WCHAR) - 1;
1017 else if (!strncmpW( port, LPR_Port, sizeof(LPR_Port) / sizeof(WCHAR) -1 ))
1018 name = port + sizeof(LPR_Port) / sizeof(WCHAR) - 1;
1021 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1022 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1023 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1025 HeapFree( GetProcessHeap(), 0, port );
1032 static void set_ppd_overrides( HANDLE printer )
1036 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1038 PMPrintSession session = NULL;
1039 PMPageFormat format = NULL;
1041 CFStringRef paper_name;
1044 status = PMCreateSession( &session );
1045 if (status) goto end;
1047 status = PMCreatePageFormat( &format );
1048 if (status) goto end;
1050 status = PMSessionDefaultPageFormat( session, format );
1051 if (status) goto end;
1053 status = PMGetPageFormatPaper( format, &paper );
1054 if (status) goto end;
1056 status = PMPaperGetPPDPaperName( paper, &paper_name );
1057 if (status) goto end;
1060 range.length = CFStringGetLength( paper_name );
1061 size = (range.length + 1) * sizeof(WCHAR);
1063 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1064 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1065 wstr[range.length] = 0;
1068 if (format) PMRelease( format );
1069 if (session) PMRelease( session );
1072 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1073 HeapFree( GetProcessHeap(), 0, wstr );
1076 static BOOL update_driver( HANDLE printer )
1079 const WCHAR *name = get_opened_printer_name( printer );
1080 WCHAR *ppd_dir, *ppd;
1083 if (!name) return FALSE;
1084 queue_name = get_queue_name( printer, &is_cups );
1085 if (!queue_name) return FALSE;
1087 ppd_dir = get_ppd_dir();
1088 ppd = get_ppd_filename( ppd_dir, name );
1090 #ifdef SONAME_LIBCUPS
1092 ret = get_cups_ppd( queue_name, ppd );
1095 ret = get_fallback_ppd( queue_name, ppd );
1099 TRACE( "updating driver %s\n", debugstr_w( name ) );
1100 ret = add_printer_driver( name, ppd );
1103 HeapFree( GetProcessHeap(), 0, ppd_dir );
1104 HeapFree( GetProcessHeap(), 0, ppd );
1105 HeapFree( GetProcessHeap(), 0, queue_name );
1107 set_ppd_overrides( printer );
1109 /* call into the driver to update the devmode */
1110 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1115 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1117 PRINTER_INFO_2A pinfo2a;
1120 char *e,*s,*name,*prettyname,*devname;
1121 BOOL ret = FALSE, set_default = FALSE;
1122 char *port = NULL, *env_default;
1123 HKEY hkeyPrinter, hkeyPrinters = NULL;
1124 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1125 HANDLE added_printer;
1127 while (isspace(*pent)) pent++;
1128 r = strchr(pent,':');
1130 name_len = r - pent;
1132 name_len = strlen(pent);
1133 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1134 memcpy(name, pent, name_len);
1135 name[name_len] = '\0';
1141 TRACE("name=%s entry=%s\n",name, pent);
1143 if(ispunct(*name)) { /* a tc entry, not a real printer */
1144 TRACE("skipping tc entry\n");
1148 if(strstr(pent,":server")) { /* server only version so skip */
1149 TRACE("skipping server entry\n");
1153 /* Determine whether this is a postscript printer. */
1156 env_default = getenv("PRINTER");
1158 /* Get longest name, usually the one at the right for later display. */
1159 while((s=strchr(prettyname,'|'))) {
1162 while(isspace(*--e)) *e = '\0';
1163 TRACE("\t%s\n", debugstr_a(prettyname));
1164 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1165 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1168 e = prettyname + strlen(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;
1173 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1174 * if it is too long, we use it as comment below. */
1175 devname = prettyname;
1176 if (strlen(devname)>=CCHDEVICENAME-1)
1178 if (strlen(devname)>=CCHDEVICENAME-1) {
1183 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1184 sprintf(port,"LPR:%s",name);
1186 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1188 ERR("Can't create Printers key\n");
1193 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
1195 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1196 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1197 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1199 TRACE("Printer already exists\n");
1200 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1201 /* flag that the PPD file should be checked for an update */
1202 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1203 RegCloseKey(hkeyPrinter);
1205 static CHAR data_type[] = "RAW",
1206 print_proc[] = "WinPrint",
1207 comment[] = "WINEPS Printer using LPR",
1208 params[] = "<parameters?>",
1209 share_name[] = "<share name?>",
1210 sep_file[] = "<sep file?>";
1211 BOOL added_driver = FALSE;
1213 if (!ppd_dir) ppd_dir = get_ppd_dir();
1214 ppd = get_ppd_filename( ppd_dir, devnameW );
1215 if (get_fallback_ppd( devname, ppd ))
1217 added_driver = add_printer_driver( devnameW, ppd );
1220 HeapFree( GetProcessHeap(), 0, ppd );
1221 if (!added_driver) goto end;
1223 memset(&pinfo2a,0,sizeof(pinfo2a));
1224 pinfo2a.pPrinterName = devname;
1225 pinfo2a.pDatatype = data_type;
1226 pinfo2a.pPrintProcessor = print_proc;
1227 pinfo2a.pDriverName = devname;
1228 pinfo2a.pComment = comment;
1229 pinfo2a.pLocation = prettyname;
1230 pinfo2a.pPortName = port;
1231 pinfo2a.pParameters = params;
1232 pinfo2a.pShareName = share_name;
1233 pinfo2a.pSepFile = sep_file;
1235 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1236 if (added_printer) ClosePrinter( added_printer );
1237 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1238 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1241 if (isfirst || set_default)
1242 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1245 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1248 RemoveDirectoryW( ppd_dir );
1249 HeapFree( GetProcessHeap(), 0, ppd_dir );
1251 HeapFree(GetProcessHeap(), 0, port);
1252 HeapFree(GetProcessHeap(), 0, name);
1257 PRINTCAP_LoadPrinters(void) {
1258 BOOL hadprinter = FALSE;
1262 BOOL had_bash = FALSE;
1264 f = fopen("/etc/printcap","r");
1268 while(fgets(buf,sizeof(buf),f)) {
1271 end=strchr(buf,'\n');
1275 while(isspace(*start)) start++;
1276 if(*start == '#' || *start == '\0')
1279 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1280 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1281 HeapFree(GetProcessHeap(),0,pent);
1285 if (end && *--end == '\\') {
1292 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1295 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1301 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1302 HeapFree(GetProcessHeap(),0,pent);
1308 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1311 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1312 (lstrlenW(value) + 1) * sizeof(WCHAR));
1314 return ERROR_FILE_NOT_FOUND;
1317 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1319 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1320 DWORD ret = ERROR_FILE_NOT_FOUND;
1322 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1323 and we support these drivers. NT writes DEVMODEW so somehow
1324 we'll need to distinguish between these when we support NT
1329 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1330 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1331 HeapFree( GetProcessHeap(), 0, dmA );
1337 /******************************************************************
1338 * get_servername_from_name (internal)
1340 * for an external server, a copy of the serverpart from the full name is returned
1343 static LPWSTR get_servername_from_name(LPCWSTR name)
1347 WCHAR buffer[MAX_PATH];
1350 if (name == NULL) return NULL;
1351 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1353 server = strdupW(&name[2]); /* skip over both backslash */
1354 if (server == NULL) return NULL;
1356 /* strip '\' and the printername */
1357 ptr = strchrW(server, '\\');
1358 if (ptr) ptr[0] = '\0';
1360 TRACE("found %s\n", debugstr_w(server));
1362 len = sizeof(buffer)/sizeof(buffer[0]);
1363 if (GetComputerNameW(buffer, &len)) {
1364 if (lstrcmpW(buffer, server) == 0) {
1365 /* The requested Servername is our computername */
1366 HeapFree(GetProcessHeap(), 0, server);
1373 /******************************************************************
1374 * get_basename_from_name (internal)
1376 * skip over the serverpart from the full name
1379 static LPCWSTR get_basename_from_name(LPCWSTR name)
1381 if (name == NULL) return NULL;
1382 if ((name[0] == '\\') && (name[1] == '\\')) {
1383 /* skip over the servername and search for the following '\' */
1384 name = strchrW(&name[2], '\\');
1385 if ((name) && (name[1])) {
1386 /* found a separator ('\') followed by a name:
1387 skip over the separator and return the rest */
1392 /* no basename present (we found only a servername) */
1399 static void free_printer_entry( opened_printer_t *printer )
1401 /* the queue is shared, so don't free that here */
1402 HeapFree( GetProcessHeap(), 0, printer->printername );
1403 HeapFree( GetProcessHeap(), 0, printer->name );
1404 HeapFree( GetProcessHeap(), 0, printer->devmode );
1405 HeapFree( GetProcessHeap(), 0, printer );
1408 /******************************************************************
1409 * get_opened_printer_entry
1410 * Get the first place empty in the opened printer table
1413 * - pDefault is ignored
1415 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1417 UINT_PTR handle = nb_printer_handles, i;
1418 jobqueue_t *queue = NULL;
1419 opened_printer_t *printer = NULL;
1421 LPCWSTR printername;
1423 if ((backend == NULL) && !load_backend()) return NULL;
1425 servername = get_servername_from_name(name);
1427 FIXME("server %s not supported\n", debugstr_w(servername));
1428 HeapFree(GetProcessHeap(), 0, servername);
1429 SetLastError(ERROR_INVALID_PRINTER_NAME);
1433 printername = get_basename_from_name(name);
1434 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1436 /* an empty printername is invalid */
1437 if (printername && (!printername[0])) {
1438 SetLastError(ERROR_INVALID_PARAMETER);
1442 EnterCriticalSection(&printer_handles_cs);
1444 for (i = 0; i < nb_printer_handles; i++)
1446 if (!printer_handles[i])
1448 if(handle == nb_printer_handles)
1453 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1454 queue = printer_handles[i]->queue;
1458 if (handle >= nb_printer_handles)
1460 opened_printer_t **new_array;
1461 if (printer_handles)
1462 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1463 (nb_printer_handles + 16) * sizeof(*new_array) );
1465 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1466 (nb_printer_handles + 16) * sizeof(*new_array) );
1473 printer_handles = new_array;
1474 nb_printer_handles += 16;
1477 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1483 /* get a printer handle from the backend */
1484 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1489 /* clone the base name. This is NULL for the printserver */
1490 printer->printername = strdupW(printername);
1492 /* clone the full name */
1493 printer->name = strdupW(name);
1494 if (name && (!printer->name)) {
1499 if (pDefault && pDefault->pDevMode)
1500 printer->devmode = dup_devmode( pDefault->pDevMode );
1503 printer->queue = queue;
1506 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1507 if (!printer->queue) {
1511 list_init(&printer->queue->jobs);
1512 printer->queue->ref = 0;
1514 InterlockedIncrement(&printer->queue->ref);
1516 printer_handles[handle] = printer;
1519 LeaveCriticalSection(&printer_handles_cs);
1520 if (!handle && printer) {
1521 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1522 free_printer_entry( printer );
1525 return (HANDLE)handle;
1528 static void old_printer_check( BOOL delete_phase )
1530 PRINTER_INFO_5W* pi;
1531 DWORD needed, type, num, delete, i, size;
1532 const DWORD one = 1;
1536 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1537 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1539 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1540 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1541 for (i = 0; i < num; i++)
1543 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1544 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1547 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1551 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1557 size = sizeof( delete );
1558 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1562 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1563 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1565 DeletePrinter( hprn );
1566 ClosePrinter( hprn );
1568 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1572 HeapFree(GetProcessHeap(), 0, pi);
1575 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1576 'M','U','T','E','X','_','_','\0'};
1577 static HANDLE init_mutex;
1579 void WINSPOOL_LoadSystemPrinters(void)
1581 HKEY hkey, hkeyPrinters;
1582 DWORD needed, num, i;
1583 WCHAR PrinterName[256];
1586 /* FIXME: The init code should be moved to spoolsv.exe */
1587 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1590 ERR( "Failed to create mutex\n" );
1593 if (GetLastError() == ERROR_ALREADY_EXISTS)
1595 WaitForSingleObject( init_mutex, INFINITE );
1596 ReleaseMutex( init_mutex );
1597 TRACE( "Init already done\n" );
1601 /* This ensures that all printer entries have a valid Name value. If causes
1602 problems later if they don't. If one is found to be missed we create one
1603 and set it equal to the name of the key */
1604 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1605 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1606 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1607 for(i = 0; i < num; i++) {
1608 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1609 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1610 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1611 set_reg_szW(hkey, NameW, PrinterName);
1618 RegCloseKey(hkeyPrinters);
1621 old_printer_check( FALSE );
1623 #ifdef SONAME_LIBCUPS
1624 done = CUPS_LoadPrinters();
1627 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1628 PRINTCAP_LoadPrinters();
1630 old_printer_check( TRUE );
1632 ReleaseMutex( init_mutex );
1636 /******************************************************************
1639 * Get the pointer to the specified job.
1640 * Should hold the printer_handles_cs before calling.
1642 static job_t *get_job(HANDLE hprn, DWORD JobId)
1644 opened_printer_t *printer = get_opened_printer(hprn);
1647 if(!printer) return NULL;
1648 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1650 if(job->job_id == JobId)
1656 /***********************************************************
1659 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1662 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1665 Formname = (dmA->dmSize > off_formname);
1666 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1667 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1668 dmW->dmDeviceName, CCHDEVICENAME);
1670 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1671 dmA->dmSize - CCHDEVICENAME);
1673 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1674 off_formname - CCHDEVICENAME);
1675 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1676 dmW->dmFormName, CCHFORMNAME);
1677 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1678 (off_formname + CCHFORMNAME));
1681 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1682 dmA->dmDriverExtra);
1686 /******************************************************************
1687 * convert_printerinfo_W_to_A [internal]
1690 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1691 DWORD level, DWORD outlen, DWORD numentries)
1697 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1699 len = pi_sizeof[level] * numentries;
1700 ptr = (LPSTR) out + len;
1703 /* copy the numbers of all PRINTER_INFO_* first */
1704 memcpy(out, pPrintersW, len);
1706 while (id < numentries) {
1710 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1711 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1713 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1714 if (piW->pDescription) {
1715 piA->pDescription = ptr;
1716 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1717 ptr, outlen, NULL, NULL);
1723 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1724 ptr, outlen, NULL, NULL);
1728 if (piW->pComment) {
1729 piA->pComment = ptr;
1730 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1731 ptr, outlen, NULL, NULL);
1740 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1741 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1744 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1745 if (piW->pServerName) {
1746 piA->pServerName = ptr;
1747 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1748 ptr, outlen, NULL, NULL);
1752 if (piW->pPrinterName) {
1753 piA->pPrinterName = ptr;
1754 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1755 ptr, outlen, NULL, NULL);
1759 if (piW->pShareName) {
1760 piA->pShareName = ptr;
1761 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1762 ptr, outlen, NULL, NULL);
1766 if (piW->pPortName) {
1767 piA->pPortName = ptr;
1768 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1769 ptr, outlen, NULL, NULL);
1773 if (piW->pDriverName) {
1774 piA->pDriverName = ptr;
1775 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1776 ptr, outlen, NULL, NULL);
1780 if (piW->pComment) {
1781 piA->pComment = ptr;
1782 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1783 ptr, outlen, NULL, NULL);
1787 if (piW->pLocation) {
1788 piA->pLocation = ptr;
1789 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1790 ptr, outlen, NULL, NULL);
1795 dmA = DEVMODEdupWtoA(piW->pDevMode);
1797 /* align DEVMODEA to a DWORD boundary */
1798 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1802 piA->pDevMode = (LPDEVMODEA) ptr;
1803 len = dmA->dmSize + dmA->dmDriverExtra;
1804 memcpy(ptr, dmA, len);
1805 HeapFree(GetProcessHeap(), 0, dmA);
1811 if (piW->pSepFile) {
1812 piA->pSepFile = ptr;
1813 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1814 ptr, outlen, NULL, NULL);
1818 if (piW->pPrintProcessor) {
1819 piA->pPrintProcessor = ptr;
1820 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1821 ptr, outlen, NULL, NULL);
1825 if (piW->pDatatype) {
1826 piA->pDatatype = ptr;
1827 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1828 ptr, outlen, NULL, NULL);
1832 if (piW->pParameters) {
1833 piA->pParameters = ptr;
1834 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1835 ptr, outlen, NULL, NULL);
1839 if (piW->pSecurityDescriptor) {
1840 piA->pSecurityDescriptor = NULL;
1841 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1848 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1849 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1851 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1853 if (piW->pPrinterName) {
1854 piA->pPrinterName = ptr;
1855 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1856 ptr, outlen, NULL, NULL);
1860 if (piW->pServerName) {
1861 piA->pServerName = ptr;
1862 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1863 ptr, outlen, NULL, NULL);
1872 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1873 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1875 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1877 if (piW->pPrinterName) {
1878 piA->pPrinterName = ptr;
1879 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1880 ptr, outlen, NULL, NULL);
1884 if (piW->pPortName) {
1885 piA->pPortName = ptr;
1886 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1887 ptr, outlen, NULL, NULL);
1894 case 6: /* 6A and 6W are the same structure */
1899 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1900 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1902 TRACE("(%u) #%u\n", level, id);
1903 if (piW->pszObjectGUID) {
1904 piA->pszObjectGUID = ptr;
1905 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1906 ptr, outlen, NULL, NULL);
1916 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1917 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1920 TRACE("(%u) #%u\n", level, id);
1921 dmA = DEVMODEdupWtoA(piW->pDevMode);
1923 /* align DEVMODEA to a DWORD boundary */
1924 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1928 piA->pDevMode = (LPDEVMODEA) ptr;
1929 len = dmA->dmSize + dmA->dmDriverExtra;
1930 memcpy(ptr, dmA, len);
1931 HeapFree(GetProcessHeap(), 0, dmA);
1941 FIXME("for level %u\n", level);
1943 pPrintersW += pi_sizeof[level];
1944 out += pi_sizeof[level];
1949 /******************************************************************
1950 * convert_driverinfo_W_to_A [internal]
1953 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1954 DWORD level, DWORD outlen, DWORD numentries)
1960 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1962 len = di_sizeof[level] * numentries;
1963 ptr = (LPSTR) out + len;
1966 /* copy the numbers of all PRINTER_INFO_* first */
1967 memcpy(out, pDriversW, len);
1969 #define COPY_STRING(fld) \
1972 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1973 ptr += len; outlen -= len;\
1975 #define COPY_MULTIZ_STRING(fld) \
1976 { LPWSTR p = diW->fld; if (p){ \
1979 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1980 ptr += len; outlen -= len; p += len;\
1982 while(len > 1 && outlen > 0); \
1985 while (id < numentries)
1991 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1992 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1994 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2001 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2002 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2004 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2007 COPY_STRING(pEnvironment);
2008 COPY_STRING(pDriverPath);
2009 COPY_STRING(pDataFile);
2010 COPY_STRING(pConfigFile);
2015 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2016 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2018 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2021 COPY_STRING(pEnvironment);
2022 COPY_STRING(pDriverPath);
2023 COPY_STRING(pDataFile);
2024 COPY_STRING(pConfigFile);
2025 COPY_STRING(pHelpFile);
2026 COPY_MULTIZ_STRING(pDependentFiles);
2027 COPY_STRING(pMonitorName);
2028 COPY_STRING(pDefaultDataType);
2033 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2034 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2036 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2039 COPY_STRING(pEnvironment);
2040 COPY_STRING(pDriverPath);
2041 COPY_STRING(pDataFile);
2042 COPY_STRING(pConfigFile);
2043 COPY_STRING(pHelpFile);
2044 COPY_MULTIZ_STRING(pDependentFiles);
2045 COPY_STRING(pMonitorName);
2046 COPY_STRING(pDefaultDataType);
2047 COPY_MULTIZ_STRING(pszzPreviousNames);
2052 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2053 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2055 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2058 COPY_STRING(pEnvironment);
2059 COPY_STRING(pDriverPath);
2060 COPY_STRING(pDataFile);
2061 COPY_STRING(pConfigFile);
2066 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2067 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2069 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2072 COPY_STRING(pEnvironment);
2073 COPY_STRING(pDriverPath);
2074 COPY_STRING(pDataFile);
2075 COPY_STRING(pConfigFile);
2076 COPY_STRING(pHelpFile);
2077 COPY_MULTIZ_STRING(pDependentFiles);
2078 COPY_STRING(pMonitorName);
2079 COPY_STRING(pDefaultDataType);
2080 COPY_MULTIZ_STRING(pszzPreviousNames);
2081 COPY_STRING(pszMfgName);
2082 COPY_STRING(pszOEMUrl);
2083 COPY_STRING(pszHardwareID);
2084 COPY_STRING(pszProvider);
2089 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2090 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2092 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2095 COPY_STRING(pEnvironment);
2096 COPY_STRING(pDriverPath);
2097 COPY_STRING(pDataFile);
2098 COPY_STRING(pConfigFile);
2099 COPY_STRING(pHelpFile);
2100 COPY_MULTIZ_STRING(pDependentFiles);
2101 COPY_STRING(pMonitorName);
2102 COPY_STRING(pDefaultDataType);
2103 COPY_MULTIZ_STRING(pszzPreviousNames);
2104 COPY_STRING(pszMfgName);
2105 COPY_STRING(pszOEMUrl);
2106 COPY_STRING(pszHardwareID);
2107 COPY_STRING(pszProvider);
2108 COPY_STRING(pszPrintProcessor);
2109 COPY_STRING(pszVendorSetup);
2110 COPY_MULTIZ_STRING(pszzColorProfiles);
2111 COPY_STRING(pszInfPath);
2112 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2118 FIXME("for level %u\n", level);
2121 pDriversW += di_sizeof[level];
2122 out += di_sizeof[level];
2127 #undef COPY_MULTIZ_STRING
2131 /***********************************************************
2134 static void *printer_info_AtoW( const void *data, DWORD level )
2137 UNICODE_STRING usBuffer;
2139 if (!data) return NULL;
2141 if (level < 1 || level > 9) return NULL;
2143 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2144 if (!ret) return NULL;
2146 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2152 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2153 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2155 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2156 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2157 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2158 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2159 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2160 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2161 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2162 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2163 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2164 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2165 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2166 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2173 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2174 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2176 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2181 FIXME( "Unhandled level %d\n", level );
2182 HeapFree( GetProcessHeap(), 0, ret );
2189 /***********************************************************
2192 static void free_printer_info( void *data, DWORD level )
2200 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2202 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2203 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2204 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2205 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2206 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2207 HeapFree( GetProcessHeap(), 0, piW->pComment );
2208 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2209 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2210 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2211 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2212 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2213 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2220 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2222 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2227 FIXME( "Unhandled level %d\n", level );
2230 HeapFree( GetProcessHeap(), 0, data );
2234 /******************************************************************
2235 * DeviceCapabilities [WINSPOOL.@]
2236 * DeviceCapabilitiesA [WINSPOOL.@]
2239 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2240 LPSTR pOutput, LPDEVMODEA lpdm)
2244 if (!GDI_CallDeviceCapabilities16)
2246 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2248 if (!GDI_CallDeviceCapabilities16) return -1;
2250 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2252 /* If DC_PAPERSIZE map POINT16s to POINTs */
2253 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2254 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2255 POINT *pt = (POINT *)pOutput;
2257 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2258 for(i = 0; i < ret; i++, pt++)
2263 HeapFree( GetProcessHeap(), 0, tmp );
2269 /*****************************************************************************
2270 * DeviceCapabilitiesW [WINSPOOL.@]
2272 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2275 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2276 WORD fwCapability, LPWSTR pOutput,
2277 const DEVMODEW *pDevMode)
2279 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2280 LPSTR pDeviceA = strdupWtoA(pDevice);
2281 LPSTR pPortA = strdupWtoA(pPort);
2284 if(pOutput && (fwCapability == DC_BINNAMES ||
2285 fwCapability == DC_FILEDEPENDENCIES ||
2286 fwCapability == DC_PAPERNAMES)) {
2287 /* These need A -> W translation */
2290 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2294 switch(fwCapability) {
2299 case DC_FILEDEPENDENCIES:
2303 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2304 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2306 for(i = 0; i < ret; i++)
2307 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2308 pOutput + (i * size), size);
2309 HeapFree(GetProcessHeap(), 0, pOutputA);
2311 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2312 (LPSTR)pOutput, dmA);
2314 HeapFree(GetProcessHeap(),0,pPortA);
2315 HeapFree(GetProcessHeap(),0,pDeviceA);
2316 HeapFree(GetProcessHeap(),0,dmA);
2320 /******************************************************************
2321 * DocumentPropertiesA [WINSPOOL.@]
2323 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2325 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2326 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2327 LPDEVMODEA pDevModeInput,DWORD fMode )
2329 LPSTR lpName = pDeviceName;
2330 static CHAR port[] = "LPT1:";
2333 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2334 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2338 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2340 ERR("no name from hPrinter?\n");
2341 SetLastError(ERROR_INVALID_HANDLE);
2344 lpName = strdupWtoA(lpNameW);
2347 if (!GDI_CallExtDeviceMode16)
2349 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2351 if (!GDI_CallExtDeviceMode16) {
2352 ERR("No CallExtDeviceMode16?\n");
2356 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2357 pDevModeInput, NULL, fMode);
2360 HeapFree(GetProcessHeap(),0,lpName);
2365 /*****************************************************************************
2366 * DocumentPropertiesW (WINSPOOL.@)
2368 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2370 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2372 LPDEVMODEW pDevModeOutput,
2373 LPDEVMODEW pDevModeInput, DWORD fMode)
2376 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2377 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2378 LPDEVMODEA pDevModeOutputA = NULL;
2381 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2382 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2384 if(pDevModeOutput) {
2385 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2386 if(ret < 0) return ret;
2387 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2389 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2390 pDevModeInputA, fMode);
2391 if(pDevModeOutput) {
2392 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2393 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2395 if(fMode == 0 && ret > 0)
2396 ret += (CCHDEVICENAME + CCHFORMNAME);
2397 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2398 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2402 /*****************************************************************************
2403 * IsValidDevmodeA [WINSPOOL.@]
2405 * Validate a DEVMODE structure and fix errors if possible.
2408 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2410 FIXME("(%p,%ld): stub\n", pDevMode, size);
2418 /*****************************************************************************
2419 * IsValidDevmodeW [WINSPOOL.@]
2421 * Validate a DEVMODE structure and fix errors if possible.
2424 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2426 FIXME("(%p,%ld): stub\n", pDevMode, size);
2434 /******************************************************************
2435 * OpenPrinterA [WINSPOOL.@]
2440 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2441 LPPRINTER_DEFAULTSA pDefault)
2443 UNICODE_STRING lpPrinterNameW;
2444 UNICODE_STRING usBuffer;
2445 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2446 PWSTR pwstrPrinterNameW;
2449 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2452 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2453 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2454 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2455 pDefaultW = &DefaultW;
2457 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2459 RtlFreeUnicodeString(&usBuffer);
2460 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2462 RtlFreeUnicodeString(&lpPrinterNameW);
2466 /******************************************************************
2467 * OpenPrinterW [WINSPOOL.@]
2469 * Open a Printer / Printserver or a Printer-Object
2472 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2473 * phPrinter [O] The resulting Handle is stored here
2474 * pDefault [I] PTR to Default Printer Settings or NULL
2481 * lpPrinterName is one of:
2482 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2483 *| Printer: "PrinterName"
2484 *| Printer-Object: "PrinterName,Job xxx"
2485 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2486 *| XcvPort: "Servername,XcvPort PortName"
2489 *| Printer-Object not supported
2490 *| pDefaults is ignored
2493 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2496 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2499 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2500 SetLastError(ERROR_INVALID_PARAMETER);
2504 /* Get the unique handle of the printer or Printserver */
2505 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2510 DWORD deleting = 0, size = sizeof( deleting ), type;
2512 WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key );
2513 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2514 WaitForSingleObject( init_mutex, INFINITE );
2515 status = get_dword_from_reg( key, StatusW );
2516 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2517 ReleaseMutex( init_mutex );
2518 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2519 update_driver( *phPrinter );
2523 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2524 return (*phPrinter != 0);
2527 /******************************************************************
2528 * AddMonitorA [WINSPOOL.@]
2533 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2535 LPWSTR nameW = NULL;
2538 LPMONITOR_INFO_2A mi2a;
2539 MONITOR_INFO_2W mi2w;
2541 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2542 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2543 debugstr_a(mi2a ? mi2a->pName : NULL),
2544 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2545 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2548 SetLastError(ERROR_INVALID_LEVEL);
2552 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2558 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2559 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2560 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2563 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2565 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2566 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2567 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2569 if (mi2a->pEnvironment) {
2570 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2571 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2572 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2574 if (mi2a->pDLLName) {
2575 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2576 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2577 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2580 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2582 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2583 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2584 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2586 HeapFree(GetProcessHeap(), 0, nameW);
2590 /******************************************************************************
2591 * AddMonitorW [WINSPOOL.@]
2593 * Install a Printmonitor
2596 * pName [I] Servername or NULL (local Computer)
2597 * Level [I] Structure-Level (Must be 2)
2598 * pMonitors [I] PTR to MONITOR_INFO_2
2605 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2608 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2610 LPMONITOR_INFO_2W mi2w;
2612 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2613 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2614 debugstr_w(mi2w ? mi2w->pName : NULL),
2615 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2616 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2618 if ((backend == NULL) && !load_backend()) return FALSE;
2621 SetLastError(ERROR_INVALID_LEVEL);
2625 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2630 return backend->fpAddMonitor(pName, Level, pMonitors);
2633 /******************************************************************
2634 * DeletePrinterDriverA [WINSPOOL.@]
2637 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2639 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2642 /******************************************************************
2643 * DeletePrinterDriverW [WINSPOOL.@]
2646 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2648 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2651 /******************************************************************
2652 * DeleteMonitorA [WINSPOOL.@]
2654 * See DeleteMonitorW.
2657 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2659 LPWSTR nameW = NULL;
2660 LPWSTR EnvironmentW = NULL;
2661 LPWSTR MonitorNameW = NULL;
2666 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2667 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2668 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2672 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2673 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2674 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2677 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2678 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2679 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2682 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2684 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2685 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2686 HeapFree(GetProcessHeap(), 0, nameW);
2690 /******************************************************************
2691 * DeleteMonitorW [WINSPOOL.@]
2693 * Delete a specific Printmonitor from a Printing-Environment
2696 * pName [I] Servername or NULL (local Computer)
2697 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2698 * pMonitorName [I] Name of the Monitor, that should be deleted
2705 * pEnvironment is ignored in Windows for the local Computer.
2708 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2711 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2712 debugstr_w(pMonitorName));
2714 if ((backend == NULL) && !load_backend()) return FALSE;
2716 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2720 /******************************************************************
2721 * DeletePortA [WINSPOOL.@]
2726 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2728 LPWSTR nameW = NULL;
2729 LPWSTR portW = NULL;
2733 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2735 /* convert servername to unicode */
2737 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2738 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2739 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2742 /* convert portname to unicode */
2744 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2745 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2746 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2749 res = DeletePortW(nameW, hWnd, portW);
2750 HeapFree(GetProcessHeap(), 0, nameW);
2751 HeapFree(GetProcessHeap(), 0, portW);
2755 /******************************************************************
2756 * DeletePortW [WINSPOOL.@]
2758 * Delete a specific Port
2761 * pName [I] Servername or NULL (local Computer)
2762 * hWnd [I] Handle to parent Window for the Dialog-Box
2763 * pPortName [I] Name of the Port, that should be deleted
2770 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2772 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2774 if ((backend == NULL) && !load_backend()) return FALSE;
2777 SetLastError(RPC_X_NULL_REF_POINTER);
2781 return backend->fpDeletePort(pName, hWnd, pPortName);
2784 /******************************************************************************
2785 * WritePrinter [WINSPOOL.@]
2787 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2789 opened_printer_t *printer;
2792 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2794 EnterCriticalSection(&printer_handles_cs);
2795 printer = get_opened_printer(hPrinter);
2798 SetLastError(ERROR_INVALID_HANDLE);
2804 SetLastError(ERROR_SPL_NO_STARTDOC);
2808 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2810 LeaveCriticalSection(&printer_handles_cs);
2814 /*****************************************************************************
2815 * AddFormA [WINSPOOL.@]
2817 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2819 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2823 /*****************************************************************************
2824 * AddFormW [WINSPOOL.@]
2826 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2828 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2832 /*****************************************************************************
2833 * AddJobA [WINSPOOL.@]
2835 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2838 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2842 SetLastError(ERROR_INVALID_LEVEL);
2846 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2849 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2850 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2851 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2852 if(*pcbNeeded > cbBuf) {
2853 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2856 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2857 addjobA->JobId = addjobW->JobId;
2858 addjobA->Path = (char *)(addjobA + 1);
2859 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2865 /*****************************************************************************
2866 * AddJobW [WINSPOOL.@]
2868 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2870 opened_printer_t *printer;
2873 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2874 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2875 WCHAR path[MAX_PATH], filename[MAX_PATH];
2877 ADDJOB_INFO_1W *addjob;
2879 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2881 EnterCriticalSection(&printer_handles_cs);
2883 printer = get_opened_printer(hPrinter);
2886 SetLastError(ERROR_INVALID_HANDLE);
2891 SetLastError(ERROR_INVALID_LEVEL);
2895 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2899 job->job_id = InterlockedIncrement(&next_job_id);
2901 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2902 if(path[len - 1] != '\\')
2904 memcpy(path + len, spool_path, sizeof(spool_path));
2905 sprintfW(filename, fmtW, path, job->job_id);
2907 len = strlenW(filename);
2908 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2909 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2910 job->portname = NULL;
2911 job->document_title = strdupW(default_doc_title);
2912 job->printer_name = strdupW(printer->name);
2913 job->devmode = dup_devmode( printer->devmode );
2914 list_add_tail(&printer->queue->jobs, &job->entry);
2916 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2917 if(*pcbNeeded <= cbBuf) {
2918 addjob = (ADDJOB_INFO_1W*)pData;
2919 addjob->JobId = job->job_id;
2920 addjob->Path = (WCHAR *)(addjob + 1);
2921 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2924 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2927 LeaveCriticalSection(&printer_handles_cs);
2931 /*****************************************************************************
2932 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2934 * Return the PATH for the Print-Processors
2936 * See GetPrintProcessorDirectoryW.
2940 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2941 DWORD level, LPBYTE Info,
2942 DWORD cbBuf, LPDWORD pcbNeeded)
2944 LPWSTR serverW = NULL;
2949 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2950 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2954 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2955 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2956 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2960 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2961 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2962 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2965 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2966 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2968 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2971 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2972 cbBuf, NULL, NULL) > 0;
2975 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2976 HeapFree(GetProcessHeap(), 0, envW);
2977 HeapFree(GetProcessHeap(), 0, serverW);
2981 /*****************************************************************************
2982 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2984 * Return the PATH for the Print-Processors
2987 * server [I] Servername (NT only) or NULL (local Computer)
2988 * env [I] Printing-Environment (see below) or NULL (Default)
2989 * level [I] Structure-Level (must be 1)
2990 * Info [O] PTR to Buffer that receives the Result
2991 * cbBuf [I] Size of Buffer at "Info"
2992 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2993 * required for the Buffer at "Info"
2996 * Success: TRUE and in pcbNeeded the Bytes used in Info
2997 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2998 * if cbBuf is too small
3000 * Native Values returned in Info on Success:
3001 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3002 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3003 *| win9x(Windows 4.0): "%winsysdir%"
3005 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3008 * Only NULL or "" is supported for server
3011 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3012 DWORD level, LPBYTE Info,
3013 DWORD cbBuf, LPDWORD pcbNeeded)
3016 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3017 Info, cbBuf, pcbNeeded);
3019 if ((backend == NULL) && !load_backend()) return FALSE;
3022 /* (Level != 1) is ignored in win9x */
3023 SetLastError(ERROR_INVALID_LEVEL);
3027 if (pcbNeeded == NULL) {
3028 /* (pcbNeeded == NULL) is ignored in win9x */
3029 SetLastError(RPC_X_NULL_REF_POINTER);
3033 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3036 /*****************************************************************************
3037 * WINSPOOL_OpenDriverReg [internal]
3039 * opens the registry for the printer drivers depending on the given input
3040 * variable pEnvironment
3043 * the opened hkey on success
3046 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3050 const printenv_t * env;
3052 TRACE("(%s)\n", debugstr_w(pEnvironment));
3054 env = validate_envW(pEnvironment);
3055 if (!env) return NULL;
3057 buffer = HeapAlloc( GetProcessHeap(), 0,
3058 (strlenW(DriversW) + strlenW(env->envname) +
3059 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3061 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3062 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3063 HeapFree(GetProcessHeap(), 0, buffer);
3068 /*****************************************************************************
3069 * set_devices_and_printerports [internal]
3071 * set the [Devices] and [PrinterPorts] entries for a printer.
3074 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3076 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3080 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3082 /* FIXME: the driver must change to "winspool" */
3083 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3085 lstrcpyW(devline, driver_nt);
3086 lstrcatW(devline, commaW);
3087 lstrcatW(devline, pi->pPortName);
3089 TRACE("using %s\n", debugstr_w(devline));
3090 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
3091 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3092 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3093 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3097 lstrcatW(devline, timeout_15_45);
3098 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
3099 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3100 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3101 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3104 HeapFree(GetProcessHeap(), 0, devline);
3108 /*****************************************************************************
3109 * AddPrinterW [WINSPOOL.@]
3111 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3113 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3116 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3119 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3122 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3123 SetLastError(ERROR_INVALID_PARAMETER);
3127 ERR("Level = %d, unsupported!\n", Level);
3128 SetLastError(ERROR_INVALID_LEVEL);
3132 SetLastError(ERROR_INVALID_PARAMETER);
3135 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3137 ERR("Can't create Printers key\n");
3140 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3141 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3142 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3143 RegCloseKey(hkeyPrinter);
3144 RegCloseKey(hkeyPrinters);
3147 RegCloseKey(hkeyPrinter);
3149 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3151 ERR("Can't create Drivers key\n");
3152 RegCloseKey(hkeyPrinters);
3155 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3157 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3158 RegCloseKey(hkeyPrinters);
3159 RegCloseKey(hkeyDrivers);
3160 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3163 RegCloseKey(hkeyDriver);
3164 RegCloseKey(hkeyDrivers);
3166 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3167 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3168 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3169 RegCloseKey(hkeyPrinters);
3173 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3175 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3176 SetLastError(ERROR_INVALID_PRINTER_NAME);
3177 RegCloseKey(hkeyPrinters);
3181 set_devices_and_printerports(pi);
3183 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3184 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3185 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3186 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3187 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3188 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3189 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3190 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3191 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3192 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3193 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3194 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3195 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3196 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3197 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3198 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3199 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3200 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3202 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3206 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3207 size = sizeof(DEVMODEW);
3213 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3215 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3217 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3218 HeapFree( GetProcessHeap(), 0, dm );
3223 /* set devmode to printer name */
3224 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3228 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3229 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3231 RegCloseKey(hkeyPrinter);
3232 RegCloseKey(hkeyPrinters);
3233 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3234 ERR("OpenPrinter failing\n");
3240 /*****************************************************************************
3241 * AddPrinterA [WINSPOOL.@]
3243 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3245 UNICODE_STRING pNameW;
3247 PRINTER_INFO_2W *piW;
3248 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3251 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3253 ERR("Level = %d, unsupported!\n", Level);
3254 SetLastError(ERROR_INVALID_LEVEL);
3257 pwstrNameW = asciitounicode(&pNameW,pName);
3258 piW = printer_info_AtoW( piA, Level );
3260 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3262 free_printer_info( piW, Level );
3263 RtlFreeUnicodeString(&pNameW);
3268 /*****************************************************************************
3269 * ClosePrinter [WINSPOOL.@]
3271 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3273 UINT_PTR i = (UINT_PTR)hPrinter;
3274 opened_printer_t *printer = NULL;
3277 TRACE("(%p)\n", hPrinter);
3279 EnterCriticalSection(&printer_handles_cs);
3281 if ((i > 0) && (i <= nb_printer_handles))
3282 printer = printer_handles[i - 1];
3287 struct list *cursor, *cursor2;
3289 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3291 if (printer->backend_printer) {
3292 backend->fpClosePrinter(printer->backend_printer);
3296 EndDocPrinter(hPrinter);
3298 if(InterlockedDecrement(&printer->queue->ref) == 0)
3300 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3302 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3303 ScheduleJob(hPrinter, job->job_id);
3305 HeapFree(GetProcessHeap(), 0, printer->queue);
3308 free_printer_entry( printer );
3309 printer_handles[i - 1] = NULL;
3312 LeaveCriticalSection(&printer_handles_cs);
3316 /*****************************************************************************
3317 * DeleteFormA [WINSPOOL.@]
3319 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3321 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3325 /*****************************************************************************
3326 * DeleteFormW [WINSPOOL.@]
3328 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3330 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3334 /*****************************************************************************
3335 * DeletePrinter [WINSPOOL.@]
3337 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3339 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3340 HKEY hkeyPrinters, hkey;
3341 WCHAR def[MAX_PATH];
3342 DWORD size = sizeof( def ) / sizeof( def[0] );
3345 SetLastError(ERROR_INVALID_HANDLE);
3348 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3349 RegDeleteTreeW(hkeyPrinters, lpNameW);
3350 RegCloseKey(hkeyPrinters);
3352 WriteProfileStringW(devicesW, lpNameW, NULL);
3353 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3355 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3356 RegDeleteValueW(hkey, lpNameW);
3360 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3361 RegDeleteValueW(hkey, lpNameW);
3365 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3367 WriteProfileStringW( windowsW, deviceW, NULL );
3368 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3370 RegDeleteValueW( hkey, deviceW );
3371 RegCloseKey( hkey );
3373 SetDefaultPrinterW( NULL );
3379 /*****************************************************************************
3380 * SetPrinterA [WINSPOOL.@]
3382 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3389 dataW = printer_info_AtoW( data, level );
3390 if (!dataW) return FALSE;
3393 ret = SetPrinterW( printer, level, dataW, command );
3395 if (dataW != data) free_printer_info( dataW, level );
3400 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3402 set_reg_szW( key, NameW, pi->pPrinterName );
3403 set_reg_szW( key, Share_NameW, pi->pShareName );
3404 set_reg_szW( key, PortW, pi->pPortName );
3405 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3406 set_reg_szW( key, DescriptionW, pi->pComment );
3407 set_reg_szW( key, LocationW, pi->pLocation );
3410 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3412 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3413 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3414 set_reg_szW( key, DatatypeW, pi->pDatatype );
3415 set_reg_szW( key, ParametersW, pi->pParameters );
3417 set_reg_DWORD( key, AttributesW, pi->Attributes );
3418 set_reg_DWORD( key, PriorityW, pi->Priority );
3419 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3420 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3421 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3424 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3426 if (!pi->pDevMode) return FALSE;
3428 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3432 /******************************************************************************
3433 * SetPrinterW [WINSPOOL.@]
3435 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3440 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3442 if (command != 0) FIXME( "Ignoring command %d\n", command );
3444 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3451 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3452 set_printer_2( key, pi2 );
3459 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3460 ret = set_printer_9( key, pi );
3465 FIXME( "Unimplemented level %d\n", level );
3466 SetLastError( ERROR_INVALID_LEVEL );
3473 /*****************************************************************************
3474 * SetJobA [WINSPOOL.@]
3476 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3477 LPBYTE pJob, DWORD Command)
3481 UNICODE_STRING usBuffer;
3483 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3485 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3486 are all ignored by SetJob, so we don't bother copying them */
3494 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3495 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3497 JobW = (LPBYTE)info1W;
3498 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3499 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3500 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3501 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3502 info1W->Status = info1A->Status;
3503 info1W->Priority = info1A->Priority;
3504 info1W->Position = info1A->Position;
3505 info1W->PagesPrinted = info1A->PagesPrinted;
3510 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3511 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3513 JobW = (LPBYTE)info2W;
3514 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3515 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3516 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3517 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3518 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3519 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3520 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3521 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3522 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3523 info2W->Status = info2A->Status;
3524 info2W->Priority = info2A->Priority;
3525 info2W->Position = info2A->Position;
3526 info2W->StartTime = info2A->StartTime;
3527 info2W->UntilTime = info2A->UntilTime;
3528 info2W->PagesPrinted = info2A->PagesPrinted;
3532 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3533 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3536 SetLastError(ERROR_INVALID_LEVEL);
3540 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3546 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3547 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3548 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3549 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3550 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3555 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3556 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3557 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3558 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3559 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3560 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3561 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3562 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3563 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3567 HeapFree(GetProcessHeap(), 0, JobW);
3572 /*****************************************************************************
3573 * SetJobW [WINSPOOL.@]
3575 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3576 LPBYTE pJob, DWORD Command)
3581 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3582 FIXME("Ignoring everything other than document title\n");
3584 EnterCriticalSection(&printer_handles_cs);
3585 job = get_job(hPrinter, JobId);
3595 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3596 HeapFree(GetProcessHeap(), 0, job->document_title);
3597 job->document_title = strdupW(info1->pDocument);
3602 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3603 HeapFree(GetProcessHeap(), 0, job->document_title);
3604 job->document_title = strdupW(info2->pDocument);
3605 HeapFree(GetProcessHeap(), 0, job->devmode);
3606 job->devmode = dup_devmode( info2->pDevMode );
3612 SetLastError(ERROR_INVALID_LEVEL);
3617 LeaveCriticalSection(&printer_handles_cs);
3621 /*****************************************************************************
3622 * EndDocPrinter [WINSPOOL.@]
3624 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3626 opened_printer_t *printer;
3628 TRACE("(%p)\n", hPrinter);
3630 EnterCriticalSection(&printer_handles_cs);
3632 printer = get_opened_printer(hPrinter);
3635 SetLastError(ERROR_INVALID_HANDLE);
3641 SetLastError(ERROR_SPL_NO_STARTDOC);
3645 CloseHandle(printer->doc->hf);
3646 ScheduleJob(hPrinter, printer->doc->job_id);
3647 HeapFree(GetProcessHeap(), 0, printer->doc);
3648 printer->doc = NULL;
3651 LeaveCriticalSection(&printer_handles_cs);
3655 /*****************************************************************************
3656 * EndPagePrinter [WINSPOOL.@]
3658 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3660 FIXME("(%p): stub\n", hPrinter);
3664 /*****************************************************************************
3665 * StartDocPrinterA [WINSPOOL.@]
3667 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3669 UNICODE_STRING usBuffer;
3671 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3674 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3675 or one (DOC_INFO_3) extra DWORDs */
3679 doc2W.JobId = doc2->JobId;
3682 doc2W.dwMode = doc2->dwMode;
3685 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3686 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3687 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3691 SetLastError(ERROR_INVALID_LEVEL);
3695 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3697 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3698 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3699 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3704 /*****************************************************************************
3705 * StartDocPrinterW [WINSPOOL.@]
3707 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3709 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3710 opened_printer_t *printer;
3711 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3712 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3713 JOB_INFO_1W job_info;
3714 DWORD needed, ret = 0;
3719 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3720 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3721 debugstr_w(doc->pDatatype));
3723 if(Level < 1 || Level > 3)
3725 SetLastError(ERROR_INVALID_LEVEL);
3729 EnterCriticalSection(&printer_handles_cs);
3730 printer = get_opened_printer(hPrinter);
3733 SetLastError(ERROR_INVALID_HANDLE);
3739 SetLastError(ERROR_INVALID_PRINTER_STATE);
3743 /* Even if we're printing to a file we still add a print job, we'll
3744 just ignore the spool file name */
3746 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3748 ERR("AddJob failed gle %u\n", GetLastError());
3752 /* use pOutputFile only, when it is a real filename */
3753 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3754 filename = doc->pOutputFile;
3756 filename = addjob->Path;
3758 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3759 if(hf == INVALID_HANDLE_VALUE)
3762 memset(&job_info, 0, sizeof(job_info));
3763 job_info.pDocument = doc->pDocName;
3764 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3766 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3767 printer->doc->hf = hf;
3768 ret = printer->doc->job_id = addjob->JobId;
3769 job = get_job(hPrinter, ret);
3770 job->portname = strdupW(doc->pOutputFile);
3773 LeaveCriticalSection(&printer_handles_cs);
3778 /*****************************************************************************
3779 * StartPagePrinter [WINSPOOL.@]
3781 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3783 FIXME("(%p): stub\n", hPrinter);
3787 /*****************************************************************************
3788 * GetFormA [WINSPOOL.@]
3790 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3791 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3793 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3794 Level,pForm,cbBuf,pcbNeeded);
3798 /*****************************************************************************
3799 * GetFormW [WINSPOOL.@]
3801 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3802 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3804 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3805 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3809 /*****************************************************************************
3810 * SetFormA [WINSPOOL.@]
3812 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3815 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3819 /*****************************************************************************
3820 * SetFormW [WINSPOOL.@]
3822 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3825 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3829 /*****************************************************************************
3830 * ReadPrinter [WINSPOOL.@]
3832 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3833 LPDWORD pNoBytesRead)
3835 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3839 /*****************************************************************************
3840 * ResetPrinterA [WINSPOOL.@]
3842 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3844 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3848 /*****************************************************************************
3849 * ResetPrinterW [WINSPOOL.@]
3851 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3853 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3857 /*****************************************************************************
3858 * get_filename_from_reg [internal]
3860 * Get ValueName from hkey storing result in out
3861 * when the Value in the registry has only a filename, use driverdir as prefix
3862 * outlen is space left in out
3863 * String is stored either as unicode or ascii
3867 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3868 LPBYTE out, DWORD outlen, LPDWORD needed)
3870 WCHAR filename[MAX_PATH];
3874 LPWSTR buffer = filename;
3878 size = sizeof(filename);
3880 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3881 if (ret == ERROR_MORE_DATA) {
3882 TRACE("need dynamic buffer: %u\n", size);
3883 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3885 /* No Memory is bad */
3889 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3892 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3893 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3899 /* do we have a full path ? */
3900 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3901 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3904 /* we must build the full Path */
3906 if ((out) && (outlen > dirlen)) {
3907 lstrcpyW((LPWSTR)out, driverdir);
3915 /* write the filename */
3916 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3917 if ((out) && (outlen >= size)) {
3918 lstrcpyW((LPWSTR)out, ptr);
3925 ptr += lstrlenW(ptr)+1;
3926 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3929 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3931 /* write the multisz-termination */
3932 if (type == REG_MULTI_SZ) {
3933 size = sizeof(WCHAR);
3936 if (out && (outlen >= size)) {
3937 memset (out, 0, size);
3943 /*****************************************************************************
3944 * WINSPOOL_GetStringFromReg
3946 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3947 * String is stored as unicode.
3949 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3950 DWORD buflen, DWORD *needed)
3952 DWORD sz = buflen, type;
3955 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3956 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3957 WARN("Got ret = %d\n", ret);
3961 /* add space for terminating '\0' */
3962 sz += sizeof(WCHAR);
3966 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3971 /*****************************************************************************
3972 * WINSPOOL_GetDefaultDevMode
3974 * Get a default DevMode values for wineps.
3978 static void WINSPOOL_GetDefaultDevMode(
3980 DWORD buflen, DWORD *needed)
3983 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3985 /* fill default DEVMODE - should be read from ppd... */
3986 ZeroMemory( &dm, sizeof(dm) );
3987 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3988 dm.dmSpecVersion = DM_SPECVERSION;
3989 dm.dmDriverVersion = 1;
3990 dm.dmSize = sizeof(DEVMODEW);
3991 dm.dmDriverExtra = 0;
3993 DM_ORIENTATION | DM_PAPERSIZE |
3994 DM_PAPERLENGTH | DM_PAPERWIDTH |
3997 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3998 DM_YRESOLUTION | DM_TTOPTION;
4000 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
4001 dm.u1.s1.dmPaperSize = DMPAPER_A4;
4002 dm.u1.s1.dmPaperLength = 2970;
4003 dm.u1.s1.dmPaperWidth = 2100;
4005 dm.u1.s1.dmScale = 100;
4006 dm.u1.s1.dmCopies = 1;
4007 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
4008 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
4011 dm.dmYResolution = 300; /* 300dpi */
4012 dm.dmTTOption = DMTT_BITMAP;
4015 /* dm.dmLogPixels */
4016 /* dm.dmBitsPerPel */
4017 /* dm.dmPelsWidth */
4018 /* dm.dmPelsHeight */
4019 /* dm.u2.dmDisplayFlags */
4020 /* dm.dmDisplayFrequency */
4021 /* dm.dmICMMethod */
4022 /* dm.dmICMIntent */
4023 /* dm.dmMediaType */
4024 /* dm.dmDitherType */
4025 /* dm.dmReserved1 */
4026 /* dm.dmReserved2 */
4027 /* dm.dmPanningWidth */
4028 /* dm.dmPanningHeight */
4030 if(buflen >= sizeof(DEVMODEW))
4031 memcpy(ptr, &dm, sizeof(DEVMODEW));
4032 *needed = sizeof(DEVMODEW);
4035 /*****************************************************************************
4036 * WINSPOOL_GetDevModeFromReg
4038 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4039 * DevMode is stored either as unicode or ascii.
4041 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4043 DWORD buflen, DWORD *needed)
4045 DWORD sz = buflen, type;
4048 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4049 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4050 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4051 if (sz < sizeof(DEVMODEA))
4053 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4056 /* ensures that dmSize is not erratically bogus if registry is invalid */
4057 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4058 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4059 sz += (CCHDEVICENAME + CCHFORMNAME);
4060 if (ptr && (buflen >= sz)) {
4061 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4062 memcpy(ptr, dmW, sz);
4063 HeapFree(GetProcessHeap(),0,dmW);
4069 /*********************************************************************
4070 * WINSPOOL_GetPrinter_1
4072 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4074 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4075 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4077 DWORD size, left = cbBuf;
4078 BOOL space = (cbBuf > 0);
4083 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4084 if(space && size <= left) {
4085 pi1->pName = (LPWSTR)ptr;
4093 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4094 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4095 if(space && size <= left) {
4096 pi1->pDescription = (LPWSTR)ptr;
4104 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4105 if(space && size <= left) {
4106 pi1->pComment = (LPWSTR)ptr;
4114 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4116 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4117 memset(pi1, 0, sizeof(*pi1));
4121 /*********************************************************************
4122 * WINSPOOL_GetPrinter_2
4124 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4126 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4127 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4129 DWORD size, left = cbBuf;
4130 BOOL space = (cbBuf > 0);
4135 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4136 if(space && size <= left) {
4137 pi2->pPrinterName = (LPWSTR)ptr;
4144 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4145 if(space && size <= left) {
4146 pi2->pShareName = (LPWSTR)ptr;
4153 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4154 if(space && size <= left) {
4155 pi2->pPortName = (LPWSTR)ptr;
4162 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4163 if(space && size <= left) {
4164 pi2->pDriverName = (LPWSTR)ptr;
4171 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4172 if(space && size <= left) {
4173 pi2->pComment = (LPWSTR)ptr;
4180 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4181 if(space && size <= left) {
4182 pi2->pLocation = (LPWSTR)ptr;
4189 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4190 if(space && size <= left) {
4191 pi2->pDevMode = (LPDEVMODEW)ptr;
4200 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4201 if(space && size <= left) {
4202 pi2->pDevMode = (LPDEVMODEW)ptr;
4209 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4210 if(space && size <= left) {
4211 pi2->pSepFile = (LPWSTR)ptr;
4218 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4219 if(space && size <= left) {
4220 pi2->pPrintProcessor = (LPWSTR)ptr;
4227 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4228 if(space && size <= left) {
4229 pi2->pDatatype = (LPWSTR)ptr;
4236 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4237 if(space && size <= left) {
4238 pi2->pParameters = (LPWSTR)ptr;
4246 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4247 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4248 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4249 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4250 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4253 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4254 memset(pi2, 0, sizeof(*pi2));
4259 /*********************************************************************
4260 * WINSPOOL_GetPrinter_4
4262 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4264 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4265 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4267 DWORD size, left = cbBuf;
4268 BOOL space = (cbBuf > 0);
4273 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4274 if(space && size <= left) {
4275 pi4->pPrinterName = (LPWSTR)ptr;
4283 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4286 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4287 memset(pi4, 0, sizeof(*pi4));
4292 /*********************************************************************
4293 * WINSPOOL_GetPrinter_5
4295 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4297 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4298 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4300 DWORD size, left = cbBuf;
4301 BOOL space = (cbBuf > 0);
4306 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4307 if(space && size <= left) {
4308 pi5->pPrinterName = (LPWSTR)ptr;
4315 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4316 if(space && size <= left) {
4317 pi5->pPortName = (LPWSTR)ptr;
4325 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4326 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4327 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4330 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4331 memset(pi5, 0, sizeof(*pi5));
4336 /*********************************************************************
4337 * WINSPOOL_GetPrinter_7
4339 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4341 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4342 DWORD cbBuf, LPDWORD pcbNeeded)
4344 DWORD size, left = cbBuf;
4345 BOOL space = (cbBuf > 0);
4350 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4353 size = sizeof(pi7->pszObjectGUID);
4355 if (space && size <= left) {
4356 pi7->pszObjectGUID = (LPWSTR)ptr;
4363 /* We do not have a Directory Service */
4364 pi7->dwAction = DSPRINT_UNPUBLISH;
4367 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4368 memset(pi7, 0, sizeof(*pi7));
4373 /*********************************************************************
4374 * WINSPOOL_GetPrinter_9
4376 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4378 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4379 DWORD cbBuf, LPDWORD pcbNeeded)
4382 BOOL space = (cbBuf > 0);
4386 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4387 if(space && size <= cbBuf) {
4388 pi9->pDevMode = (LPDEVMODEW)buf;
4395 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4396 if(space && size <= cbBuf) {
4397 pi9->pDevMode = (LPDEVMODEW)buf;
4403 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4404 memset(pi9, 0, sizeof(*pi9));
4409 /*****************************************************************************
4410 * GetPrinterW [WINSPOOL.@]
4412 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4413 DWORD cbBuf, LPDWORD pcbNeeded)
4415 DWORD size, needed = 0, err;
4420 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4422 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4425 SetLastError( err );
4432 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4434 size = sizeof(PRINTER_INFO_2W);
4436 ptr = pPrinter + size;
4438 memset(pPrinter, 0, size);
4443 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4450 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4452 size = sizeof(PRINTER_INFO_4W);
4454 ptr = pPrinter + size;
4456 memset(pPrinter, 0, size);
4461 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4469 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4471 size = sizeof(PRINTER_INFO_5W);
4473 ptr = pPrinter + size;
4475 memset(pPrinter, 0, size);
4481 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4489 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4491 size = sizeof(PRINTER_INFO_6);
4492 if (size <= cbBuf) {
4493 /* FIXME: We do not update the status yet */
4494 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4506 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4508 size = sizeof(PRINTER_INFO_7W);
4509 if (size <= cbBuf) {
4510 ptr = pPrinter + size;
4512 memset(pPrinter, 0, size);
4518 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4525 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4526 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4530 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4532 size = sizeof(PRINTER_INFO_9W);
4534 ptr = pPrinter + size;
4536 memset(pPrinter, 0, size);
4542 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4549 FIXME("Unimplemented level %d\n", Level);
4550 SetLastError(ERROR_INVALID_LEVEL);
4551 RegCloseKey(hkeyPrinter);
4555 RegCloseKey(hkeyPrinter);
4557 TRACE("returning %d needed = %d\n", ret, needed);
4558 if(pcbNeeded) *pcbNeeded = needed;
4560 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4564 /*****************************************************************************
4565 * GetPrinterA [WINSPOOL.@]
4567 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4568 DWORD cbBuf, LPDWORD pcbNeeded)
4574 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4576 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4578 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4579 HeapFree(GetProcessHeap(), 0, buf);
4584 /*****************************************************************************
4585 * WINSPOOL_EnumPrintersW
4587 * Implementation of EnumPrintersW
4589 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4590 DWORD dwLevel, LPBYTE lpbPrinters,
4591 DWORD cbBuf, LPDWORD lpdwNeeded,
4592 LPDWORD lpdwReturned)
4595 HKEY hkeyPrinters, hkeyPrinter;
4596 WCHAR PrinterName[255];
4597 DWORD needed = 0, number = 0;
4598 DWORD used, i, left;
4602 memset(lpbPrinters, 0, cbBuf);
4608 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4609 if(dwType == PRINTER_ENUM_DEFAULT)
4612 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4613 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4614 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4616 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4622 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4623 FIXME("dwType = %08x\n", dwType);
4624 SetLastError(ERROR_INVALID_FLAGS);
4628 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4630 ERR("Can't create Printers key\n");
4634 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4635 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4636 RegCloseKey(hkeyPrinters);
4637 ERR("Can't query Printers key\n");
4640 TRACE("Found %d printers\n", number);
4644 used = number * sizeof(PRINTER_INFO_1W);
4647 used = number * sizeof(PRINTER_INFO_2W);
4650 used = number * sizeof(PRINTER_INFO_4W);
4653 used = number * sizeof(PRINTER_INFO_5W);
4657 SetLastError(ERROR_INVALID_LEVEL);
4658 RegCloseKey(hkeyPrinters);
4661 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4663 for(i = 0; i < number; i++) {
4664 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4666 ERR("Can't enum key number %d\n", i);
4667 RegCloseKey(hkeyPrinters);
4670 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4671 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4673 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4674 RegCloseKey(hkeyPrinters);
4679 buf = lpbPrinters + used;
4680 left = cbBuf - used;
4688 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4691 if(pi) pi += sizeof(PRINTER_INFO_1W);
4694 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4697 if(pi) pi += sizeof(PRINTER_INFO_2W);
4700 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4703 if(pi) pi += sizeof(PRINTER_INFO_4W);
4706 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4709 if(pi) pi += sizeof(PRINTER_INFO_5W);
4712 ERR("Shouldn't be here!\n");
4713 RegCloseKey(hkeyPrinter);
4714 RegCloseKey(hkeyPrinters);
4717 RegCloseKey(hkeyPrinter);
4719 RegCloseKey(hkeyPrinters);
4726 memset(lpbPrinters, 0, cbBuf);
4727 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4731 *lpdwReturned = number;
4732 SetLastError(ERROR_SUCCESS);
4737 /******************************************************************
4738 * EnumPrintersW [WINSPOOL.@]
4740 * Enumerates the available printers, print servers and print
4741 * providers, depending on the specified flags, name and level.
4745 * If level is set to 1:
4746 * Returns an array of PRINTER_INFO_1 data structures in the
4747 * lpbPrinters buffer.
4749 * If level is set to 2:
4750 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4751 * Returns an array of PRINTER_INFO_2 data structures in the
4752 * lpbPrinters buffer. Note that according to MSDN also an
4753 * OpenPrinter should be performed on every remote printer.
4755 * If level is set to 4 (officially WinNT only):
4756 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4757 * Fast: Only the registry is queried to retrieve printer names,
4758 * no connection to the driver is made.
4759 * Returns an array of PRINTER_INFO_4 data structures in the
4760 * lpbPrinters buffer.
4762 * If level is set to 5 (officially WinNT4/Win9x only):
4763 * Fast: Only the registry is queried to retrieve printer names,
4764 * no connection to the driver is made.
4765 * Returns an array of PRINTER_INFO_5 data structures in the
4766 * lpbPrinters buffer.
4768 * If level set to 3 or 6+:
4769 * returns zero (failure!)
4771 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4775 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4776 * - Only levels 2, 4 and 5 are implemented at the moment.
4777 * - 16-bit printer drivers are not enumerated.
4778 * - Returned amount of bytes used/needed does not match the real Windoze
4779 * implementation (as in this implementation, all strings are part
4780 * of the buffer, whereas Win32 keeps them somewhere else)
4781 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4784 * - In a regular Wine installation, no registry settings for printers
4785 * exist, which makes this function return an empty list.
4787 BOOL WINAPI EnumPrintersW(
4788 DWORD dwType, /* [in] Types of print objects to enumerate */
4789 LPWSTR lpszName, /* [in] name of objects to enumerate */
4790 DWORD dwLevel, /* [in] type of printer info structure */
4791 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4792 DWORD cbBuf, /* [in] max size of buffer in bytes */
4793 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4794 LPDWORD lpdwReturned /* [out] number of entries returned */
4797 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4798 lpdwNeeded, lpdwReturned);
4801 /******************************************************************
4802 * EnumPrintersA [WINSPOOL.@]
4807 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4808 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4811 UNICODE_STRING pNameU;
4815 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4816 pPrinters, cbBuf, pcbNeeded, pcReturned);
4818 pNameW = asciitounicode(&pNameU, pName);
4820 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4821 MS Office need this */
4822 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4824 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4826 RtlFreeUnicodeString(&pNameU);
4828 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4830 HeapFree(GetProcessHeap(), 0, pPrintersW);
4834 /*****************************************************************************
4835 * WINSPOOL_GetDriverInfoFromReg [internal]
4837 * Enters the information from the registry into the DRIVER_INFO struct
4840 * zero if the printer driver does not exist in the registry
4841 * (only if Level > 1) otherwise nonzero
4843 static BOOL WINSPOOL_GetDriverInfoFromReg(
4846 const printenv_t * env,
4848 LPBYTE ptr, /* DRIVER_INFO */
4849 LPBYTE pDriverStrings, /* strings buffer */
4850 DWORD cbBuf, /* size of string buffer */
4851 LPDWORD pcbNeeded) /* space needed for str. */
4855 WCHAR driverdir[MAX_PATH];
4857 LPBYTE strPtr = pDriverStrings;
4858 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4860 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4861 debugstr_w(DriverName), env,
4862 Level, di, pDriverStrings, cbBuf);
4864 if (di) ZeroMemory(di, di_sizeof[Level]);
4866 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4867 if (*pcbNeeded <= cbBuf)
4868 strcpyW((LPWSTR)strPtr, DriverName);
4870 /* pName for level 1 has a different offset! */
4872 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4876 /* .cVersion and .pName for level > 1 */
4878 di->cVersion = env->driverversion;
4879 di->pName = (LPWSTR) strPtr;
4880 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4883 /* Reserve Space for the largest subdir and a Backslash*/
4884 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4885 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4886 /* Should never Fail */
4889 lstrcatW(driverdir, env->versionsubdir);
4890 lstrcatW(driverdir, backslashW);
4892 /* dirlen must not include the terminating zero */
4893 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4895 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4896 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4897 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4902 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4905 if (*pcbNeeded <= cbBuf) {
4906 lstrcpyW((LPWSTR)strPtr, env->envname);
4907 if (di) di->pEnvironment = (LPWSTR)strPtr;
4908 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4911 /* .pDriverPath is the Graphics rendering engine.
4912 The full Path is required to avoid a crash in some apps */
4913 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4915 if (*pcbNeeded <= cbBuf)
4916 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4918 if (di) di->pDriverPath = (LPWSTR)strPtr;
4919 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4922 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4923 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4925 if (*pcbNeeded <= cbBuf)
4926 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4928 if (di) di->pDataFile = (LPWSTR)strPtr;
4929 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4932 /* .pConfigFile is the Driver user Interface */
4933 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4935 if (*pcbNeeded <= cbBuf)
4936 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4938 if (di) di->pConfigFile = (LPWSTR)strPtr;
4939 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4943 RegCloseKey(hkeyDriver);
4944 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4949 RegCloseKey(hkeyDriver);
4950 FIXME("level 5: incomplete\n");
4955 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4957 if (*pcbNeeded <= cbBuf)
4958 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4960 if (di) di->pHelpFile = (LPWSTR)strPtr;
4961 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4964 /* .pDependentFiles */
4965 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4967 if (*pcbNeeded <= cbBuf)
4968 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4970 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4971 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4973 else if (GetVersion() & 0x80000000) {
4974 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4975 size = 2 * sizeof(WCHAR);
4977 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4979 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4980 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4983 /* .pMonitorName is the optional Language Monitor */
4984 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4986 if (*pcbNeeded <= cbBuf)
4987 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4989 if (di) di->pMonitorName = (LPWSTR)strPtr;
4990 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4993 /* .pDefaultDataType */
4994 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4996 if(*pcbNeeded <= cbBuf)
4997 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4999 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
5000 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5004 RegCloseKey(hkeyDriver);
5005 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5009 /* .pszzPreviousNames */
5010 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
5012 if(*pcbNeeded <= cbBuf)
5013 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
5015 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
5016 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5020 RegCloseKey(hkeyDriver);
5021 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5025 /* support is missing, but not important enough for a FIXME */
5026 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5029 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5031 if(*pcbNeeded <= cbBuf)
5032 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5034 if (di) di->pszMfgName = (LPWSTR)strPtr;
5035 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5039 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5041 if(*pcbNeeded <= cbBuf)
5042 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5044 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5045 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5048 /* .pszHardwareID */
5049 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5051 if(*pcbNeeded <= cbBuf)
5052 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5054 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5055 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5059 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5061 if(*pcbNeeded <= cbBuf)
5062 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5064 if (di) di->pszProvider = (LPWSTR)strPtr;
5065 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5069 RegCloseKey(hkeyDriver);
5073 /* support is missing, but not important enough for a FIXME */
5074 TRACE("level 8: incomplete\n");
5076 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5077 RegCloseKey(hkeyDriver);
5081 /*****************************************************************************
5082 * GetPrinterDriverW [WINSPOOL.@]
5084 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5085 DWORD Level, LPBYTE pDriverInfo,
5086 DWORD cbBuf, LPDWORD pcbNeeded)
5089 WCHAR DriverName[100];
5090 DWORD ret, type, size, needed = 0;
5092 HKEY hkeyPrinter, hkeyDrivers;
5093 const printenv_t * env;
5095 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5096 Level,pDriverInfo,cbBuf, pcbNeeded);
5099 ZeroMemory(pDriverInfo, cbBuf);
5101 if (!(name = get_opened_printer_name(hPrinter))) {
5102 SetLastError(ERROR_INVALID_HANDLE);
5106 if (Level < 1 || Level == 7 || Level > 8) {
5107 SetLastError(ERROR_INVALID_LEVEL);
5111 env = validate_envW(pEnvironment);
5112 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5114 ret = open_printer_reg_key( name, &hkeyPrinter );
5117 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5118 SetLastError( ret );
5122 size = sizeof(DriverName);
5124 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5125 (LPBYTE)DriverName, &size);
5126 RegCloseKey(hkeyPrinter);
5127 if(ret != ERROR_SUCCESS) {
5128 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5132 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5134 ERR("Can't create Drivers key\n");
5138 size = di_sizeof[Level];
5139 if ((size <= cbBuf) && pDriverInfo)
5140 ptr = pDriverInfo + size;
5142 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5143 env, Level, pDriverInfo, ptr,
5144 (cbBuf < size) ? 0 : cbBuf - size,
5146 RegCloseKey(hkeyDrivers);
5150 RegCloseKey(hkeyDrivers);
5152 if(pcbNeeded) *pcbNeeded = size + needed;
5153 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5154 if(cbBuf >= size + needed) return TRUE;
5155 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5159 /*****************************************************************************
5160 * GetPrinterDriverA [WINSPOOL.@]
5162 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5163 DWORD Level, LPBYTE pDriverInfo,
5164 DWORD cbBuf, LPDWORD pcbNeeded)
5167 UNICODE_STRING pEnvW;
5173 ZeroMemory(pDriverInfo, cbBuf);
5174 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5177 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5178 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5181 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5183 HeapFree(GetProcessHeap(), 0, buf);
5185 RtlFreeUnicodeString(&pEnvW);
5189 /*****************************************************************************
5190 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5192 * Return the PATH for the Printer-Drivers (UNICODE)
5195 * pName [I] Servername (NT only) or NULL (local Computer)
5196 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5197 * Level [I] Structure-Level (must be 1)
5198 * pDriverDirectory [O] PTR to Buffer that receives the Result
5199 * cbBuf [I] Size of Buffer at pDriverDirectory
5200 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5201 * required for pDriverDirectory
5204 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5205 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5206 * if cbBuf is too small
5208 * Native Values returned in pDriverDirectory on Success:
5209 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5210 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5211 *| win9x(Windows 4.0): "%winsysdir%"
5213 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5216 *- Only NULL or "" is supported for pName
5219 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5220 DWORD Level, LPBYTE pDriverDirectory,
5221 DWORD cbBuf, LPDWORD pcbNeeded)
5223 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5224 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5226 if ((backend == NULL) && !load_backend()) return FALSE;
5229 /* (Level != 1) is ignored in win9x */
5230 SetLastError(ERROR_INVALID_LEVEL);
5233 if (pcbNeeded == NULL) {
5234 /* (pcbNeeded == NULL) is ignored in win9x */
5235 SetLastError(RPC_X_NULL_REF_POINTER);
5239 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5240 pDriverDirectory, cbBuf, pcbNeeded);
5245 /*****************************************************************************
5246 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5248 * Return the PATH for the Printer-Drivers (ANSI)
5250 * See GetPrinterDriverDirectoryW.
5253 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5256 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5257 DWORD Level, LPBYTE pDriverDirectory,
5258 DWORD cbBuf, LPDWORD pcbNeeded)
5260 UNICODE_STRING nameW, environmentW;
5263 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5264 WCHAR *driverDirectoryW = NULL;
5266 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5267 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5269 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5271 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5272 else nameW.Buffer = NULL;
5273 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5274 else environmentW.Buffer = NULL;
5276 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5277 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5280 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5281 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5283 *pcbNeeded = needed;
5284 ret = needed <= cbBuf;
5286 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5288 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5290 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5291 RtlFreeUnicodeString(&environmentW);
5292 RtlFreeUnicodeString(&nameW);
5297 /*****************************************************************************
5298 * AddPrinterDriverA [WINSPOOL.@]
5300 * See AddPrinterDriverW.
5303 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5305 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5306 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5309 /******************************************************************************
5310 * AddPrinterDriverW (WINSPOOL.@)
5312 * Install a Printer Driver
5315 * pName [I] Servername or NULL (local Computer)
5316 * level [I] Level for the supplied DRIVER_INFO_*W struct
5317 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5324 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5326 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5327 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5330 /*****************************************************************************
5331 * AddPrintProcessorA [WINSPOOL.@]
5333 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5334 LPSTR pPrintProcessorName)
5336 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5337 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5341 /*****************************************************************************
5342 * AddPrintProcessorW [WINSPOOL.@]
5344 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5345 LPWSTR pPrintProcessorName)
5347 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5348 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5352 /*****************************************************************************
5353 * AddPrintProvidorA [WINSPOOL.@]
5355 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5357 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5361 /*****************************************************************************
5362 * AddPrintProvidorW [WINSPOOL.@]
5364 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5366 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5370 /*****************************************************************************
5371 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5373 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5374 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5376 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5377 pDevModeOutput, pDevModeInput);
5381 /*****************************************************************************
5382 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5384 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5385 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5387 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5388 pDevModeOutput, pDevModeInput);
5392 /*****************************************************************************
5393 * PrinterProperties [WINSPOOL.@]
5395 * Displays a dialog to set the properties of the printer.
5398 * nonzero on success or zero on failure
5401 * implemented as stub only
5403 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5404 HANDLE hPrinter /* [in] handle to printer object */
5406 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5407 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5411 /*****************************************************************************
5412 * EnumJobsA [WINSPOOL.@]
5415 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5416 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5419 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5420 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5422 if(pcbNeeded) *pcbNeeded = 0;
5423 if(pcReturned) *pcReturned = 0;
5428 /*****************************************************************************
5429 * EnumJobsW [WINSPOOL.@]
5432 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5433 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5436 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5437 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5439 if(pcbNeeded) *pcbNeeded = 0;
5440 if(pcReturned) *pcReturned = 0;
5444 /*****************************************************************************
5445 * WINSPOOL_EnumPrinterDrivers [internal]
5447 * Delivers information about all printer drivers installed on the
5448 * localhost or a given server
5451 * nonzero on success or zero on failure. If the buffer for the returned
5452 * information is too small the function will return an error
5455 * - only implemented for localhost, foreign hosts will return an error
5457 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5458 DWORD Level, LPBYTE pDriverInfo,
5460 DWORD cbBuf, LPDWORD pcbNeeded,
5461 LPDWORD pcFound, DWORD data_offset)
5465 const printenv_t * env;
5467 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5468 debugstr_w(pName), debugstr_w(pEnvironment),
5469 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5471 env = validate_envW(pEnvironment);
5472 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5476 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5478 ERR("Can't open Drivers key\n");
5482 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5483 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5484 RegCloseKey(hkeyDrivers);
5485 ERR("Can't query Drivers key\n");
5488 TRACE("Found %d Drivers\n", *pcFound);
5490 /* get size of single struct
5491 * unicode and ascii structure have the same size
5493 size = di_sizeof[Level];
5495 if (data_offset == 0)
5496 data_offset = size * (*pcFound);
5497 *pcbNeeded = data_offset;
5499 for( i = 0; i < *pcFound; i++) {
5500 WCHAR DriverNameW[255];
5501 PBYTE table_ptr = NULL;
5502 PBYTE data_ptr = NULL;
5505 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5507 ERR("Can't enum key number %d\n", i);
5508 RegCloseKey(hkeyDrivers);
5512 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5513 table_ptr = pDriverInfo + (driver_index + i) * size;
5514 if (pDriverInfo && *pcbNeeded <= cbBuf)
5515 data_ptr = pDriverInfo + *pcbNeeded;
5517 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5518 env, Level, table_ptr, data_ptr,
5519 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5521 RegCloseKey(hkeyDrivers);
5525 *pcbNeeded += needed;
5528 RegCloseKey(hkeyDrivers);
5530 if(cbBuf < *pcbNeeded){
5531 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5538 /*****************************************************************************
5539 * EnumPrinterDriversW [WINSPOOL.@]
5541 * see function EnumPrinterDrivers for RETURNS, BUGS
5543 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5544 LPBYTE pDriverInfo, DWORD cbBuf,
5545 LPDWORD pcbNeeded, LPDWORD pcReturned)
5547 static const WCHAR allW[] = {'a','l','l',0};
5551 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5553 SetLastError(RPC_X_NULL_REF_POINTER);
5557 /* check for local drivers */
5558 if((pName) && (pName[0])) {
5559 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5560 SetLastError(ERROR_ACCESS_DENIED);
5564 /* check input parameter */
5565 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5566 SetLastError(ERROR_INVALID_LEVEL);
5570 if(pDriverInfo && cbBuf > 0)
5571 memset( pDriverInfo, 0, cbBuf);
5573 /* Exception: pull all printers */
5574 if (pEnvironment && !strcmpW(pEnvironment, allW))
5576 DWORD i, needed, bufsize = cbBuf;
5577 DWORD total_needed = 0;
5578 DWORD total_found = 0;
5581 /* Precompute the overall total; we need this to know
5582 where pointers end and data begins (i.e. data_offset) */
5583 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5586 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5587 NULL, 0, 0, &needed, &found, 0);
5588 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5589 total_needed += needed;
5590 total_found += found;
5593 data_offset = di_sizeof[Level] * total_found;
5598 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5601 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5602 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5603 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5605 *pcReturned += found;
5606 *pcbNeeded = needed;
5607 data_offset = needed;
5608 total_found += found;
5613 /* Normal behavior */
5614 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5615 0, cbBuf, pcbNeeded, &found, 0);
5617 *pcReturned = found;
5622 /*****************************************************************************
5623 * EnumPrinterDriversA [WINSPOOL.@]
5625 * see function EnumPrinterDrivers for RETURNS, BUGS
5627 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5628 LPBYTE pDriverInfo, DWORD cbBuf,
5629 LPDWORD pcbNeeded, LPDWORD pcReturned)
5632 UNICODE_STRING pNameW, pEnvironmentW;
5633 PWSTR pwstrNameW, pwstrEnvironmentW;
5637 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5639 pwstrNameW = asciitounicode(&pNameW, pName);
5640 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5642 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5643 buf, cbBuf, pcbNeeded, pcReturned);
5645 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5647 HeapFree(GetProcessHeap(), 0, buf);
5649 RtlFreeUnicodeString(&pNameW);
5650 RtlFreeUnicodeString(&pEnvironmentW);
5655 /******************************************************************************
5656 * EnumPortsA (WINSPOOL.@)
5661 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5662 LPDWORD pcbNeeded, LPDWORD pcReturned)
5665 LPBYTE bufferW = NULL;
5666 LPWSTR nameW = NULL;
5668 DWORD numentries = 0;
5671 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5672 cbBuf, pcbNeeded, pcReturned);
5674 /* convert servername to unicode */
5676 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5677 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5678 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5680 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5681 needed = cbBuf * sizeof(WCHAR);
5682 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5683 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5685 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5686 if (pcbNeeded) needed = *pcbNeeded;
5687 /* HeapReAlloc return NULL, when bufferW was NULL */
5688 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5689 HeapAlloc(GetProcessHeap(), 0, needed);
5691 /* Try again with the large Buffer */
5692 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5694 needed = pcbNeeded ? *pcbNeeded : 0;
5695 numentries = pcReturned ? *pcReturned : 0;
5698 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5699 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5702 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5703 DWORD entrysize = 0;
5706 LPPORT_INFO_2W pi2w;
5707 LPPORT_INFO_2A pi2a;
5710 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5712 /* First pass: calculate the size for all Entries */
5713 pi2w = (LPPORT_INFO_2W) bufferW;
5714 pi2a = (LPPORT_INFO_2A) pPorts;
5716 while (index < numentries) {
5718 needed += entrysize; /* PORT_INFO_?A */
5719 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5721 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5722 NULL, 0, NULL, NULL);
5724 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5725 NULL, 0, NULL, NULL);
5726 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5727 NULL, 0, NULL, NULL);
5729 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5730 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5731 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5734 /* check for errors and quit on failure */
5735 if (cbBuf < needed) {
5736 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5740 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5741 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5742 cbBuf -= len ; /* free Bytes in the user-Buffer */
5743 pi2w = (LPPORT_INFO_2W) bufferW;
5744 pi2a = (LPPORT_INFO_2A) pPorts;
5746 /* Second Pass: Fill the User Buffer (if we have one) */
5747 while ((index < numentries) && pPorts) {
5749 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5750 pi2a->pPortName = ptr;
5751 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5752 ptr, cbBuf , NULL, NULL);
5756 pi2a->pMonitorName = ptr;
5757 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5758 ptr, cbBuf, NULL, NULL);
5762 pi2a->pDescription = ptr;
5763 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5764 ptr, cbBuf, NULL, NULL);
5768 pi2a->fPortType = pi2w->fPortType;
5769 pi2a->Reserved = 0; /* documented: "must be zero" */
5772 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5773 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5774 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5779 if (pcbNeeded) *pcbNeeded = needed;
5780 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5782 HeapFree(GetProcessHeap(), 0, nameW);
5783 HeapFree(GetProcessHeap(), 0, bufferW);
5785 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5786 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5792 /******************************************************************************
5793 * EnumPortsW (WINSPOOL.@)
5795 * Enumerate available Ports
5798 * pName [I] Servername or NULL (local Computer)
5799 * Level [I] Structure-Level (1 or 2)
5800 * pPorts [O] PTR to Buffer that receives the Result
5801 * cbBuf [I] Size of Buffer at pPorts
5802 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5803 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5807 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5810 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5813 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5814 cbBuf, pcbNeeded, pcReturned);
5816 if ((backend == NULL) && !load_backend()) return FALSE;
5818 /* Level is not checked in win9x */
5819 if (!Level || (Level > 2)) {
5820 WARN("level (%d) is ignored in win9x\n", Level);
5821 SetLastError(ERROR_INVALID_LEVEL);
5824 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5825 SetLastError(RPC_X_NULL_REF_POINTER);
5829 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5832 /******************************************************************************
5833 * GetDefaultPrinterW (WINSPOOL.@)
5836 * This function must read the value from data 'device' of key
5837 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5839 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5843 WCHAR *buffer, *ptr;
5847 SetLastError(ERROR_INVALID_PARAMETER);
5851 /* make the buffer big enough for the stuff from the profile/registry,
5852 * the content must fit into the local buffer to compute the correct
5853 * size even if the extern buffer is too small or not given.
5854 * (20 for ,driver,port) */
5856 len = max(100, (insize + 20));
5857 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5859 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5861 SetLastError (ERROR_FILE_NOT_FOUND);
5865 TRACE("%s\n", debugstr_w(buffer));
5867 if ((ptr = strchrW(buffer, ',')) == NULL)
5869 SetLastError(ERROR_INVALID_NAME);
5875 *namesize = strlenW(buffer) + 1;
5876 if(!name || (*namesize > insize))
5878 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5882 strcpyW(name, buffer);
5885 HeapFree( GetProcessHeap(), 0, buffer);
5890 /******************************************************************************
5891 * GetDefaultPrinterA (WINSPOOL.@)
5893 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5897 WCHAR *bufferW = NULL;
5901 SetLastError(ERROR_INVALID_PARAMETER);
5905 if(name && *namesize) {
5907 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5910 if(!GetDefaultPrinterW( bufferW, namesize)) {
5915 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5919 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5922 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5925 HeapFree( GetProcessHeap(), 0, bufferW);
5930 /******************************************************************************
5931 * SetDefaultPrinterW (WINSPOOL.204)
5933 * Set the Name of the Default Printer
5936 * pszPrinter [I] Name of the Printer or NULL
5943 * When the Parameter is NULL or points to an Empty String and
5944 * a Default Printer was already present, then this Function changes nothing.
5945 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5946 * the First enumerated local Printer is used.
5949 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5951 WCHAR default_printer[MAX_PATH];
5952 LPWSTR buffer = NULL;
5958 TRACE("(%s)\n", debugstr_w(pszPrinter));
5959 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5961 default_printer[0] = '\0';
5962 size = sizeof(default_printer)/sizeof(WCHAR);
5964 /* if we have a default Printer, do nothing. */
5965 if (GetDefaultPrinterW(default_printer, &size))
5969 /* we have no default Printer: search local Printers and use the first */
5970 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5972 default_printer[0] = '\0';
5973 size = sizeof(default_printer)/sizeof(WCHAR);
5974 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5976 pszPrinter = default_printer;
5977 TRACE("using %s\n", debugstr_w(pszPrinter));
5982 if (pszPrinter == NULL) {
5983 TRACE("no local printer found\n");
5984 SetLastError(ERROR_FILE_NOT_FOUND);
5989 /* "pszPrinter" is never empty or NULL here. */
5990 namelen = lstrlenW(pszPrinter);
5991 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5992 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5994 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5995 HeapFree(GetProcessHeap(), 0, buffer);
5996 SetLastError(ERROR_FILE_NOT_FOUND);
6000 /* read the devices entry for the printer (driver,port) to build the string for the
6001 default device entry (printer,driver,port) */
6002 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
6003 buffer[namelen] = ',';
6004 namelen++; /* move index to the start of the driver */
6006 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
6007 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
6009 TRACE("set device to %s\n", debugstr_w(buffer));
6011 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
6012 TRACE("failed to set the device entry: %d\n", GetLastError());
6013 lres = ERROR_INVALID_PRINTER_NAME;
6016 /* remove the next section, when INIFileMapping is implemented */
6019 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
6020 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6027 if (lres != ERROR_FILE_NOT_FOUND)
6028 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6030 SetLastError(ERROR_INVALID_PRINTER_NAME);
6034 HeapFree(GetProcessHeap(), 0, buffer);
6035 return (lres == ERROR_SUCCESS);
6038 /******************************************************************************
6039 * SetDefaultPrinterA (WINSPOOL.202)
6041 * See SetDefaultPrinterW.
6044 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6046 LPWSTR bufferW = NULL;
6049 TRACE("(%s)\n", debugstr_a(pszPrinter));
6051 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6052 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6053 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6055 res = SetDefaultPrinterW(bufferW);
6056 HeapFree(GetProcessHeap(), 0, bufferW);
6060 /******************************************************************************
6061 * SetPrinterDataExA (WINSPOOL.@)
6063 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6064 LPCSTR pValueName, DWORD Type,
6065 LPBYTE pData, DWORD cbData)
6067 HKEY hkeyPrinter, hkeySubkey;
6070 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6071 debugstr_a(pValueName), Type, pData, cbData);
6073 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6077 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6079 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6080 RegCloseKey(hkeyPrinter);
6083 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6084 RegCloseKey(hkeySubkey);
6085 RegCloseKey(hkeyPrinter);
6089 /******************************************************************************
6090 * SetPrinterDataExW (WINSPOOL.@)
6092 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6093 LPCWSTR pValueName, DWORD Type,
6094 LPBYTE pData, DWORD cbData)
6096 HKEY hkeyPrinter, hkeySubkey;
6099 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6100 debugstr_w(pValueName), Type, pData, cbData);
6102 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6106 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6108 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6109 RegCloseKey(hkeyPrinter);
6112 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6113 RegCloseKey(hkeySubkey);
6114 RegCloseKey(hkeyPrinter);
6118 /******************************************************************************
6119 * SetPrinterDataA (WINSPOOL.@)
6121 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6122 LPBYTE pData, DWORD cbData)
6124 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6128 /******************************************************************************
6129 * SetPrinterDataW (WINSPOOL.@)
6131 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6132 LPBYTE pData, DWORD cbData)
6134 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6138 /******************************************************************************
6139 * GetPrinterDataExA (WINSPOOL.@)
6141 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6142 LPCSTR pValueName, LPDWORD pType,
6143 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6145 opened_printer_t *printer;
6146 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6149 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6150 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6152 printer = get_opened_printer(hPrinter);
6153 if(!printer) return ERROR_INVALID_HANDLE;
6155 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6156 if (ret) return ret;
6158 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6160 if (printer->name) {
6162 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6164 RegCloseKey(hkeyPrinters);
6167 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6168 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6169 RegCloseKey(hkeyPrinter);
6170 RegCloseKey(hkeyPrinters);
6175 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6176 0, pType, pData, pcbNeeded);
6178 if (!ret && !pData) ret = ERROR_MORE_DATA;
6180 RegCloseKey(hkeySubkey);
6181 RegCloseKey(hkeyPrinter);
6182 RegCloseKey(hkeyPrinters);
6184 TRACE("--> %d\n", ret);
6188 /******************************************************************************
6189 * GetPrinterDataExW (WINSPOOL.@)
6191 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6192 LPCWSTR pValueName, LPDWORD pType,
6193 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6195 opened_printer_t *printer;
6196 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6199 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6200 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6202 printer = get_opened_printer(hPrinter);
6203 if(!printer) return ERROR_INVALID_HANDLE;
6205 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6206 if (ret) return ret;
6208 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6210 if (printer->name) {
6212 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6214 RegCloseKey(hkeyPrinters);
6217 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6218 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6219 RegCloseKey(hkeyPrinter);
6220 RegCloseKey(hkeyPrinters);
6225 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6226 0, pType, pData, pcbNeeded);
6228 if (!ret && !pData) ret = ERROR_MORE_DATA;
6230 RegCloseKey(hkeySubkey);
6231 RegCloseKey(hkeyPrinter);
6232 RegCloseKey(hkeyPrinters);
6234 TRACE("--> %d\n", ret);
6238 /******************************************************************************
6239 * GetPrinterDataA (WINSPOOL.@)
6241 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6242 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6244 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6245 pData, nSize, pcbNeeded);
6248 /******************************************************************************
6249 * GetPrinterDataW (WINSPOOL.@)
6251 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6252 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6254 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6255 pData, nSize, pcbNeeded);
6258 /*******************************************************************************
6259 * EnumPrinterDataExW [WINSPOOL.@]
6261 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6262 LPBYTE pEnumValues, DWORD cbEnumValues,
6263 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6265 HKEY hkPrinter, hkSubKey;
6266 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6267 cbValueNameLen, cbMaxValueLen, cbValueLen,
6272 PPRINTER_ENUM_VALUESW ppev;
6274 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6276 if (pKeyName == NULL || *pKeyName == 0)
6277 return ERROR_INVALID_PARAMETER;
6279 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6280 if (ret != ERROR_SUCCESS)
6282 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6287 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6288 if (ret != ERROR_SUCCESS)
6290 r = RegCloseKey (hkPrinter);
6291 if (r != ERROR_SUCCESS)
6292 WARN ("RegCloseKey returned %i\n", r);
6293 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6294 debugstr_w (pKeyName), ret);
6298 ret = RegCloseKey (hkPrinter);
6299 if (ret != ERROR_SUCCESS)
6301 ERR ("RegCloseKey returned %i\n", ret);
6302 r = RegCloseKey (hkSubKey);
6303 if (r != ERROR_SUCCESS)
6304 WARN ("RegCloseKey returned %i\n", r);
6308 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6309 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6310 if (ret != ERROR_SUCCESS)
6312 r = RegCloseKey (hkSubKey);
6313 if (r != ERROR_SUCCESS)
6314 WARN ("RegCloseKey returned %i\n", r);
6315 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6319 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6320 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6322 if (cValues == 0) /* empty key */
6324 r = RegCloseKey (hkSubKey);
6325 if (r != ERROR_SUCCESS)
6326 WARN ("RegCloseKey returned %i\n", r);
6327 *pcbEnumValues = *pnEnumValues = 0;
6328 return ERROR_SUCCESS;
6331 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6333 hHeap = GetProcessHeap ();
6336 ERR ("GetProcessHeap failed\n");
6337 r = RegCloseKey (hkSubKey);
6338 if (r != ERROR_SUCCESS)
6339 WARN ("RegCloseKey returned %i\n", r);
6340 return ERROR_OUTOFMEMORY;
6343 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6344 if (lpValueName == NULL)
6346 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6347 r = RegCloseKey (hkSubKey);
6348 if (r != ERROR_SUCCESS)
6349 WARN ("RegCloseKey returned %i\n", r);
6350 return ERROR_OUTOFMEMORY;
6353 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6354 if (lpValue == NULL)
6356 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6357 if (HeapFree (hHeap, 0, lpValueName) == 0)
6358 WARN ("HeapFree failed with code %i\n", GetLastError ());
6359 r = RegCloseKey (hkSubKey);
6360 if (r != ERROR_SUCCESS)
6361 WARN ("RegCloseKey returned %i\n", r);
6362 return ERROR_OUTOFMEMORY;
6365 TRACE ("pass 1: calculating buffer required for all names and values\n");
6367 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6369 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6371 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6373 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6374 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6375 NULL, NULL, lpValue, &cbValueLen);
6376 if (ret != ERROR_SUCCESS)
6378 if (HeapFree (hHeap, 0, lpValue) == 0)
6379 WARN ("HeapFree failed with code %i\n", GetLastError ());
6380 if (HeapFree (hHeap, 0, lpValueName) == 0)
6381 WARN ("HeapFree failed with code %i\n", GetLastError ());
6382 r = RegCloseKey (hkSubKey);
6383 if (r != ERROR_SUCCESS)
6384 WARN ("RegCloseKey returned %i\n", r);
6385 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6389 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6390 debugstr_w (lpValueName), dwIndex,
6391 cbValueNameLen + 1, cbValueLen);
6393 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6394 cbBufSize += cbValueLen;
6397 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6399 *pcbEnumValues = cbBufSize;
6400 *pnEnumValues = cValues;
6402 if (cbEnumValues < cbBufSize) /* buffer too small */
6404 if (HeapFree (hHeap, 0, lpValue) == 0)
6405 WARN ("HeapFree failed with code %i\n", GetLastError ());
6406 if (HeapFree (hHeap, 0, lpValueName) == 0)
6407 WARN ("HeapFree failed with code %i\n", GetLastError ());
6408 r = RegCloseKey (hkSubKey);
6409 if (r != ERROR_SUCCESS)
6410 WARN ("RegCloseKey returned %i\n", r);
6411 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6412 return ERROR_MORE_DATA;
6415 TRACE ("pass 2: copying all names and values to buffer\n");
6417 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6418 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6420 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6422 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6423 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6424 NULL, &dwType, lpValue, &cbValueLen);
6425 if (ret != ERROR_SUCCESS)
6427 if (HeapFree (hHeap, 0, lpValue) == 0)
6428 WARN ("HeapFree failed with code %i\n", GetLastError ());
6429 if (HeapFree (hHeap, 0, lpValueName) == 0)
6430 WARN ("HeapFree failed with code %i\n", GetLastError ());
6431 r = RegCloseKey (hkSubKey);
6432 if (r != ERROR_SUCCESS)
6433 WARN ("RegCloseKey returned %i\n", r);
6434 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6438 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6439 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6440 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6441 pEnumValues += cbValueNameLen;
6443 /* return # of *bytes* (including trailing \0), not # of chars */
6444 ppev[dwIndex].cbValueName = cbValueNameLen;
6446 ppev[dwIndex].dwType = dwType;
6448 memcpy (pEnumValues, lpValue, cbValueLen);
6449 ppev[dwIndex].pData = pEnumValues;
6450 pEnumValues += cbValueLen;
6452 ppev[dwIndex].cbData = cbValueLen;
6454 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6455 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6458 if (HeapFree (hHeap, 0, lpValue) == 0)
6460 ret = GetLastError ();
6461 ERR ("HeapFree failed with code %i\n", ret);
6462 if (HeapFree (hHeap, 0, lpValueName) == 0)
6463 WARN ("HeapFree failed with code %i\n", GetLastError ());
6464 r = RegCloseKey (hkSubKey);
6465 if (r != ERROR_SUCCESS)
6466 WARN ("RegCloseKey returned %i\n", r);
6470 if (HeapFree (hHeap, 0, lpValueName) == 0)
6472 ret = GetLastError ();
6473 ERR ("HeapFree failed with code %i\n", ret);
6474 r = RegCloseKey (hkSubKey);
6475 if (r != ERROR_SUCCESS)
6476 WARN ("RegCloseKey returned %i\n", r);
6480 ret = RegCloseKey (hkSubKey);
6481 if (ret != ERROR_SUCCESS)
6483 ERR ("RegCloseKey returned %i\n", ret);
6487 return ERROR_SUCCESS;
6490 /*******************************************************************************
6491 * EnumPrinterDataExA [WINSPOOL.@]
6493 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6494 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6495 * what Windows 2000 SP1 does.
6498 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6499 LPBYTE pEnumValues, DWORD cbEnumValues,
6500 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6504 DWORD ret, dwIndex, dwBufSize;
6508 TRACE ("%p %s\n", hPrinter, pKeyName);
6510 if (pKeyName == NULL || *pKeyName == 0)
6511 return ERROR_INVALID_PARAMETER;
6513 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6516 ret = GetLastError ();
6517 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6521 hHeap = GetProcessHeap ();
6524 ERR ("GetProcessHeap failed\n");
6525 return ERROR_OUTOFMEMORY;
6528 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6529 if (pKeyNameW == NULL)
6531 ERR ("Failed to allocate %i bytes from process heap\n",
6532 (LONG)(len * sizeof (WCHAR)));
6533 return ERROR_OUTOFMEMORY;
6536 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6538 ret = GetLastError ();
6539 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6540 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6541 WARN ("HeapFree failed with code %i\n", GetLastError ());
6545 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6546 pcbEnumValues, pnEnumValues);
6547 if (ret != ERROR_SUCCESS)
6549 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6550 WARN ("HeapFree failed with code %i\n", GetLastError ());
6551 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6555 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6557 ret = GetLastError ();
6558 ERR ("HeapFree failed with code %i\n", ret);
6562 if (*pnEnumValues == 0) /* empty key */
6563 return ERROR_SUCCESS;
6566 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6568 PPRINTER_ENUM_VALUESW ppev =
6569 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6571 if (dwBufSize < ppev->cbValueName)
6572 dwBufSize = ppev->cbValueName;
6574 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6575 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6576 dwBufSize = ppev->cbData;
6579 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6581 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6582 if (pBuffer == NULL)
6584 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6585 return ERROR_OUTOFMEMORY;
6588 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6590 PPRINTER_ENUM_VALUESW ppev =
6591 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6593 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6594 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6598 ret = GetLastError ();
6599 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6600 if (HeapFree (hHeap, 0, pBuffer) == 0)
6601 WARN ("HeapFree failed with code %i\n", GetLastError ());
6605 memcpy (ppev->pValueName, pBuffer, len);
6607 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6609 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6610 ppev->dwType != REG_MULTI_SZ)
6613 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6614 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6617 ret = GetLastError ();
6618 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6619 if (HeapFree (hHeap, 0, pBuffer) == 0)
6620 WARN ("HeapFree failed with code %i\n", GetLastError ());
6624 memcpy (ppev->pData, pBuffer, len);
6626 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6627 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6630 if (HeapFree (hHeap, 0, pBuffer) == 0)
6632 ret = GetLastError ();
6633 ERR ("HeapFree failed with code %i\n", ret);
6637 return ERROR_SUCCESS;
6640 /******************************************************************************
6641 * AbortPrinter (WINSPOOL.@)
6643 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6645 FIXME("(%p), stub!\n", hPrinter);
6649 /******************************************************************************
6650 * AddPortA (WINSPOOL.@)
6655 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6657 LPWSTR nameW = NULL;
6658 LPWSTR monitorW = NULL;
6662 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6665 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6666 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6667 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6671 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6672 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6673 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6675 res = AddPortW(nameW, hWnd, monitorW);
6676 HeapFree(GetProcessHeap(), 0, nameW);
6677 HeapFree(GetProcessHeap(), 0, monitorW);
6681 /******************************************************************************
6682 * AddPortW (WINSPOOL.@)
6684 * Add a Port for a specific Monitor
6687 * pName [I] Servername or NULL (local Computer)
6688 * hWnd [I] Handle to parent Window for the Dialog-Box
6689 * pMonitorName [I] Name of the Monitor that manage the Port
6696 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6698 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6700 if ((backend == NULL) && !load_backend()) return FALSE;
6702 if (!pMonitorName) {
6703 SetLastError(RPC_X_NULL_REF_POINTER);
6707 return backend->fpAddPort(pName, hWnd, pMonitorName);
6710 /******************************************************************************
6711 * AddPortExA (WINSPOOL.@)
6716 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6719 PORT_INFO_2A * pi2A;
6720 LPWSTR nameW = NULL;
6721 LPWSTR monitorW = NULL;
6725 pi2A = (PORT_INFO_2A *) pBuffer;
6727 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6728 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6730 if ((level < 1) || (level > 2)) {
6731 SetLastError(ERROR_INVALID_LEVEL);
6736 SetLastError(ERROR_INVALID_PARAMETER);
6741 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6742 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6743 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6747 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6748 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6749 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6752 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6754 if (pi2A->pPortName) {
6755 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6756 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6757 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6761 if (pi2A->pMonitorName) {
6762 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6763 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6764 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6767 if (pi2A->pDescription) {
6768 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6769 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6770 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6772 pi2W.fPortType = pi2A->fPortType;
6773 pi2W.Reserved = pi2A->Reserved;
6776 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6778 HeapFree(GetProcessHeap(), 0, nameW);
6779 HeapFree(GetProcessHeap(), 0, monitorW);
6780 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6781 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6782 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6787 /******************************************************************************
6788 * AddPortExW (WINSPOOL.@)
6790 * Add a Port for a specific Monitor, without presenting a user interface
6793 * pName [I] Servername or NULL (local Computer)
6794 * level [I] Structure-Level (1 or 2) for pBuffer
6795 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6796 * pMonitorName [I] Name of the Monitor that manage the Port
6803 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6807 pi2 = (PORT_INFO_2W *) pBuffer;
6809 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6810 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6811 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6812 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6814 if ((backend == NULL) && !load_backend()) return FALSE;
6816 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6817 SetLastError(ERROR_INVALID_PARAMETER);
6821 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6824 /******************************************************************************
6825 * AddPrinterConnectionA (WINSPOOL.@)
6827 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6829 FIXME("%s\n", debugstr_a(pName));
6833 /******************************************************************************
6834 * AddPrinterConnectionW (WINSPOOL.@)
6836 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6838 FIXME("%s\n", debugstr_w(pName));
6842 /******************************************************************************
6843 * AddPrinterDriverExW (WINSPOOL.@)
6845 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6848 * pName [I] Servername or NULL (local Computer)
6849 * level [I] Level for the supplied DRIVER_INFO_*W struct
6850 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6851 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6858 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6860 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6862 if ((backend == NULL) && !load_backend()) return FALSE;
6864 if (level < 2 || level == 5 || level == 7 || level > 8) {
6865 SetLastError(ERROR_INVALID_LEVEL);
6870 SetLastError(ERROR_INVALID_PARAMETER);
6874 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6877 /******************************************************************************
6878 * AddPrinterDriverExA (WINSPOOL.@)
6880 * See AddPrinterDriverExW.
6883 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6885 DRIVER_INFO_8A *diA;
6887 LPWSTR nameW = NULL;
6892 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6894 diA = (DRIVER_INFO_8A *) pDriverInfo;
6895 ZeroMemory(&diW, sizeof(diW));
6897 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6898 SetLastError(ERROR_INVALID_LEVEL);
6903 SetLastError(ERROR_INVALID_PARAMETER);
6907 /* convert servername to unicode */
6909 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6910 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6911 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6915 diW.cVersion = diA->cVersion;
6918 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6919 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6920 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6923 if (diA->pEnvironment) {
6924 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6925 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6926 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6929 if (diA->pDriverPath) {
6930 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6931 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6932 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6935 if (diA->pDataFile) {
6936 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6937 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6938 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6941 if (diA->pConfigFile) {
6942 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6943 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6944 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6947 if ((Level > 2) && diA->pDependentFiles) {
6948 lenA = multi_sz_lenA(diA->pDependentFiles);
6949 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6950 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6951 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6954 if ((Level > 2) && diA->pMonitorName) {
6955 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6956 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6957 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6960 if ((Level > 3) && diA->pDefaultDataType) {
6961 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6962 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6963 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6966 if ((Level > 3) && diA->pszzPreviousNames) {
6967 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6968 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6969 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6970 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6973 if ((Level > 5) && diA->pszMfgName) {
6974 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6975 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6976 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6979 if ((Level > 5) && diA->pszOEMUrl) {
6980 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6981 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6982 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6985 if ((Level > 5) && diA->pszHardwareID) {
6986 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6987 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6988 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6991 if ((Level > 5) && diA->pszProvider) {
6992 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6993 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6994 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6998 FIXME("level %u is incomplete\n", Level);
7001 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
7002 TRACE("got %u with %u\n", res, GetLastError());
7003 HeapFree(GetProcessHeap(), 0, nameW);
7004 HeapFree(GetProcessHeap(), 0, diW.pName);
7005 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
7006 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
7007 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
7008 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
7009 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
7010 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
7011 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
7012 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
7013 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
7014 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
7015 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
7016 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
7018 TRACE("=> %u with %u\n", res, GetLastError());
7022 /******************************************************************************
7023 * ConfigurePortA (WINSPOOL.@)
7025 * See ConfigurePortW.
7028 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7030 LPWSTR nameW = NULL;
7031 LPWSTR portW = NULL;
7035 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7037 /* convert servername to unicode */
7039 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7040 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7041 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7044 /* convert portname to unicode */
7046 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7047 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7048 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7051 res = ConfigurePortW(nameW, hWnd, portW);
7052 HeapFree(GetProcessHeap(), 0, nameW);
7053 HeapFree(GetProcessHeap(), 0, portW);
7057 /******************************************************************************
7058 * ConfigurePortW (WINSPOOL.@)
7060 * Display the Configuration-Dialog for a specific Port
7063 * pName [I] Servername or NULL (local Computer)
7064 * hWnd [I] Handle to parent Window for the Dialog-Box
7065 * pPortName [I] Name of the Port, that should be configured
7072 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7075 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7077 if ((backend == NULL) && !load_backend()) return FALSE;
7080 SetLastError(RPC_X_NULL_REF_POINTER);
7084 return backend->fpConfigurePort(pName, hWnd, pPortName);
7087 /******************************************************************************
7088 * ConnectToPrinterDlg (WINSPOOL.@)
7090 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7092 FIXME("%p %x\n", hWnd, Flags);
7096 /******************************************************************************
7097 * DeletePrinterConnectionA (WINSPOOL.@)
7099 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7101 FIXME("%s\n", debugstr_a(pName));
7105 /******************************************************************************
7106 * DeletePrinterConnectionW (WINSPOOL.@)
7108 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7110 FIXME("%s\n", debugstr_w(pName));
7114 /******************************************************************************
7115 * DeletePrinterDriverExW (WINSPOOL.@)
7117 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7118 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7123 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7124 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7126 if(pName && pName[0])
7128 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7129 SetLastError(ERROR_INVALID_PARAMETER);
7135 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7136 SetLastError(ERROR_INVALID_PARAMETER);
7140 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7144 ERR("Can't open drivers key\n");
7148 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7151 RegCloseKey(hkey_drivers);
7156 /******************************************************************************
7157 * DeletePrinterDriverExA (WINSPOOL.@)
7159 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7160 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7162 UNICODE_STRING NameW, EnvW, DriverW;
7165 asciitounicode(&NameW, pName);
7166 asciitounicode(&EnvW, pEnvironment);
7167 asciitounicode(&DriverW, pDriverName);
7169 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7171 RtlFreeUnicodeString(&DriverW);
7172 RtlFreeUnicodeString(&EnvW);
7173 RtlFreeUnicodeString(&NameW);
7178 /******************************************************************************
7179 * DeletePrinterDataExW (WINSPOOL.@)
7181 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7184 FIXME("%p %s %s\n", hPrinter,
7185 debugstr_w(pKeyName), debugstr_w(pValueName));
7186 return ERROR_INVALID_PARAMETER;
7189 /******************************************************************************
7190 * DeletePrinterDataExA (WINSPOOL.@)
7192 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7195 FIXME("%p %s %s\n", hPrinter,
7196 debugstr_a(pKeyName), debugstr_a(pValueName));
7197 return ERROR_INVALID_PARAMETER;
7200 /******************************************************************************
7201 * DeletePrintProcessorA (WINSPOOL.@)
7203 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7205 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7206 debugstr_a(pPrintProcessorName));
7210 /******************************************************************************
7211 * DeletePrintProcessorW (WINSPOOL.@)
7213 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7215 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7216 debugstr_w(pPrintProcessorName));
7220 /******************************************************************************
7221 * DeletePrintProvidorA (WINSPOOL.@)
7223 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7225 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7226 debugstr_a(pPrintProviderName));
7230 /******************************************************************************
7231 * DeletePrintProvidorW (WINSPOOL.@)
7233 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7235 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7236 debugstr_w(pPrintProviderName));
7240 /******************************************************************************
7241 * EnumFormsA (WINSPOOL.@)
7243 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7244 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7246 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7247 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7251 /******************************************************************************
7252 * EnumFormsW (WINSPOOL.@)
7254 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7255 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7257 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7258 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7262 /*****************************************************************************
7263 * EnumMonitorsA [WINSPOOL.@]
7265 * See EnumMonitorsW.
7268 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7269 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7272 LPBYTE bufferW = NULL;
7273 LPWSTR nameW = NULL;
7275 DWORD numentries = 0;
7278 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7279 cbBuf, pcbNeeded, pcReturned);
7281 /* convert servername to unicode */
7283 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7284 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7285 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7287 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7288 needed = cbBuf * sizeof(WCHAR);
7289 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7290 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7292 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7293 if (pcbNeeded) needed = *pcbNeeded;
7294 /* HeapReAlloc return NULL, when bufferW was NULL */
7295 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7296 HeapAlloc(GetProcessHeap(), 0, needed);
7298 /* Try again with the large Buffer */
7299 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7301 numentries = pcReturned ? *pcReturned : 0;
7304 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7305 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7308 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7309 DWORD entrysize = 0;
7312 LPMONITOR_INFO_2W mi2w;
7313 LPMONITOR_INFO_2A mi2a;
7315 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7316 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7318 /* First pass: calculate the size for all Entries */
7319 mi2w = (LPMONITOR_INFO_2W) bufferW;
7320 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7322 while (index < numentries) {
7324 needed += entrysize; /* MONITOR_INFO_?A */
7325 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7327 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7328 NULL, 0, NULL, NULL);
7330 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7331 NULL, 0, NULL, NULL);
7332 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7333 NULL, 0, NULL, NULL);
7335 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7336 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7337 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7340 /* check for errors and quit on failure */
7341 if (cbBuf < needed) {
7342 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7346 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7347 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7348 cbBuf -= len ; /* free Bytes in the user-Buffer */
7349 mi2w = (LPMONITOR_INFO_2W) bufferW;
7350 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7352 /* Second Pass: Fill the User Buffer (if we have one) */
7353 while ((index < numentries) && pMonitors) {
7355 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7357 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7358 ptr, cbBuf , NULL, NULL);
7362 mi2a->pEnvironment = ptr;
7363 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7364 ptr, cbBuf, NULL, NULL);
7368 mi2a->pDLLName = ptr;
7369 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7370 ptr, cbBuf, NULL, NULL);
7374 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7375 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7376 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7380 if (pcbNeeded) *pcbNeeded = needed;
7381 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7383 HeapFree(GetProcessHeap(), 0, nameW);
7384 HeapFree(GetProcessHeap(), 0, bufferW);
7386 TRACE("returning %d with %d (%d byte for %d entries)\n",
7387 (res), GetLastError(), needed, numentries);
7393 /*****************************************************************************
7394 * EnumMonitorsW [WINSPOOL.@]
7396 * Enumerate available Port-Monitors
7399 * pName [I] Servername or NULL (local Computer)
7400 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7401 * pMonitors [O] PTR to Buffer that receives the Result
7402 * cbBuf [I] Size of Buffer at pMonitors
7403 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7404 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7408 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7411 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7412 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7415 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7416 cbBuf, pcbNeeded, pcReturned);
7418 if ((backend == NULL) && !load_backend()) return FALSE;
7420 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7421 SetLastError(RPC_X_NULL_REF_POINTER);
7425 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7428 /******************************************************************************
7429 * SpoolerInit (WINSPOOL.@)
7431 * Initialize the Spooler
7438 * The function fails on windows, when the spooler service is not running
7441 BOOL WINAPI SpoolerInit(void)
7444 if ((backend == NULL) && !load_backend()) return FALSE;
7448 /******************************************************************************
7449 * XcvDataW (WINSPOOL.@)
7451 * Execute commands in the Printmonitor DLL
7454 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7455 * pszDataName [i] Name of the command to execute
7456 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7457 * cbInputData [i] Size in Bytes of Buffer at pInputData
7458 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7459 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7460 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7461 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7468 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7469 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7471 * Minimal List of commands, that a Printmonitor DLL should support:
7473 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7474 *| "AddPort" : Add a Port
7475 *| "DeletePort": Delete a Port
7477 * Many Printmonitors support additional commands. Examples for localspl.dll:
7478 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7479 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7482 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7483 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7484 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7486 opened_printer_t *printer;
7488 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7489 pInputData, cbInputData, pOutputData,
7490 cbOutputData, pcbOutputNeeded, pdwStatus);
7492 if ((backend == NULL) && !load_backend()) return FALSE;
7494 printer = get_opened_printer(hXcv);
7495 if (!printer || (!printer->backend_printer)) {
7496 SetLastError(ERROR_INVALID_HANDLE);
7500 if (!pcbOutputNeeded) {
7501 SetLastError(ERROR_INVALID_PARAMETER);
7505 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7506 SetLastError(RPC_X_NULL_REF_POINTER);
7510 *pcbOutputNeeded = 0;
7512 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7513 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7517 /*****************************************************************************
7518 * EnumPrinterDataA [WINSPOOL.@]
7521 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7522 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7523 DWORD cbData, LPDWORD pcbData )
7525 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7526 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7527 return ERROR_NO_MORE_ITEMS;
7530 /*****************************************************************************
7531 * EnumPrinterDataW [WINSPOOL.@]
7534 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7535 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7536 DWORD cbData, LPDWORD pcbData )
7538 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7539 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7540 return ERROR_NO_MORE_ITEMS;
7543 /*****************************************************************************
7544 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7547 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7548 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7549 LPDWORD pcbNeeded, LPDWORD pcReturned)
7551 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7552 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7553 pcbNeeded, pcReturned);
7557 /*****************************************************************************
7558 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7561 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7562 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7563 LPDWORD pcbNeeded, LPDWORD pcReturned)
7565 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7566 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7567 pcbNeeded, pcReturned);
7571 /*****************************************************************************
7572 * EnumPrintProcessorsA [WINSPOOL.@]
7574 * See EnumPrintProcessorsW.
7577 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7578 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7581 LPBYTE bufferW = NULL;
7582 LPWSTR nameW = NULL;
7585 DWORD numentries = 0;
7588 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7589 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7591 /* convert names to unicode */
7593 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7594 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7595 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7598 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7599 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7600 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7603 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7604 needed = cbBuf * sizeof(WCHAR);
7605 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7606 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7608 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7609 if (pcbNeeded) needed = *pcbNeeded;
7610 /* HeapReAlloc return NULL, when bufferW was NULL */
7611 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7612 HeapAlloc(GetProcessHeap(), 0, needed);
7614 /* Try again with the large Buffer */
7615 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7617 numentries = pcReturned ? *pcReturned : 0;
7621 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7624 PPRINTPROCESSOR_INFO_1W ppiw;
7625 PPRINTPROCESSOR_INFO_1A ppia;
7627 /* First pass: calculate the size for all Entries */
7628 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7629 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7631 while (index < numentries) {
7633 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7634 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7636 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7637 NULL, 0, NULL, NULL);
7639 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7640 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7643 /* check for errors and quit on failure */
7644 if (cbBuf < needed) {
7645 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7650 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7651 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7652 cbBuf -= len ; /* free Bytes in the user-Buffer */
7653 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7654 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7656 /* Second Pass: Fill the User Buffer (if we have one) */
7657 while ((index < numentries) && pPPInfo) {
7659 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7661 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7662 ptr, cbBuf , NULL, NULL);
7666 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7667 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7672 if (pcbNeeded) *pcbNeeded = needed;
7673 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7675 HeapFree(GetProcessHeap(), 0, nameW);
7676 HeapFree(GetProcessHeap(), 0, envW);
7677 HeapFree(GetProcessHeap(), 0, bufferW);
7679 TRACE("returning %d with %d (%d byte for %d entries)\n",
7680 (res), GetLastError(), needed, numentries);
7685 /*****************************************************************************
7686 * EnumPrintProcessorsW [WINSPOOL.@]
7688 * Enumerate available Print Processors
7691 * pName [I] Servername or NULL (local Computer)
7692 * pEnvironment [I] Printing-Environment or NULL (Default)
7693 * Level [I] Structure-Level (Only 1 is allowed)
7694 * pPPInfo [O] PTR to Buffer that receives the Result
7695 * cbBuf [I] Size of Buffer at pPPInfo
7696 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7697 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7701 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7704 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7705 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7708 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7709 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7711 if ((backend == NULL) && !load_backend()) return FALSE;
7713 if (!pcbNeeded || !pcReturned) {
7714 SetLastError(RPC_X_NULL_REF_POINTER);
7718 if (!pPPInfo && (cbBuf > 0)) {
7719 SetLastError(ERROR_INVALID_USER_BUFFER);
7723 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7724 cbBuf, pcbNeeded, pcReturned);
7727 /*****************************************************************************
7728 * ExtDeviceMode [WINSPOOL.@]
7731 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7732 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7735 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7736 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7737 debugstr_a(pProfile), fMode);
7741 /*****************************************************************************
7742 * FindClosePrinterChangeNotification [WINSPOOL.@]
7745 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7747 FIXME("Stub: %p\n", hChange);
7751 /*****************************************************************************
7752 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7755 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7756 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7758 FIXME("Stub: %p %x %x %p\n",
7759 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7760 return INVALID_HANDLE_VALUE;
7763 /*****************************************************************************
7764 * FindNextPrinterChangeNotification [WINSPOOL.@]
7767 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7768 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7770 FIXME("Stub: %p %p %p %p\n",
7771 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7775 /*****************************************************************************
7776 * FreePrinterNotifyInfo [WINSPOOL.@]
7779 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7781 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7785 /*****************************************************************************
7788 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7789 * ansi depending on the unicode parameter.
7791 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7801 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7804 memcpy(ptr, str, *size);
7811 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7814 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7821 /*****************************************************************************
7824 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7825 LPDWORD pcbNeeded, BOOL unicode)
7827 DWORD size, left = cbBuf;
7828 BOOL space = (cbBuf > 0);
7835 ji1->JobId = job->job_id;
7838 string_to_buf(job->document_title, ptr, left, &size, unicode);
7839 if(space && size <= left)
7841 ji1->pDocument = (LPWSTR)ptr;
7849 if (job->printer_name)
7851 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7852 if(space && size <= left)
7854 ji1->pPrinterName = (LPWSTR)ptr;
7866 /*****************************************************************************
7869 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7870 LPDWORD pcbNeeded, BOOL unicode)
7872 DWORD size, left = cbBuf;
7874 BOOL space = (cbBuf > 0);
7876 LPDEVMODEA dmA = NULL;
7883 ji2->JobId = job->job_id;
7886 string_to_buf(job->document_title, ptr, left, &size, unicode);
7887 if(space && size <= left)
7889 ji2->pDocument = (LPWSTR)ptr;
7897 if (job->printer_name)
7899 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7900 if(space && size <= left)
7902 ji2->pPrinterName = (LPWSTR)ptr;
7915 dmA = DEVMODEdupWtoA(job->devmode);
7916 devmode = (LPDEVMODEW) dmA;
7917 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7921 devmode = job->devmode;
7922 size = devmode->dmSize + devmode->dmDriverExtra;
7926 FIXME("Can't convert DEVMODE W to A\n");
7929 /* align DEVMODE to a DWORD boundary */
7930 shift = (4 - (*pcbNeeded & 3)) & 3;
7936 memcpy(ptr, devmode, size-shift);
7937 ji2->pDevMode = (LPDEVMODEW)ptr;
7938 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7951 /*****************************************************************************
7954 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7955 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7958 DWORD needed = 0, size;
7962 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7964 EnterCriticalSection(&printer_handles_cs);
7965 job = get_job(hPrinter, JobId);
7972 size = sizeof(JOB_INFO_1W);
7977 memset(pJob, 0, size);
7981 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7986 size = sizeof(JOB_INFO_2W);
7991 memset(pJob, 0, size);
7995 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
8000 size = sizeof(JOB_INFO_3);
8004 memset(pJob, 0, size);
8013 SetLastError(ERROR_INVALID_LEVEL);
8017 *pcbNeeded = needed;
8019 LeaveCriticalSection(&printer_handles_cs);
8023 /*****************************************************************************
8024 * GetJobA [WINSPOOL.@]
8027 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8028 DWORD cbBuf, LPDWORD pcbNeeded)
8030 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8033 /*****************************************************************************
8034 * GetJobW [WINSPOOL.@]
8037 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8038 DWORD cbBuf, LPDWORD pcbNeeded)
8040 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8043 /*****************************************************************************
8046 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8049 char *unixname, *cmdA;
8051 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8057 if(!(unixname = wine_get_unix_file_name(filename)))
8060 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8061 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8062 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8064 TRACE("printing with: %s\n", cmdA);
8066 if((file_fd = open(unixname, O_RDONLY)) == -1)
8071 ERR("pipe() failed!\n");
8075 if ((pid = fork()) == 0)
8081 /* reset signals that we previously set to SIG_IGN */
8082 signal(SIGPIPE, SIG_DFL);
8084 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8089 ERR("fork() failed!\n");
8093 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8094 write(fds[1], buf, no_read);
8101 wret = waitpid(pid, &status, 0);
8102 } while (wret < 0 && errno == EINTR);
8105 ERR("waitpid() failed!\n");
8108 if (!WIFEXITED(status) || WEXITSTATUS(status))
8110 ERR("child process failed! %d\n", status);
8117 if(file_fd != -1) close(file_fd);
8118 if(fds[0] != -1) close(fds[0]);
8119 if(fds[1] != -1) close(fds[1]);
8121 HeapFree(GetProcessHeap(), 0, cmdA);
8122 HeapFree(GetProcessHeap(), 0, unixname);
8129 /*****************************************************************************
8132 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8135 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8138 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8139 sprintfW(cmd, fmtW, printer_name);
8141 r = schedule_pipe(cmd, filename);
8143 HeapFree(GetProcessHeap(), 0, cmd);
8147 #ifdef SONAME_LIBCUPS
8148 /*****************************************************************************
8149 * get_cups_jobs_ticket_options
8151 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8152 * The CUPS scheduler only looks for these in Print-File requests, and since
8153 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8156 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8158 FILE *fp = fopen( file, "r" );
8159 char buf[257]; /* DSC max of 256 + '\0' */
8160 const char *ps_adobe = "%!PS-Adobe-";
8161 const char *cups_job = "%cupsJobTicket:";
8163 if (!fp) return num_options;
8164 if (!fgets( buf, sizeof(buf), fp )) goto end;
8165 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8166 while (fgets( buf, sizeof(buf), fp ))
8168 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8169 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8178 /*****************************************************************************
8181 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8183 #ifdef SONAME_LIBCUPS
8186 char *unixname, *queue, *unix_doc_title;
8189 int num_options = 0, i;
8190 cups_option_t *options = NULL;
8192 if(!(unixname = wine_get_unix_file_name(filename)))
8195 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8196 queue = HeapAlloc(GetProcessHeap(), 0, len);
8197 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8199 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8200 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8201 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8203 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8205 TRACE( "printing via cups with options:\n" );
8206 for (i = 0; i < num_options; i++)
8207 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8209 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8211 pcupsFreeOptions( num_options, options );
8213 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8214 HeapFree(GetProcessHeap(), 0, queue);
8215 HeapFree(GetProcessHeap(), 0, unixname);
8221 return schedule_lpr(printer_name, filename);
8225 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8232 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8236 if(HIWORD(wparam) == BN_CLICKED)
8238 if(LOWORD(wparam) == IDOK)
8241 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8244 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8245 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8247 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8249 WCHAR caption[200], message[200];
8252 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8253 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8254 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8255 if(mb_ret == IDCANCEL)
8257 HeapFree(GetProcessHeap(), 0, filename);
8261 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8262 if(hf == INVALID_HANDLE_VALUE)
8264 WCHAR caption[200], message[200];
8266 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8267 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8268 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8269 HeapFree(GetProcessHeap(), 0, filename);
8273 DeleteFileW(filename);
8274 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8276 EndDialog(hwnd, IDOK);
8279 if(LOWORD(wparam) == IDCANCEL)
8281 EndDialog(hwnd, IDCANCEL);
8290 /*****************************************************************************
8293 static BOOL get_filename(LPWSTR *filename)
8295 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8296 file_dlg_proc, (LPARAM)filename) == IDOK;
8299 /*****************************************************************************
8302 static BOOL schedule_file(LPCWSTR filename)
8304 LPWSTR output = NULL;
8306 if(get_filename(&output))
8309 TRACE("copy to %s\n", debugstr_w(output));
8310 r = CopyFileW(filename, output, FALSE);
8311 HeapFree(GetProcessHeap(), 0, output);
8317 /*****************************************************************************
8320 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8322 int in_fd, out_fd, no_read;
8325 char *unixname, *outputA;
8328 if(!(unixname = wine_get_unix_file_name(filename)))
8331 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8332 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8333 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8335 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8336 in_fd = open(unixname, O_RDONLY);
8337 if(out_fd == -1 || in_fd == -1)
8340 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8341 write(out_fd, buf, no_read);
8345 if(in_fd != -1) close(in_fd);
8346 if(out_fd != -1) close(out_fd);
8347 HeapFree(GetProcessHeap(), 0, outputA);
8348 HeapFree(GetProcessHeap(), 0, unixname);
8352 /*****************************************************************************
8353 * ScheduleJob [WINSPOOL.@]
8356 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8358 opened_printer_t *printer;
8360 struct list *cursor, *cursor2;
8362 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8363 EnterCriticalSection(&printer_handles_cs);
8364 printer = get_opened_printer(hPrinter);
8368 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8370 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8373 if(job->job_id != dwJobID) continue;
8375 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8376 if(hf != INVALID_HANDLE_VALUE)
8378 PRINTER_INFO_5W *pi5 = NULL;
8379 LPWSTR portname = job->portname;
8383 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8384 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8388 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8389 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8390 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8391 portname = pi5->pPortName;
8393 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8394 debugstr_w(portname));
8398 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8399 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8401 DWORD type, count = sizeof(output);
8402 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8405 if(output[0] == '|')
8407 ret = schedule_pipe(output + 1, job->filename);
8411 ret = schedule_unixfile(output, job->filename);
8413 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8415 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8417 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8419 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8421 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8423 ret = schedule_file(job->filename);
8427 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8429 HeapFree(GetProcessHeap(), 0, pi5);
8431 DeleteFileW(job->filename);
8433 list_remove(cursor);
8434 HeapFree(GetProcessHeap(), 0, job->document_title);
8435 HeapFree(GetProcessHeap(), 0, job->printer_name);
8436 HeapFree(GetProcessHeap(), 0, job->portname);
8437 HeapFree(GetProcessHeap(), 0, job->filename);
8438 HeapFree(GetProcessHeap(), 0, job->devmode);
8439 HeapFree(GetProcessHeap(), 0, job);
8443 LeaveCriticalSection(&printer_handles_cs);
8447 /*****************************************************************************
8448 * StartDocDlgA [WINSPOOL.@]
8450 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8452 UNICODE_STRING usBuffer;
8455 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8458 docW.cbSize = sizeof(docW);
8459 if (doc->lpszDocName)
8461 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8462 if (!(docW.lpszDocName = docnameW)) return NULL;
8464 if (doc->lpszOutput)
8466 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8467 if (!(docW.lpszOutput = outputW)) return NULL;
8469 if (doc->lpszDatatype)
8471 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8472 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8474 docW.fwType = doc->fwType;
8476 retW = StartDocDlgW(hPrinter, &docW);
8480 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8481 ret = HeapAlloc(GetProcessHeap(), 0, len);
8482 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8483 HeapFree(GetProcessHeap(), 0, retW);
8486 HeapFree(GetProcessHeap(), 0, datatypeW);
8487 HeapFree(GetProcessHeap(), 0, outputW);
8488 HeapFree(GetProcessHeap(), 0, docnameW);
8493 /*****************************************************************************
8494 * StartDocDlgW [WINSPOOL.@]
8496 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8497 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8498 * port is "FILE:". Also returns the full path if passed a relative path.
8500 * The caller should free the returned string from the process heap.
8502 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8507 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8509 PRINTER_INFO_5W *pi5;
8510 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8511 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8513 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8514 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8515 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8517 HeapFree(GetProcessHeap(), 0, pi5);
8520 HeapFree(GetProcessHeap(), 0, pi5);
8523 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8527 if (get_filename(&name))
8529 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8531 HeapFree(GetProcessHeap(), 0, name);
8534 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8535 GetFullPathNameW(name, len, ret, NULL);
8536 HeapFree(GetProcessHeap(), 0, name);
8541 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8544 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8545 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8547 attr = GetFileAttributesW(ret);
8548 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8550 HeapFree(GetProcessHeap(), 0, ret);