4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
37 #ifdef HAVE_SYS_WAIT_H
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
48 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
49 #define GetCurrentProcess GetCurrentProcess_Mac
50 #define GetCurrentThread GetCurrentThread_Mac
51 #define LoadResource LoadResource_Mac
52 #define AnimatePalette AnimatePalette_Mac
53 #define EqualRgn EqualRgn_Mac
54 #define FillRgn FillRgn_Mac
55 #define FrameRgn FrameRgn_Mac
56 #define GetPixel GetPixel_Mac
57 #define InvertRgn InvertRgn_Mac
58 #define LineTo LineTo_Mac
59 #define OffsetRgn OffsetRgn_Mac
60 #define PaintRgn PaintRgn_Mac
61 #define Polygon Polygon_Mac
62 #define ResizePalette ResizePalette_Mac
63 #define SetRectRgn SetRectRgn_Mac
64 #define EqualRect EqualRect_Mac
65 #define FillRect FillRect_Mac
66 #define FrameRect FrameRect_Mac
67 #define GetCursor GetCursor_Mac
68 #define InvertRect InvertRect_Mac
69 #define OffsetRect OffsetRect_Mac
70 #define PtInRect PtInRect_Mac
71 #define SetCursor SetCursor_Mac
72 #define SetRect SetRect_Mac
73 #define ShowCursor ShowCursor_Mac
74 #define UnionRect UnionRect_Mac
75 #include <ApplicationServices/ApplicationServices.h>
76 #undef GetCurrentProcess
77 #undef GetCurrentThread
105 #define NONAMELESSUNION
106 #define NONAMELESSSTRUCT
107 #include "wine/library.h"
111 #include "winerror.h"
114 #include "winspool.h"
115 #include "winternl.h"
116 #include "wine/windef16.h"
117 #include "wine/unicode.h"
118 #include "wine/debug.h"
119 #include "wine/list.h"
122 #include "ddk/winsplp.h"
125 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
127 /* ############################### */
129 static CRITICAL_SECTION printer_handles_cs;
130 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
132 0, 0, &printer_handles_cs,
133 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
134 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
136 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
138 /* ############################### */
153 HANDLE backend_printer;
164 WCHAR *document_title;
174 LPCWSTR versionregpath;
175 LPCWSTR versionsubdir;
178 /* ############################### */
180 static opened_printer_t **printer_handles;
181 static UINT nb_printer_handles;
182 static LONG next_job_id = 1;
184 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
185 WORD fwCapability, LPSTR lpszOutput,
187 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
188 LPSTR lpszDevice, LPSTR lpszPort,
189 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
192 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
193 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
194 'c','o','n','t','r','o','l','\\',
195 'P','r','i','n','t','\\',
196 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
197 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
199 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
200 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
201 'C','o','n','t','r','o','l','\\',
202 'P','r','i','n','t','\\',
203 'P','r','i','n','t','e','r','s',0};
205 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
207 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
208 'M','i','c','r','o','s','o','f','t','\\',
209 'W','i','n','d','o','w','s',' ','N','T','\\',
210 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
211 'W','i','n','d','o','w','s',0};
213 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
214 'M','i','c','r','o','s','o','f','t','\\',
215 'W','i','n','d','o','w','s',' ','N','T','\\',
216 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
217 'D','e','v','i','c','e','s',0};
219 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
220 'M','i','c','r','o','s','o','f','t','\\',
221 'W','i','n','d','o','w','s',' ','N','T','\\',
222 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
223 'P','o','r','t','s',0};
225 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
226 'M','i','c','r','o','s','o','f','t','\\',
227 'W','i','n','d','o','w','s',' ','N','T','\\',
228 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
229 'P','r','i','n','t','e','r','P','o','r','t','s',0};
231 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
232 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
233 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
234 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
235 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
236 static const WCHAR subdir_x64W[] = {'x','6','4',0};
237 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
238 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
239 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
240 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
241 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
243 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
245 static const WCHAR AttributesW[] = {'A','t','t','r','i','b','u','t','e','s',0};
246 static const WCHAR backslashW[] = {'\\',0};
247 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
248 'i','o','n',' ','F','i','l','e',0};
249 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
250 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
251 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
252 static const WCHAR Default_PriorityW[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
253 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
254 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
255 static const WCHAR dnsTimeoutW[] = {'d','n','s','T','i','m','e','o','u','t',0};
256 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
257 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
258 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
259 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
260 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
261 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
262 static const WCHAR NameW[] = {'N','a','m','e',0};
263 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
264 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
265 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
266 static const WCHAR PortW[] = {'P','o','r','t',0};
267 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
268 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
269 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
270 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
271 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
272 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
273 static const WCHAR PriorityW[] = {'P','r','i','o','r','i','t','y',0};
274 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
275 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
276 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
277 static const WCHAR StartTimeW[] = {'S','t','a','r','t','T','i','m','e',0};
278 static const WCHAR StatusW[] = {'S','t','a','t','u','s',0};
279 static const WCHAR txTimeoutW[] = {'t','x','T','i','m','e','o','u','t',0};
280 static const WCHAR UntilTimeW[] = {'U','n','t','i','l','T','i','m','e',0};
281 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
282 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
283 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
284 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
285 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
286 static WCHAR rawW[] = {'R','A','W',0};
287 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
288 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
289 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
290 static const WCHAR commaW[] = {',',0};
291 static WCHAR emptyStringW[] = {0};
293 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
295 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
296 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
297 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
299 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
300 'D','o','c','u','m','e','n','t',0};
302 static const WCHAR PPD_Overrides[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
303 static const WCHAR DefaultPageSize[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
305 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
306 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
307 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
308 0, sizeof(DRIVER_INFO_8W)};
311 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
312 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
313 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
314 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
315 sizeof(PRINTER_INFO_9W)};
317 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
318 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
319 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
321 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
323 /******************************************************************
324 * validate the user-supplied printing-environment [internal]
327 * env [I] PTR to Environment-String or NULL
331 * Success: PTR to printenv_t
334 * An empty string is handled the same way as NULL.
335 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
339 static const printenv_t * validate_envW(LPCWSTR env)
341 const printenv_t *result = NULL;
344 TRACE("testing %s\n", debugstr_w(env));
347 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
349 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
351 result = all_printenv[i];
356 if (result == NULL) {
357 FIXME("unsupported Environment: %s\n", debugstr_w(env));
358 SetLastError(ERROR_INVALID_ENVIRONMENT);
360 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
364 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
366 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
372 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
373 if passed a NULL string. This returns NULLs to the result.
375 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
379 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
380 return usBufferPtr->Buffer;
382 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
386 static LPWSTR strdupW(LPCWSTR p)
392 len = (strlenW(p) + 1) * sizeof(WCHAR);
393 ret = HeapAlloc(GetProcessHeap(), 0, len);
398 static LPSTR strdupWtoA( LPCWSTR str )
403 if (!str) return NULL;
404 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
405 ret = HeapAlloc( GetProcessHeap(), 0, len );
406 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
410 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
414 if (!dm) return NULL;
415 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
416 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
420 /***********************************************************
422 * Creates an ansi copy of supplied devmode
424 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
429 if (!dmW) return NULL;
430 size = dmW->dmSize - CCHDEVICENAME -
431 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
433 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
434 if (!dmA) return NULL;
436 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
437 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
439 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
441 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
442 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
446 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
447 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
448 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
449 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
451 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
455 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
460 /******************************************************************
461 * verify, that the filename is a local file
464 static inline BOOL is_local_file(LPWSTR name)
466 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
469 /* ################################ */
471 static int multi_sz_lenA(const char *str)
473 const char *ptr = str;
477 ptr += lstrlenA(ptr) + 1;
480 return ptr - str + 1;
483 /*****************************************************************************
486 * Return DWORD associated with name from hkey.
488 static DWORD get_dword_from_reg( HKEY hkey, const WCHAR *name )
490 DWORD sz = sizeof(DWORD), type, value = 0;
493 ret = RegQueryValueExW( hkey, name, 0, &type, (LPBYTE)&value, &sz );
495 if (ret != ERROR_SUCCESS)
497 WARN( "Got ret = %d on name %s\n", ret, debugstr_w(name) );
500 if (type != REG_DWORD)
502 ERR( "Got type %d\n", type );
508 static inline DWORD set_reg_DWORD( HKEY hkey, const WCHAR *keyname, const DWORD value )
510 return RegSetValueExW( hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value) );
513 /******************************************************************
515 * Get the pointer to the opened printer referred by the handle
517 static opened_printer_t *get_opened_printer(HANDLE hprn)
519 UINT_PTR idx = (UINT_PTR)hprn;
520 opened_printer_t *ret = NULL;
522 EnterCriticalSection(&printer_handles_cs);
524 if ((idx > 0) && (idx <= nb_printer_handles)) {
525 ret = printer_handles[idx - 1];
527 LeaveCriticalSection(&printer_handles_cs);
531 /******************************************************************
532 * get_opened_printer_name
533 * Get the pointer to the opened printer name referred by the handle
535 static LPCWSTR get_opened_printer_name(HANDLE hprn)
537 opened_printer_t *printer = get_opened_printer(hprn);
538 if(!printer) return NULL;
539 return printer->name;
542 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
548 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
551 err = RegOpenKeyW( printers, name, key );
552 if (err) err = ERROR_INVALID_PRINTER_NAME;
553 RegCloseKey( printers );
557 /******************************************************************
558 * WINSPOOL_GetOpenedPrinterRegKey
561 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
563 LPCWSTR name = get_opened_printer_name(hPrinter);
565 if(!name) return ERROR_INVALID_HANDLE;
566 return open_printer_reg_key( name, phkey );
570 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
573 /* If forcing, or no profile string entry for device yet, set the entry
575 * The always change entry if not WINEPS yet is discussable.
578 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
580 !strstr(qbuf,"WINEPS.DRV")
582 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
585 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
586 WriteProfileStringA("windows","device",buf);
587 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
588 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
591 HeapFree(GetProcessHeap(),0,buf);
595 static BOOL add_printer_driver(const WCHAR *name, WCHAR *ppd)
599 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
601 di3.pName = (WCHAR*)name;
602 di3.pEnvironment = envname_x86W;
603 di3.pDriverPath = driver_nt;
605 di3.pConfigFile = driver_nt;
606 di3.pDefaultDataType = rawW;
608 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
609 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
612 di3.pEnvironment = envname_win40W;
613 di3.pDriverPath = driver_9x;
614 di3.pConfigFile = driver_9x;
615 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
616 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
621 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
625 static inline char *expand_env_string( char *str, DWORD type )
627 if (type == REG_EXPAND_SZ)
630 DWORD needed = ExpandEnvironmentStringsA( str, NULL, 0 );
631 tmp = HeapAlloc( GetProcessHeap(), 0, needed );
634 ExpandEnvironmentStringsA( str, tmp, needed );
635 HeapFree( GetProcessHeap(), 0, str );
642 static char *get_fallback_ppd_name( const char *printer_name )
644 static const WCHAR ppds_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
645 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
649 const char *data_dir, *filename;
651 if (RegOpenKeyW( HKEY_CURRENT_USER, ppds_key, &hkey ) == ERROR_SUCCESS )
653 const char *value_name = NULL;
655 if (RegQueryValueExA( hkey, printer_name, 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
656 value_name = printer_name;
657 else if (RegQueryValueExA( hkey, "generic", 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
658 value_name = "generic";
662 ret = HeapAlloc( GetProcessHeap(), 0, needed );
663 if (!ret) return NULL;
664 RegQueryValueExA( hkey, value_name, 0, &type, (BYTE *)ret, &needed );
667 if (ret) return expand_env_string( ret, type );
670 if ((data_dir = wine_get_data_dir())) filename = "/generic.ppd";
671 else if ((data_dir = wine_get_build_dir())) filename = "/dlls/wineps.drv/generic.ppd";
674 ERR( "Error getting PPD file name for printer '%s'\n", debugstr_a(printer_name) );
677 ret = HeapAlloc( GetProcessHeap(), 0, strlen(data_dir) + strlen(filename) + 1 );
680 strcpy( ret, data_dir );
681 strcat( ret, filename );
687 static BOOL copy_file( const char *src, const char *dst )
689 int fds[2] = {-1, -1}, num;
693 fds[0] = open( src, O_RDONLY );
694 fds[1] = open( dst, O_CREAT | O_TRUNC | O_WRONLY, 0666 );
695 if (fds[0] == -1 || fds[1] == -1) goto fail;
697 while ((num = read( fds[0], buf, sizeof(buf) )) != 0)
699 if (num == -1) goto fail;
700 if (write( fds[1], buf, num ) != num) goto fail;
705 if (fds[1] != -1) close( fds[1] );
706 if (fds[0] != -1) close( fds[0] );
710 static BOOL get_fallback_ppd( const char *printer_name, const WCHAR *ppd )
712 char *src = get_fallback_ppd_name( printer_name );
713 char *dst = wine_get_unix_file_name( ppd );
716 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name), debugstr_w(ppd), debugstr_a(src) );
718 if (!src || !dst) goto fail;
720 if (symlink( src, dst ) == -1)
721 if (errno != ENOSYS || !copy_file( src, dst ))
726 HeapFree( GetProcessHeap(), 0, dst );
727 HeapFree( GetProcessHeap(), 0, src );
731 static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
733 static const WCHAR dot_ppd[] = {'.','p','p','d',0};
734 int len = (strlenW( dir ) + strlenW( file_name )) * sizeof(WCHAR) + sizeof(dot_ppd);
735 WCHAR *ppd = HeapAlloc( GetProcessHeap(), 0, len );
737 if (!ppd) return NULL;
739 strcatW( ppd, file_name );
740 strcatW( ppd, dot_ppd );
745 static WCHAR *get_ppd_dir( void )
747 static const WCHAR wine_ppds[] = {'w','i','n','e','_','p','p','d','s','\\',0};
749 WCHAR *dir, tmp_path[MAX_PATH];
752 len = GetTempPathW( sizeof(tmp_path) / sizeof(tmp_path[0]), tmp_path );
753 if (!len) return NULL;
754 dir = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
755 if (!dir) return NULL;
757 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
758 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
759 res = CreateDirectoryW( dir, NULL );
760 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
762 HeapFree( GetProcessHeap(), 0, dir );
765 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
769 static void unlink_ppd( const WCHAR *ppd )
771 char *unix_name = wine_get_unix_file_name( ppd );
773 HeapFree( GetProcessHeap(), 0, unix_name );
776 #ifdef SONAME_LIBCUPS
778 static void *cupshandle;
781 DO_FUNC(cupsFreeDests); \
782 DO_FUNC(cupsFreeOptions); \
783 DO_FUNC(cupsGetDests); \
784 DO_FUNC(cupsGetOption); \
785 DO_FUNC(cupsGetPPD); \
786 DO_FUNC(cupsParseOptions); \
787 DO_FUNC(cupsPrintFile)
788 #define CUPS_OPT_FUNCS \
791 #define DO_FUNC(f) static typeof(f) *p##f
794 static http_status_t (*pcupsGetPPD3)(http_t *,const char *, time_t *, char *, size_t);
796 static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name,
797 time_t *modtime, char *buffer,
802 if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
804 if (!pcupsGetPPD) return HTTP_NOT_FOUND;
806 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
809 ppd = pcupsGetPPD( name );
811 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
813 if (!ppd) return HTTP_NOT_FOUND;
815 if (rename( ppd, buffer ) == -1)
817 BOOL res = copy_file( ppd, buffer );
819 if (!res) return HTTP_NOT_FOUND;
824 static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
827 http_status_t http_status;
828 char *unix_name = wine_get_unix_file_name( ppd );
830 TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
832 if (!unix_name) return FALSE;
834 http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
835 unix_name, strlen( unix_name ) + 1 );
837 if (http_status != HTTP_OK) unlink( unix_name );
838 HeapFree( GetProcessHeap(), 0, unix_name );
840 if (http_status == HTTP_OK) return TRUE;
842 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
843 debugstr_a(printer_name), http_status );
844 return get_fallback_ppd( printer_name, ppd );
847 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
853 value = pcupsGetOption( name, num_options, options );
854 if (!value) return NULL;
856 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
857 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
858 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
863 static cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
865 WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
866 cups_ptype_t ret = 0;
870 ret = (cups_ptype_t)strtoulW( type, &end, 10 );
873 HeapFree( GetProcessHeap(), 0, type );
877 static BOOL CUPS_LoadPrinters(void)
880 BOOL hadprinter = FALSE, haddefault = FALSE;
883 WCHAR *port, *ppd_dir = NULL, *ppd;
884 HKEY hkeyPrinter, hkeyPrinters;
886 WCHAR nameW[MAX_PATH];
887 HANDLE added_printer;
888 cups_ptype_t printer_type;
890 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
892 TRACE("%s\n", loaderror);
895 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
897 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE
900 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 )
904 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
906 ERR("Can't create Printers key\n");
910 nrofdests = pcupsGetDests(&dests);
911 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
912 for (i=0;i<nrofdests;i++) {
913 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
914 printer_type = get_cups_printer_type( dests + i );
916 TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
918 if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
920 TRACE( "skipping scanner-only device\n" );
924 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
925 lstrcpyW(port, CUPS_Port);
926 lstrcatW(port, nameW);
928 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
929 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
930 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
932 TRACE("Printer already exists\n");
933 /* overwrite old LPR:* port */
934 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
935 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
936 /* flag that the PPD file should be checked for an update */
937 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
938 RegCloseKey(hkeyPrinter);
940 BOOL added_driver = FALSE;
942 if (!ppd_dir) ppd_dir = get_ppd_dir();
943 ppd = get_ppd_filename( ppd_dir, nameW );
944 if (get_cups_ppd( dests[i].name, ppd ))
946 added_driver = add_printer_driver( nameW, ppd );
949 HeapFree( GetProcessHeap(), 0, ppd );
952 HeapFree( GetProcessHeap(), 0, port );
956 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
957 pi2.pPrinterName = nameW;
958 pi2.pDatatype = rawW;
959 pi2.pPrintProcessor = WinPrintW;
960 pi2.pDriverName = nameW;
961 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
962 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
963 pi2.pPortName = port;
964 pi2.pParameters = emptyStringW;
965 pi2.pShareName = emptyStringW;
966 pi2.pSepFile = emptyStringW;
968 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
969 if (added_printer) ClosePrinter( added_printer );
970 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
971 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
973 HeapFree( GetProcessHeap(), 0, pi2.pComment );
974 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
976 HeapFree( GetProcessHeap(), 0, port );
979 if (dests[i].is_default) {
980 SetDefaultPrinterW(nameW);
987 RemoveDirectoryW( ppd_dir );
988 HeapFree( GetProcessHeap(), 0, ppd_dir );
991 if (hadprinter && !haddefault) {
992 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
993 SetDefaultPrinterW(nameW);
995 pcupsFreeDests(nrofdests, dests);
996 RegCloseKey(hkeyPrinters);
1002 static char *get_queue_name( HANDLE printer, BOOL *cups )
1004 WCHAR *port, *name = NULL;
1005 DWORD err, needed, type;
1011 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1012 if (err) return NULL;
1013 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1015 port = HeapAlloc( GetProcessHeap(), 0, needed );
1016 if (!port) goto end;
1017 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1019 if (!strncmpW( port, CUPS_Port, sizeof(CUPS_Port) / sizeof(WCHAR) -1 ))
1021 name = port + sizeof(CUPS_Port) / sizeof(WCHAR) - 1;
1024 else if (!strncmpW( port, LPR_Port, sizeof(LPR_Port) / sizeof(WCHAR) -1 ))
1025 name = port + sizeof(LPR_Port) / sizeof(WCHAR) - 1;
1028 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1029 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1030 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1032 HeapFree( GetProcessHeap(), 0, port );
1039 static void set_ppd_overrides( HANDLE printer )
1043 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1045 PMPrintSession session = NULL;
1046 PMPageFormat format = NULL;
1048 CFStringRef paper_name;
1051 status = PMCreateSession( &session );
1052 if (status) goto end;
1054 status = PMCreatePageFormat( &format );
1055 if (status) goto end;
1057 status = PMSessionDefaultPageFormat( session, format );
1058 if (status) goto end;
1060 status = PMGetPageFormatPaper( format, &paper );
1061 if (status) goto end;
1063 status = PMPaperGetPPDPaperName( paper, &paper_name );
1064 if (status) goto end;
1067 range.length = CFStringGetLength( paper_name );
1068 size = (range.length + 1) * sizeof(WCHAR);
1070 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1071 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1072 wstr[range.length] = 0;
1075 if (format) PMRelease( format );
1076 if (session) PMRelease( session );
1079 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1080 HeapFree( GetProcessHeap(), 0, wstr );
1083 static BOOL update_driver( HANDLE printer )
1086 const WCHAR *name = get_opened_printer_name( printer );
1087 WCHAR *ppd_dir, *ppd;
1090 if (!name) return FALSE;
1091 queue_name = get_queue_name( printer, &is_cups );
1092 if (!queue_name) return FALSE;
1094 ppd_dir = get_ppd_dir();
1095 ppd = get_ppd_filename( ppd_dir, name );
1097 #ifdef SONAME_LIBCUPS
1099 ret = get_cups_ppd( queue_name, ppd );
1102 ret = get_fallback_ppd( queue_name, ppd );
1106 TRACE( "updating driver %s\n", debugstr_w( name ) );
1107 ret = add_printer_driver( name, ppd );
1110 HeapFree( GetProcessHeap(), 0, ppd_dir );
1111 HeapFree( GetProcessHeap(), 0, ppd );
1112 HeapFree( GetProcessHeap(), 0, queue_name );
1114 set_ppd_overrides( printer );
1116 /* call into the driver to update the devmode */
1117 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1122 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1124 PRINTER_INFO_2A pinfo2a;
1127 char *e,*s,*name,*prettyname,*devname;
1128 BOOL ret = FALSE, set_default = FALSE;
1129 char *port = NULL, *env_default;
1130 HKEY hkeyPrinter, hkeyPrinters = NULL;
1131 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1132 HANDLE added_printer;
1134 while (isspace(*pent)) pent++;
1135 r = strchr(pent,':');
1137 name_len = r - pent;
1139 name_len = strlen(pent);
1140 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1141 memcpy(name, pent, name_len);
1142 name[name_len] = '\0';
1148 TRACE("name=%s entry=%s\n",name, pent);
1150 if(ispunct(*name)) { /* a tc entry, not a real printer */
1151 TRACE("skipping tc entry\n");
1155 if(strstr(pent,":server")) { /* server only version so skip */
1156 TRACE("skipping server entry\n");
1160 /* Determine whether this is a postscript printer. */
1163 env_default = getenv("PRINTER");
1165 /* Get longest name, usually the one at the right for later display. */
1166 while((s=strchr(prettyname,'|'))) {
1169 while(isspace(*--e)) *e = '\0';
1170 TRACE("\t%s\n", debugstr_a(prettyname));
1171 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1172 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1175 e = prettyname + strlen(prettyname);
1176 while(isspace(*--e)) *e = '\0';
1177 TRACE("\t%s\n", debugstr_a(prettyname));
1178 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1180 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1181 * if it is too long, we use it as comment below. */
1182 devname = prettyname;
1183 if (strlen(devname)>=CCHDEVICENAME-1)
1185 if (strlen(devname)>=CCHDEVICENAME-1) {
1190 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1191 sprintf(port,"LPR:%s",name);
1193 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1195 ERR("Can't create Printers key\n");
1200 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
1202 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1203 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1204 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1206 TRACE("Printer already exists\n");
1207 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1208 /* flag that the PPD file should be checked for an update */
1209 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1210 RegCloseKey(hkeyPrinter);
1212 static CHAR data_type[] = "RAW",
1213 print_proc[] = "WinPrint",
1214 comment[] = "WINEPS Printer using LPR",
1215 params[] = "<parameters?>",
1216 share_name[] = "<share name?>",
1217 sep_file[] = "<sep file?>";
1218 BOOL added_driver = FALSE;
1220 if (!ppd_dir) ppd_dir = get_ppd_dir();
1221 ppd = get_ppd_filename( ppd_dir, devnameW );
1222 if (get_fallback_ppd( devname, ppd ))
1224 added_driver = add_printer_driver( devnameW, ppd );
1227 HeapFree( GetProcessHeap(), 0, ppd );
1228 if (!added_driver) goto end;
1230 memset(&pinfo2a,0,sizeof(pinfo2a));
1231 pinfo2a.pPrinterName = devname;
1232 pinfo2a.pDatatype = data_type;
1233 pinfo2a.pPrintProcessor = print_proc;
1234 pinfo2a.pDriverName = devname;
1235 pinfo2a.pComment = comment;
1236 pinfo2a.pLocation = prettyname;
1237 pinfo2a.pPortName = port;
1238 pinfo2a.pParameters = params;
1239 pinfo2a.pShareName = share_name;
1240 pinfo2a.pSepFile = sep_file;
1242 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1243 if (added_printer) ClosePrinter( added_printer );
1244 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1245 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1248 if (isfirst || set_default)
1249 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1252 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1255 RemoveDirectoryW( ppd_dir );
1256 HeapFree( GetProcessHeap(), 0, ppd_dir );
1258 HeapFree(GetProcessHeap(), 0, port);
1259 HeapFree(GetProcessHeap(), 0, name);
1264 PRINTCAP_LoadPrinters(void) {
1265 BOOL hadprinter = FALSE;
1269 BOOL had_bash = FALSE;
1271 f = fopen("/etc/printcap","r");
1275 while(fgets(buf,sizeof(buf),f)) {
1278 end=strchr(buf,'\n');
1282 while(isspace(*start)) start++;
1283 if(*start == '#' || *start == '\0')
1286 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1287 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1288 HeapFree(GetProcessHeap(),0,pent);
1292 if (end && *--end == '\\') {
1299 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1302 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1308 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1309 HeapFree(GetProcessHeap(),0,pent);
1315 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1318 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1319 (lstrlenW(value) + 1) * sizeof(WCHAR));
1321 return ERROR_FILE_NOT_FOUND;
1324 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1326 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1327 DWORD ret = ERROR_FILE_NOT_FOUND;
1329 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1330 and we support these drivers. NT writes DEVMODEW so somehow
1331 we'll need to distinguish between these when we support NT
1336 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1337 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1338 HeapFree( GetProcessHeap(), 0, dmA );
1344 /******************************************************************
1345 * get_servername_from_name (internal)
1347 * for an external server, a copy of the serverpart from the full name is returned
1350 static LPWSTR get_servername_from_name(LPCWSTR name)
1354 WCHAR buffer[MAX_PATH];
1357 if (name == NULL) return NULL;
1358 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1360 server = strdupW(&name[2]); /* skip over both backslash */
1361 if (server == NULL) return NULL;
1363 /* strip '\' and the printername */
1364 ptr = strchrW(server, '\\');
1365 if (ptr) ptr[0] = '\0';
1367 TRACE("found %s\n", debugstr_w(server));
1369 len = sizeof(buffer)/sizeof(buffer[0]);
1370 if (GetComputerNameW(buffer, &len)) {
1371 if (lstrcmpW(buffer, server) == 0) {
1372 /* The requested Servername is our computername */
1373 HeapFree(GetProcessHeap(), 0, server);
1380 /******************************************************************
1381 * get_basename_from_name (internal)
1383 * skip over the serverpart from the full name
1386 static LPCWSTR get_basename_from_name(LPCWSTR name)
1388 if (name == NULL) return NULL;
1389 if ((name[0] == '\\') && (name[1] == '\\')) {
1390 /* skip over the servername and search for the following '\' */
1391 name = strchrW(&name[2], '\\');
1392 if ((name) && (name[1])) {
1393 /* found a separator ('\') followed by a name:
1394 skip over the separator and return the rest */
1399 /* no basename present (we found only a servername) */
1406 static void free_printer_entry( opened_printer_t *printer )
1408 /* the queue is shared, so don't free that here */
1409 HeapFree( GetProcessHeap(), 0, printer->printername );
1410 HeapFree( GetProcessHeap(), 0, printer->name );
1411 HeapFree( GetProcessHeap(), 0, printer->devmode );
1412 HeapFree( GetProcessHeap(), 0, printer );
1415 /******************************************************************
1416 * get_opened_printer_entry
1417 * Get the first place empty in the opened printer table
1420 * - pDefault is ignored
1422 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1424 UINT_PTR handle = nb_printer_handles, i;
1425 jobqueue_t *queue = NULL;
1426 opened_printer_t *printer = NULL;
1428 LPCWSTR printername;
1430 if ((backend == NULL) && !load_backend()) return NULL;
1432 servername = get_servername_from_name(name);
1434 FIXME("server %s not supported\n", debugstr_w(servername));
1435 HeapFree(GetProcessHeap(), 0, servername);
1436 SetLastError(ERROR_INVALID_PRINTER_NAME);
1440 printername = get_basename_from_name(name);
1441 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1443 /* an empty printername is invalid */
1444 if (printername && (!printername[0])) {
1445 SetLastError(ERROR_INVALID_PARAMETER);
1449 EnterCriticalSection(&printer_handles_cs);
1451 for (i = 0; i < nb_printer_handles; i++)
1453 if (!printer_handles[i])
1455 if(handle == nb_printer_handles)
1460 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1461 queue = printer_handles[i]->queue;
1465 if (handle >= nb_printer_handles)
1467 opened_printer_t **new_array;
1468 if (printer_handles)
1469 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1470 (nb_printer_handles + 16) * sizeof(*new_array) );
1472 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1473 (nb_printer_handles + 16) * sizeof(*new_array) );
1480 printer_handles = new_array;
1481 nb_printer_handles += 16;
1484 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1490 /* get a printer handle from the backend */
1491 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1496 /* clone the base name. This is NULL for the printserver */
1497 printer->printername = strdupW(printername);
1499 /* clone the full name */
1500 printer->name = strdupW(name);
1501 if (name && (!printer->name)) {
1506 if (pDefault && pDefault->pDevMode)
1507 printer->devmode = dup_devmode( pDefault->pDevMode );
1510 printer->queue = queue;
1513 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1514 if (!printer->queue) {
1518 list_init(&printer->queue->jobs);
1519 printer->queue->ref = 0;
1521 InterlockedIncrement(&printer->queue->ref);
1523 printer_handles[handle] = printer;
1526 LeaveCriticalSection(&printer_handles_cs);
1527 if (!handle && printer) {
1528 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1529 free_printer_entry( printer );
1532 return (HANDLE)handle;
1535 static void old_printer_check( BOOL delete_phase )
1537 PRINTER_INFO_5W* pi;
1538 DWORD needed, type, num, delete, i, size;
1539 const DWORD one = 1;
1543 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1544 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1546 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1547 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1548 for (i = 0; i < num; i++)
1550 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1551 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1554 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1558 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1564 size = sizeof( delete );
1565 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1569 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1570 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1572 DeletePrinter( hprn );
1573 ClosePrinter( hprn );
1575 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1579 HeapFree(GetProcessHeap(), 0, pi);
1582 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1583 'M','U','T','E','X','_','_','\0'};
1584 static HANDLE init_mutex;
1586 void WINSPOOL_LoadSystemPrinters(void)
1588 HKEY hkey, hkeyPrinters;
1589 DWORD needed, num, i;
1590 WCHAR PrinterName[256];
1593 /* FIXME: The init code should be moved to spoolsv.exe */
1594 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1597 ERR( "Failed to create mutex\n" );
1600 if (GetLastError() == ERROR_ALREADY_EXISTS)
1602 WaitForSingleObject( init_mutex, INFINITE );
1603 ReleaseMutex( init_mutex );
1604 TRACE( "Init already done\n" );
1608 /* This ensures that all printer entries have a valid Name value. If causes
1609 problems later if they don't. If one is found to be missed we create one
1610 and set it equal to the name of the key */
1611 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1612 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1613 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1614 for(i = 0; i < num; i++) {
1615 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1616 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1617 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1618 set_reg_szW(hkey, NameW, PrinterName);
1625 RegCloseKey(hkeyPrinters);
1628 old_printer_check( FALSE );
1630 #ifdef SONAME_LIBCUPS
1631 done = CUPS_LoadPrinters();
1634 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1635 PRINTCAP_LoadPrinters();
1637 old_printer_check( TRUE );
1639 ReleaseMutex( init_mutex );
1643 /******************************************************************
1646 * Get the pointer to the specified job.
1647 * Should hold the printer_handles_cs before calling.
1649 static job_t *get_job(HANDLE hprn, DWORD JobId)
1651 opened_printer_t *printer = get_opened_printer(hprn);
1654 if(!printer) return NULL;
1655 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1657 if(job->job_id == JobId)
1663 /***********************************************************
1666 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1669 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1672 Formname = (dmA->dmSize > off_formname);
1673 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1674 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1675 dmW->dmDeviceName, CCHDEVICENAME);
1677 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1678 dmA->dmSize - CCHDEVICENAME);
1680 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1681 off_formname - CCHDEVICENAME);
1682 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1683 dmW->dmFormName, CCHFORMNAME);
1684 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1685 (off_formname + CCHFORMNAME));
1688 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1689 dmA->dmDriverExtra);
1693 /******************************************************************
1694 * convert_printerinfo_W_to_A [internal]
1697 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1698 DWORD level, DWORD outlen, DWORD numentries)
1704 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1706 len = pi_sizeof[level] * numentries;
1707 ptr = (LPSTR) out + len;
1710 /* copy the numbers of all PRINTER_INFO_* first */
1711 memcpy(out, pPrintersW, len);
1713 while (id < numentries) {
1717 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1718 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1720 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1721 if (piW->pDescription) {
1722 piA->pDescription = ptr;
1723 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1724 ptr, outlen, NULL, NULL);
1730 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1731 ptr, outlen, NULL, NULL);
1735 if (piW->pComment) {
1736 piA->pComment = ptr;
1737 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1738 ptr, outlen, NULL, NULL);
1747 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1748 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1751 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1752 if (piW->pServerName) {
1753 piA->pServerName = ptr;
1754 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1755 ptr, outlen, NULL, NULL);
1759 if (piW->pPrinterName) {
1760 piA->pPrinterName = ptr;
1761 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1762 ptr, outlen, NULL, NULL);
1766 if (piW->pShareName) {
1767 piA->pShareName = ptr;
1768 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1769 ptr, outlen, NULL, NULL);
1773 if (piW->pPortName) {
1774 piA->pPortName = ptr;
1775 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1776 ptr, outlen, NULL, NULL);
1780 if (piW->pDriverName) {
1781 piA->pDriverName = ptr;
1782 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1783 ptr, outlen, NULL, NULL);
1787 if (piW->pComment) {
1788 piA->pComment = ptr;
1789 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1790 ptr, outlen, NULL, NULL);
1794 if (piW->pLocation) {
1795 piA->pLocation = ptr;
1796 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1797 ptr, outlen, NULL, NULL);
1802 dmA = DEVMODEdupWtoA(piW->pDevMode);
1804 /* align DEVMODEA to a DWORD boundary */
1805 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1809 piA->pDevMode = (LPDEVMODEA) ptr;
1810 len = dmA->dmSize + dmA->dmDriverExtra;
1811 memcpy(ptr, dmA, len);
1812 HeapFree(GetProcessHeap(), 0, dmA);
1818 if (piW->pSepFile) {
1819 piA->pSepFile = ptr;
1820 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1821 ptr, outlen, NULL, NULL);
1825 if (piW->pPrintProcessor) {
1826 piA->pPrintProcessor = ptr;
1827 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1828 ptr, outlen, NULL, NULL);
1832 if (piW->pDatatype) {
1833 piA->pDatatype = ptr;
1834 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1835 ptr, outlen, NULL, NULL);
1839 if (piW->pParameters) {
1840 piA->pParameters = ptr;
1841 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1842 ptr, outlen, NULL, NULL);
1846 if (piW->pSecurityDescriptor) {
1847 piA->pSecurityDescriptor = NULL;
1848 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1855 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1856 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1858 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1860 if (piW->pPrinterName) {
1861 piA->pPrinterName = ptr;
1862 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1863 ptr, outlen, NULL, NULL);
1867 if (piW->pServerName) {
1868 piA->pServerName = ptr;
1869 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1870 ptr, outlen, NULL, NULL);
1879 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1880 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1882 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1884 if (piW->pPrinterName) {
1885 piA->pPrinterName = ptr;
1886 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1887 ptr, outlen, NULL, NULL);
1891 if (piW->pPortName) {
1892 piA->pPortName = ptr;
1893 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1894 ptr, outlen, NULL, NULL);
1901 case 6: /* 6A and 6W are the same structure */
1906 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1907 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1909 TRACE("(%u) #%u\n", level, id);
1910 if (piW->pszObjectGUID) {
1911 piA->pszObjectGUID = ptr;
1912 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1913 ptr, outlen, NULL, NULL);
1923 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1924 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1927 TRACE("(%u) #%u\n", level, id);
1928 dmA = DEVMODEdupWtoA(piW->pDevMode);
1930 /* align DEVMODEA to a DWORD boundary */
1931 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1935 piA->pDevMode = (LPDEVMODEA) ptr;
1936 len = dmA->dmSize + dmA->dmDriverExtra;
1937 memcpy(ptr, dmA, len);
1938 HeapFree(GetProcessHeap(), 0, dmA);
1948 FIXME("for level %u\n", level);
1950 pPrintersW += pi_sizeof[level];
1951 out += pi_sizeof[level];
1956 /******************************************************************
1957 * convert_driverinfo_W_to_A [internal]
1960 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1961 DWORD level, DWORD outlen, DWORD numentries)
1967 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1969 len = di_sizeof[level] * numentries;
1970 ptr = (LPSTR) out + len;
1973 /* copy the numbers of all PRINTER_INFO_* first */
1974 memcpy(out, pDriversW, len);
1976 #define COPY_STRING(fld) \
1979 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1980 ptr += len; outlen -= len;\
1982 #define COPY_MULTIZ_STRING(fld) \
1983 { LPWSTR p = diW->fld; if (p){ \
1986 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1987 ptr += len; outlen -= len; p += len;\
1989 while(len > 1 && outlen > 0); \
1992 while (id < numentries)
1998 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1999 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
2001 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2008 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2009 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2011 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2014 COPY_STRING(pEnvironment);
2015 COPY_STRING(pDriverPath);
2016 COPY_STRING(pDataFile);
2017 COPY_STRING(pConfigFile);
2022 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2023 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2025 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2028 COPY_STRING(pEnvironment);
2029 COPY_STRING(pDriverPath);
2030 COPY_STRING(pDataFile);
2031 COPY_STRING(pConfigFile);
2032 COPY_STRING(pHelpFile);
2033 COPY_MULTIZ_STRING(pDependentFiles);
2034 COPY_STRING(pMonitorName);
2035 COPY_STRING(pDefaultDataType);
2040 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2041 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2043 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2046 COPY_STRING(pEnvironment);
2047 COPY_STRING(pDriverPath);
2048 COPY_STRING(pDataFile);
2049 COPY_STRING(pConfigFile);
2050 COPY_STRING(pHelpFile);
2051 COPY_MULTIZ_STRING(pDependentFiles);
2052 COPY_STRING(pMonitorName);
2053 COPY_STRING(pDefaultDataType);
2054 COPY_MULTIZ_STRING(pszzPreviousNames);
2059 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2060 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2062 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2065 COPY_STRING(pEnvironment);
2066 COPY_STRING(pDriverPath);
2067 COPY_STRING(pDataFile);
2068 COPY_STRING(pConfigFile);
2073 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2074 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2076 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2079 COPY_STRING(pEnvironment);
2080 COPY_STRING(pDriverPath);
2081 COPY_STRING(pDataFile);
2082 COPY_STRING(pConfigFile);
2083 COPY_STRING(pHelpFile);
2084 COPY_MULTIZ_STRING(pDependentFiles);
2085 COPY_STRING(pMonitorName);
2086 COPY_STRING(pDefaultDataType);
2087 COPY_MULTIZ_STRING(pszzPreviousNames);
2088 COPY_STRING(pszMfgName);
2089 COPY_STRING(pszOEMUrl);
2090 COPY_STRING(pszHardwareID);
2091 COPY_STRING(pszProvider);
2096 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2097 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2099 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2102 COPY_STRING(pEnvironment);
2103 COPY_STRING(pDriverPath);
2104 COPY_STRING(pDataFile);
2105 COPY_STRING(pConfigFile);
2106 COPY_STRING(pHelpFile);
2107 COPY_MULTIZ_STRING(pDependentFiles);
2108 COPY_STRING(pMonitorName);
2109 COPY_STRING(pDefaultDataType);
2110 COPY_MULTIZ_STRING(pszzPreviousNames);
2111 COPY_STRING(pszMfgName);
2112 COPY_STRING(pszOEMUrl);
2113 COPY_STRING(pszHardwareID);
2114 COPY_STRING(pszProvider);
2115 COPY_STRING(pszPrintProcessor);
2116 COPY_STRING(pszVendorSetup);
2117 COPY_MULTIZ_STRING(pszzColorProfiles);
2118 COPY_STRING(pszInfPath);
2119 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2125 FIXME("for level %u\n", level);
2128 pDriversW += di_sizeof[level];
2129 out += di_sizeof[level];
2134 #undef COPY_MULTIZ_STRING
2138 /***********************************************************
2141 static void *printer_info_AtoW( const void *data, DWORD level )
2144 UNICODE_STRING usBuffer;
2146 if (!data) return NULL;
2148 if (level < 1 || level > 9) return NULL;
2150 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2151 if (!ret) return NULL;
2153 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2159 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2160 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2162 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2163 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2164 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2165 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2166 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2167 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2168 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2169 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2170 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2171 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2172 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2173 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2180 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2181 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2183 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2188 FIXME( "Unhandled level %d\n", level );
2189 HeapFree( GetProcessHeap(), 0, ret );
2196 /***********************************************************
2199 static void free_printer_info( void *data, DWORD level )
2207 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2209 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2210 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2211 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2212 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2213 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2214 HeapFree( GetProcessHeap(), 0, piW->pComment );
2215 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2216 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2217 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2218 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2219 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2220 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2227 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2229 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2234 FIXME( "Unhandled level %d\n", level );
2237 HeapFree( GetProcessHeap(), 0, data );
2241 /******************************************************************
2242 * DeviceCapabilities [WINSPOOL.@]
2243 * DeviceCapabilitiesA [WINSPOOL.@]
2246 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2247 LPSTR pOutput, LPDEVMODEA lpdm)
2251 if (!GDI_CallDeviceCapabilities16)
2253 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2255 if (!GDI_CallDeviceCapabilities16) return -1;
2257 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2259 /* If DC_PAPERSIZE map POINT16s to POINTs */
2260 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2261 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2262 POINT *pt = (POINT *)pOutput;
2264 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2265 for(i = 0; i < ret; i++, pt++)
2270 HeapFree( GetProcessHeap(), 0, tmp );
2276 /*****************************************************************************
2277 * DeviceCapabilitiesW [WINSPOOL.@]
2279 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2282 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2283 WORD fwCapability, LPWSTR pOutput,
2284 const DEVMODEW *pDevMode)
2286 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2287 LPSTR pDeviceA = strdupWtoA(pDevice);
2288 LPSTR pPortA = strdupWtoA(pPort);
2291 if(pOutput && (fwCapability == DC_BINNAMES ||
2292 fwCapability == DC_FILEDEPENDENCIES ||
2293 fwCapability == DC_PAPERNAMES)) {
2294 /* These need A -> W translation */
2297 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2301 switch(fwCapability) {
2306 case DC_FILEDEPENDENCIES:
2310 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2311 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2313 for(i = 0; i < ret; i++)
2314 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2315 pOutput + (i * size), size);
2316 HeapFree(GetProcessHeap(), 0, pOutputA);
2318 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2319 (LPSTR)pOutput, dmA);
2321 HeapFree(GetProcessHeap(),0,pPortA);
2322 HeapFree(GetProcessHeap(),0,pDeviceA);
2323 HeapFree(GetProcessHeap(),0,dmA);
2327 /******************************************************************
2328 * DocumentPropertiesA [WINSPOOL.@]
2330 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2332 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2333 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2334 LPDEVMODEA pDevModeInput,DWORD fMode )
2336 LPSTR lpName = pDeviceName;
2337 static CHAR port[] = "LPT1:";
2340 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2341 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2345 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2347 ERR("no name from hPrinter?\n");
2348 SetLastError(ERROR_INVALID_HANDLE);
2351 lpName = strdupWtoA(lpNameW);
2354 if (!GDI_CallExtDeviceMode16)
2356 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2358 if (!GDI_CallExtDeviceMode16) {
2359 ERR("No CallExtDeviceMode16?\n");
2363 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2364 pDevModeInput, NULL, fMode);
2367 HeapFree(GetProcessHeap(),0,lpName);
2372 /*****************************************************************************
2373 * DocumentPropertiesW (WINSPOOL.@)
2375 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2377 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2379 LPDEVMODEW pDevModeOutput,
2380 LPDEVMODEW pDevModeInput, DWORD fMode)
2383 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2384 LPDEVMODEA pDevModeInputA;
2385 LPDEVMODEA pDevModeOutputA = NULL;
2388 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2389 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2391 if(pDevModeOutput) {
2392 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2393 if(ret < 0) return ret;
2394 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2396 pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2397 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2398 pDevModeInputA, fMode);
2399 if(pDevModeOutput) {
2400 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2401 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2403 if(fMode == 0 && ret > 0)
2404 ret += (CCHDEVICENAME + CCHFORMNAME);
2405 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2406 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2410 /*****************************************************************************
2411 * IsValidDevmodeA [WINSPOOL.@]
2413 * Validate a DEVMODE structure and fix errors if possible.
2416 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2418 FIXME("(%p,%ld): stub\n", pDevMode, size);
2426 /*****************************************************************************
2427 * IsValidDevmodeW [WINSPOOL.@]
2429 * Validate a DEVMODE structure and fix errors if possible.
2432 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2434 FIXME("(%p,%ld): stub\n", pDevMode, size);
2442 /******************************************************************
2443 * OpenPrinterA [WINSPOOL.@]
2448 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2449 LPPRINTER_DEFAULTSA pDefault)
2451 UNICODE_STRING lpPrinterNameW;
2452 UNICODE_STRING usBuffer;
2453 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2454 PWSTR pwstrPrinterNameW;
2457 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2460 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2461 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2462 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2463 pDefaultW = &DefaultW;
2465 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2467 RtlFreeUnicodeString(&usBuffer);
2468 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2470 RtlFreeUnicodeString(&lpPrinterNameW);
2474 /******************************************************************
2475 * OpenPrinterW [WINSPOOL.@]
2477 * Open a Printer / Printserver or a Printer-Object
2480 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2481 * phPrinter [O] The resulting Handle is stored here
2482 * pDefault [I] PTR to Default Printer Settings or NULL
2489 * lpPrinterName is one of:
2490 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2491 *| Printer: "PrinterName"
2492 *| Printer-Object: "PrinterName,Job xxx"
2493 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2494 *| XcvPort: "Servername,XcvPort PortName"
2497 *| Printer-Object not supported
2498 *| pDefaults is ignored
2501 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2504 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2507 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2508 SetLastError(ERROR_INVALID_PARAMETER);
2512 /* Get the unique handle of the printer or Printserver */
2513 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2518 DWORD deleting = 0, size = sizeof( deleting ), type;
2520 WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key );
2521 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2522 WaitForSingleObject( init_mutex, INFINITE );
2523 status = get_dword_from_reg( key, StatusW );
2524 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2525 ReleaseMutex( init_mutex );
2526 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2527 update_driver( *phPrinter );
2531 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2532 return (*phPrinter != 0);
2535 /******************************************************************
2536 * AddMonitorA [WINSPOOL.@]
2541 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2543 LPWSTR nameW = NULL;
2546 LPMONITOR_INFO_2A mi2a;
2547 MONITOR_INFO_2W mi2w;
2549 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2550 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2551 debugstr_a(mi2a ? mi2a->pName : NULL),
2552 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2553 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2556 SetLastError(ERROR_INVALID_LEVEL);
2560 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2566 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2567 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2568 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2571 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2573 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2574 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2575 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2577 if (mi2a->pEnvironment) {
2578 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2579 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2580 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2582 if (mi2a->pDLLName) {
2583 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2584 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2585 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2588 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2590 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2591 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2592 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2594 HeapFree(GetProcessHeap(), 0, nameW);
2598 /******************************************************************************
2599 * AddMonitorW [WINSPOOL.@]
2601 * Install a Printmonitor
2604 * pName [I] Servername or NULL (local Computer)
2605 * Level [I] Structure-Level (Must be 2)
2606 * pMonitors [I] PTR to MONITOR_INFO_2
2613 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2616 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2618 LPMONITOR_INFO_2W mi2w;
2620 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2621 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2622 debugstr_w(mi2w ? mi2w->pName : NULL),
2623 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2624 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2626 if ((backend == NULL) && !load_backend()) return FALSE;
2629 SetLastError(ERROR_INVALID_LEVEL);
2633 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2638 return backend->fpAddMonitor(pName, Level, pMonitors);
2641 /******************************************************************
2642 * DeletePrinterDriverA [WINSPOOL.@]
2645 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2647 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2650 /******************************************************************
2651 * DeletePrinterDriverW [WINSPOOL.@]
2654 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2656 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2659 /******************************************************************
2660 * DeleteMonitorA [WINSPOOL.@]
2662 * See DeleteMonitorW.
2665 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2667 LPWSTR nameW = NULL;
2668 LPWSTR EnvironmentW = NULL;
2669 LPWSTR MonitorNameW = NULL;
2674 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2675 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2676 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2680 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2681 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2682 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2685 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2686 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2687 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2690 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2692 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2693 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2694 HeapFree(GetProcessHeap(), 0, nameW);
2698 /******************************************************************
2699 * DeleteMonitorW [WINSPOOL.@]
2701 * Delete a specific Printmonitor from a Printing-Environment
2704 * pName [I] Servername or NULL (local Computer)
2705 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2706 * pMonitorName [I] Name of the Monitor, that should be deleted
2713 * pEnvironment is ignored in Windows for the local Computer.
2716 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2719 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2720 debugstr_w(pMonitorName));
2722 if ((backend == NULL) && !load_backend()) return FALSE;
2724 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2728 /******************************************************************
2729 * DeletePortA [WINSPOOL.@]
2734 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2736 LPWSTR nameW = NULL;
2737 LPWSTR portW = NULL;
2741 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2743 /* convert servername to unicode */
2745 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2746 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2747 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2750 /* convert portname to unicode */
2752 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2753 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2754 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2757 res = DeletePortW(nameW, hWnd, portW);
2758 HeapFree(GetProcessHeap(), 0, nameW);
2759 HeapFree(GetProcessHeap(), 0, portW);
2763 /******************************************************************
2764 * DeletePortW [WINSPOOL.@]
2766 * Delete a specific Port
2769 * pName [I] Servername or NULL (local Computer)
2770 * hWnd [I] Handle to parent Window for the Dialog-Box
2771 * pPortName [I] Name of the Port, that should be deleted
2778 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2780 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2782 if ((backend == NULL) && !load_backend()) return FALSE;
2785 SetLastError(RPC_X_NULL_REF_POINTER);
2789 return backend->fpDeletePort(pName, hWnd, pPortName);
2792 /******************************************************************************
2793 * WritePrinter [WINSPOOL.@]
2795 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2797 opened_printer_t *printer;
2800 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2802 EnterCriticalSection(&printer_handles_cs);
2803 printer = get_opened_printer(hPrinter);
2806 SetLastError(ERROR_INVALID_HANDLE);
2812 SetLastError(ERROR_SPL_NO_STARTDOC);
2816 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2818 LeaveCriticalSection(&printer_handles_cs);
2822 /*****************************************************************************
2823 * AddFormA [WINSPOOL.@]
2825 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2827 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2831 /*****************************************************************************
2832 * AddFormW [WINSPOOL.@]
2834 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2836 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2840 /*****************************************************************************
2841 * AddJobA [WINSPOOL.@]
2843 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2846 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2850 SetLastError(ERROR_INVALID_LEVEL);
2854 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2857 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2858 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2859 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2860 if(*pcbNeeded > cbBuf) {
2861 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2864 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2865 addjobA->JobId = addjobW->JobId;
2866 addjobA->Path = (char *)(addjobA + 1);
2867 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2873 /*****************************************************************************
2874 * AddJobW [WINSPOOL.@]
2876 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2878 opened_printer_t *printer;
2881 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2882 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2883 WCHAR path[MAX_PATH], filename[MAX_PATH];
2885 ADDJOB_INFO_1W *addjob;
2887 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2889 EnterCriticalSection(&printer_handles_cs);
2891 printer = get_opened_printer(hPrinter);
2894 SetLastError(ERROR_INVALID_HANDLE);
2899 SetLastError(ERROR_INVALID_LEVEL);
2903 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2907 job->job_id = InterlockedIncrement(&next_job_id);
2909 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2910 if(path[len - 1] != '\\')
2912 memcpy(path + len, spool_path, sizeof(spool_path));
2913 sprintfW(filename, fmtW, path, job->job_id);
2915 len = strlenW(filename);
2916 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2917 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2918 job->portname = NULL;
2919 job->document_title = strdupW(default_doc_title);
2920 job->printer_name = strdupW(printer->name);
2921 job->devmode = dup_devmode( printer->devmode );
2922 list_add_tail(&printer->queue->jobs, &job->entry);
2924 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2925 if(*pcbNeeded <= cbBuf) {
2926 addjob = (ADDJOB_INFO_1W*)pData;
2927 addjob->JobId = job->job_id;
2928 addjob->Path = (WCHAR *)(addjob + 1);
2929 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2932 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2935 LeaveCriticalSection(&printer_handles_cs);
2939 /*****************************************************************************
2940 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2942 * Return the PATH for the Print-Processors
2944 * See GetPrintProcessorDirectoryW.
2948 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2949 DWORD level, LPBYTE Info,
2950 DWORD cbBuf, LPDWORD pcbNeeded)
2952 LPWSTR serverW = NULL;
2957 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2958 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2962 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2963 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2964 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2968 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2969 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2970 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2973 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2974 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2976 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2979 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2980 cbBuf, NULL, NULL) > 0;
2983 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2984 HeapFree(GetProcessHeap(), 0, envW);
2985 HeapFree(GetProcessHeap(), 0, serverW);
2989 /*****************************************************************************
2990 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2992 * Return the PATH for the Print-Processors
2995 * server [I] Servername (NT only) or NULL (local Computer)
2996 * env [I] Printing-Environment (see below) or NULL (Default)
2997 * level [I] Structure-Level (must be 1)
2998 * Info [O] PTR to Buffer that receives the Result
2999 * cbBuf [I] Size of Buffer at "Info"
3000 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3001 * required for the Buffer at "Info"
3004 * Success: TRUE and in pcbNeeded the Bytes used in Info
3005 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3006 * if cbBuf is too small
3008 * Native Values returned in Info on Success:
3009 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3010 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3011 *| win9x(Windows 4.0): "%winsysdir%"
3013 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3016 * Only NULL or "" is supported for server
3019 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3020 DWORD level, LPBYTE Info,
3021 DWORD cbBuf, LPDWORD pcbNeeded)
3024 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3025 Info, cbBuf, pcbNeeded);
3027 if ((backend == NULL) && !load_backend()) return FALSE;
3030 /* (Level != 1) is ignored in win9x */
3031 SetLastError(ERROR_INVALID_LEVEL);
3035 if (pcbNeeded == NULL) {
3036 /* (pcbNeeded == NULL) is ignored in win9x */
3037 SetLastError(RPC_X_NULL_REF_POINTER);
3041 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3044 /*****************************************************************************
3045 * WINSPOOL_OpenDriverReg [internal]
3047 * opens the registry for the printer drivers depending on the given input
3048 * variable pEnvironment
3051 * the opened hkey on success
3054 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3058 const printenv_t * env;
3060 TRACE("(%s)\n", debugstr_w(pEnvironment));
3062 env = validate_envW(pEnvironment);
3063 if (!env) return NULL;
3065 buffer = HeapAlloc( GetProcessHeap(), 0,
3066 (strlenW(DriversW) + strlenW(env->envname) +
3067 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3069 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3070 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3071 HeapFree(GetProcessHeap(), 0, buffer);
3076 /*****************************************************************************
3077 * set_devices_and_printerports [internal]
3079 * set the [Devices] and [PrinterPorts] entries for a printer.
3082 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3084 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3088 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3090 /* FIXME: the driver must change to "winspool" */
3091 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3093 lstrcpyW(devline, driver_nt);
3094 lstrcatW(devline, commaW);
3095 lstrcatW(devline, pi->pPortName);
3097 TRACE("using %s\n", debugstr_w(devline));
3098 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
3099 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3100 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3101 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3105 lstrcatW(devline, timeout_15_45);
3106 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
3107 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3108 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3109 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3112 HeapFree(GetProcessHeap(), 0, devline);
3116 /*****************************************************************************
3117 * AddPrinterW [WINSPOOL.@]
3119 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3121 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3124 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3127 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3130 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3131 SetLastError(ERROR_INVALID_PARAMETER);
3135 ERR("Level = %d, unsupported!\n", Level);
3136 SetLastError(ERROR_INVALID_LEVEL);
3140 SetLastError(ERROR_INVALID_PARAMETER);
3143 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3145 ERR("Can't create Printers key\n");
3148 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3149 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3150 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3151 RegCloseKey(hkeyPrinter);
3152 RegCloseKey(hkeyPrinters);
3155 RegCloseKey(hkeyPrinter);
3157 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3159 ERR("Can't create Drivers key\n");
3160 RegCloseKey(hkeyPrinters);
3163 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3165 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3166 RegCloseKey(hkeyPrinters);
3167 RegCloseKey(hkeyDrivers);
3168 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3171 RegCloseKey(hkeyDriver);
3172 RegCloseKey(hkeyDrivers);
3174 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3175 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3176 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3177 RegCloseKey(hkeyPrinters);
3181 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3183 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3184 SetLastError(ERROR_INVALID_PRINTER_NAME);
3185 RegCloseKey(hkeyPrinters);
3189 set_devices_and_printerports(pi);
3191 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3192 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3193 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3194 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3195 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3196 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3197 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3198 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3199 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3200 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3201 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3202 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3203 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3204 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3205 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3206 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3207 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3208 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3210 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3214 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3215 size = sizeof(DEVMODEW);
3221 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3223 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3225 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3226 HeapFree( GetProcessHeap(), 0, dm );
3231 /* set devmode to printer name */
3232 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3236 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3237 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3239 RegCloseKey(hkeyPrinter);
3240 RegCloseKey(hkeyPrinters);
3241 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3242 ERR("OpenPrinter failing\n");
3248 /*****************************************************************************
3249 * AddPrinterA [WINSPOOL.@]
3251 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3253 UNICODE_STRING pNameW;
3255 PRINTER_INFO_2W *piW;
3256 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3259 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3261 ERR("Level = %d, unsupported!\n", Level);
3262 SetLastError(ERROR_INVALID_LEVEL);
3265 pwstrNameW = asciitounicode(&pNameW,pName);
3266 piW = printer_info_AtoW( piA, Level );
3268 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3270 free_printer_info( piW, Level );
3271 RtlFreeUnicodeString(&pNameW);
3276 /*****************************************************************************
3277 * ClosePrinter [WINSPOOL.@]
3279 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3281 UINT_PTR i = (UINT_PTR)hPrinter;
3282 opened_printer_t *printer = NULL;
3285 TRACE("(%p)\n", hPrinter);
3287 EnterCriticalSection(&printer_handles_cs);
3289 if ((i > 0) && (i <= nb_printer_handles))
3290 printer = printer_handles[i - 1];
3295 struct list *cursor, *cursor2;
3297 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3299 if (printer->backend_printer) {
3300 backend->fpClosePrinter(printer->backend_printer);
3304 EndDocPrinter(hPrinter);
3306 if(InterlockedDecrement(&printer->queue->ref) == 0)
3308 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3310 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3311 ScheduleJob(hPrinter, job->job_id);
3313 HeapFree(GetProcessHeap(), 0, printer->queue);
3316 free_printer_entry( printer );
3317 printer_handles[i - 1] = NULL;
3320 LeaveCriticalSection(&printer_handles_cs);
3324 /*****************************************************************************
3325 * DeleteFormA [WINSPOOL.@]
3327 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3329 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3333 /*****************************************************************************
3334 * DeleteFormW [WINSPOOL.@]
3336 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3338 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3342 /*****************************************************************************
3343 * DeletePrinter [WINSPOOL.@]
3345 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3347 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3348 HKEY hkeyPrinters, hkey;
3349 WCHAR def[MAX_PATH];
3350 DWORD size = sizeof( def ) / sizeof( def[0] );
3353 SetLastError(ERROR_INVALID_HANDLE);
3356 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3357 RegDeleteTreeW(hkeyPrinters, lpNameW);
3358 RegCloseKey(hkeyPrinters);
3360 WriteProfileStringW(devicesW, lpNameW, NULL);
3361 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3363 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3364 RegDeleteValueW(hkey, lpNameW);
3368 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3369 RegDeleteValueW(hkey, lpNameW);
3373 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3375 WriteProfileStringW( windowsW, deviceW, NULL );
3376 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3378 RegDeleteValueW( hkey, deviceW );
3379 RegCloseKey( hkey );
3381 SetDefaultPrinterW( NULL );
3387 /*****************************************************************************
3388 * SetPrinterA [WINSPOOL.@]
3390 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3397 dataW = printer_info_AtoW( data, level );
3398 if (!dataW) return FALSE;
3401 ret = SetPrinterW( printer, level, dataW, command );
3403 if (dataW != data) free_printer_info( dataW, level );
3408 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3410 set_reg_szW( key, NameW, pi->pPrinterName );
3411 set_reg_szW( key, Share_NameW, pi->pShareName );
3412 set_reg_szW( key, PortW, pi->pPortName );
3413 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3414 set_reg_szW( key, DescriptionW, pi->pComment );
3415 set_reg_szW( key, LocationW, pi->pLocation );
3418 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3420 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3421 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3422 set_reg_szW( key, DatatypeW, pi->pDatatype );
3423 set_reg_szW( key, ParametersW, pi->pParameters );
3425 set_reg_DWORD( key, AttributesW, pi->Attributes );
3426 set_reg_DWORD( key, PriorityW, pi->Priority );
3427 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3428 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3429 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3432 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3434 if (!pi->pDevMode) return FALSE;
3436 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3440 /******************************************************************************
3441 * SetPrinterW [WINSPOOL.@]
3443 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3448 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3450 if (command != 0) FIXME( "Ignoring command %d\n", command );
3452 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3459 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3460 set_printer_2( key, pi2 );
3467 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3468 ret = set_printer_9( key, pi );
3473 FIXME( "Unimplemented level %d\n", level );
3474 SetLastError( ERROR_INVALID_LEVEL );
3481 /*****************************************************************************
3482 * SetJobA [WINSPOOL.@]
3484 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3485 LPBYTE pJob, DWORD Command)
3489 UNICODE_STRING usBuffer;
3491 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3493 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3494 are all ignored by SetJob, so we don't bother copying them */
3502 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3503 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3505 JobW = (LPBYTE)info1W;
3506 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3507 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3508 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3509 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3510 info1W->Status = info1A->Status;
3511 info1W->Priority = info1A->Priority;
3512 info1W->Position = info1A->Position;
3513 info1W->PagesPrinted = info1A->PagesPrinted;
3518 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3519 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3521 JobW = (LPBYTE)info2W;
3522 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3523 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3524 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3525 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3526 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3527 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3528 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3529 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3530 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3531 info2W->Status = info2A->Status;
3532 info2W->Priority = info2A->Priority;
3533 info2W->Position = info2A->Position;
3534 info2W->StartTime = info2A->StartTime;
3535 info2W->UntilTime = info2A->UntilTime;
3536 info2W->PagesPrinted = info2A->PagesPrinted;
3540 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3541 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3544 SetLastError(ERROR_INVALID_LEVEL);
3548 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3554 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3555 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3556 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3557 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3558 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3563 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3564 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3565 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3566 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3567 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3568 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3569 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3570 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3571 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3575 HeapFree(GetProcessHeap(), 0, JobW);
3580 /*****************************************************************************
3581 * SetJobW [WINSPOOL.@]
3583 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3584 LPBYTE pJob, DWORD Command)
3589 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3590 FIXME("Ignoring everything other than document title\n");
3592 EnterCriticalSection(&printer_handles_cs);
3593 job = get_job(hPrinter, JobId);
3603 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3604 HeapFree(GetProcessHeap(), 0, job->document_title);
3605 job->document_title = strdupW(info1->pDocument);
3610 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3611 HeapFree(GetProcessHeap(), 0, job->document_title);
3612 job->document_title = strdupW(info2->pDocument);
3613 HeapFree(GetProcessHeap(), 0, job->devmode);
3614 job->devmode = dup_devmode( info2->pDevMode );
3620 SetLastError(ERROR_INVALID_LEVEL);
3625 LeaveCriticalSection(&printer_handles_cs);
3629 /*****************************************************************************
3630 * EndDocPrinter [WINSPOOL.@]
3632 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3634 opened_printer_t *printer;
3636 TRACE("(%p)\n", hPrinter);
3638 EnterCriticalSection(&printer_handles_cs);
3640 printer = get_opened_printer(hPrinter);
3643 SetLastError(ERROR_INVALID_HANDLE);
3649 SetLastError(ERROR_SPL_NO_STARTDOC);
3653 CloseHandle(printer->doc->hf);
3654 ScheduleJob(hPrinter, printer->doc->job_id);
3655 HeapFree(GetProcessHeap(), 0, printer->doc);
3656 printer->doc = NULL;
3659 LeaveCriticalSection(&printer_handles_cs);
3663 /*****************************************************************************
3664 * EndPagePrinter [WINSPOOL.@]
3666 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3668 FIXME("(%p): stub\n", hPrinter);
3672 /*****************************************************************************
3673 * StartDocPrinterA [WINSPOOL.@]
3675 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3677 UNICODE_STRING usBuffer;
3679 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3682 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3683 or one (DOC_INFO_3) extra DWORDs */
3687 doc2W.JobId = doc2->JobId;
3690 doc2W.dwMode = doc2->dwMode;
3693 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3694 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3695 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3699 SetLastError(ERROR_INVALID_LEVEL);
3703 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3705 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3706 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3707 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3712 /*****************************************************************************
3713 * StartDocPrinterW [WINSPOOL.@]
3715 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3717 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3718 opened_printer_t *printer;
3719 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3720 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3721 JOB_INFO_1W job_info;
3722 DWORD needed, ret = 0;
3727 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3728 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3729 debugstr_w(doc->pDatatype));
3731 if(Level < 1 || Level > 3)
3733 SetLastError(ERROR_INVALID_LEVEL);
3737 EnterCriticalSection(&printer_handles_cs);
3738 printer = get_opened_printer(hPrinter);
3741 SetLastError(ERROR_INVALID_HANDLE);
3747 SetLastError(ERROR_INVALID_PRINTER_STATE);
3751 /* Even if we're printing to a file we still add a print job, we'll
3752 just ignore the spool file name */
3754 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3756 ERR("AddJob failed gle %u\n", GetLastError());
3760 /* use pOutputFile only, when it is a real filename */
3761 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3762 filename = doc->pOutputFile;
3764 filename = addjob->Path;
3766 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3767 if(hf == INVALID_HANDLE_VALUE)
3770 memset(&job_info, 0, sizeof(job_info));
3771 job_info.pDocument = doc->pDocName;
3772 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3774 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3775 printer->doc->hf = hf;
3776 ret = printer->doc->job_id = addjob->JobId;
3777 job = get_job(hPrinter, ret);
3778 job->portname = strdupW(doc->pOutputFile);
3781 LeaveCriticalSection(&printer_handles_cs);
3786 /*****************************************************************************
3787 * StartPagePrinter [WINSPOOL.@]
3789 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3791 FIXME("(%p): stub\n", hPrinter);
3795 /*****************************************************************************
3796 * GetFormA [WINSPOOL.@]
3798 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3799 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3801 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3802 Level,pForm,cbBuf,pcbNeeded);
3806 /*****************************************************************************
3807 * GetFormW [WINSPOOL.@]
3809 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3810 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3812 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3813 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3817 /*****************************************************************************
3818 * SetFormA [WINSPOOL.@]
3820 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3823 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3827 /*****************************************************************************
3828 * SetFormW [WINSPOOL.@]
3830 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3833 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3837 /*****************************************************************************
3838 * ReadPrinter [WINSPOOL.@]
3840 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3841 LPDWORD pNoBytesRead)
3843 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3847 /*****************************************************************************
3848 * ResetPrinterA [WINSPOOL.@]
3850 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3852 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3856 /*****************************************************************************
3857 * ResetPrinterW [WINSPOOL.@]
3859 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3861 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3865 /*****************************************************************************
3866 * get_filename_from_reg [internal]
3868 * Get ValueName from hkey storing result in out
3869 * when the Value in the registry has only a filename, use driverdir as prefix
3870 * outlen is space left in out
3871 * String is stored either as unicode or ascii
3875 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3876 LPBYTE out, DWORD outlen, LPDWORD needed)
3878 WCHAR filename[MAX_PATH];
3882 LPWSTR buffer = filename;
3886 size = sizeof(filename);
3888 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3889 if (ret == ERROR_MORE_DATA) {
3890 TRACE("need dynamic buffer: %u\n", size);
3891 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3893 /* No Memory is bad */
3897 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3900 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3901 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3907 /* do we have a full path ? */
3908 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3909 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3912 /* we must build the full Path */
3914 if ((out) && (outlen > dirlen)) {
3915 lstrcpyW((LPWSTR)out, driverdir);
3923 /* write the filename */
3924 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3925 if ((out) && (outlen >= size)) {
3926 lstrcpyW((LPWSTR)out, ptr);
3933 ptr += lstrlenW(ptr)+1;
3934 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3937 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3939 /* write the multisz-termination */
3940 if (type == REG_MULTI_SZ) {
3941 size = sizeof(WCHAR);
3944 if (out && (outlen >= size)) {
3945 memset (out, 0, size);
3951 /*****************************************************************************
3952 * WINSPOOL_GetStringFromReg
3954 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3955 * String is stored as unicode.
3957 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3958 DWORD buflen, DWORD *needed)
3960 DWORD sz = buflen, type;
3963 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3964 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3965 WARN("Got ret = %d\n", ret);
3969 /* add space for terminating '\0' */
3970 sz += sizeof(WCHAR);
3974 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3979 /*****************************************************************************
3980 * WINSPOOL_GetDefaultDevMode
3982 * Get a default DevMode values for wineps.
3986 static void WINSPOOL_GetDefaultDevMode(
3988 DWORD buflen, DWORD *needed)
3991 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3993 /* fill default DEVMODE - should be read from ppd... */
3994 ZeroMemory( &dm, sizeof(dm) );
3995 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3996 dm.dmSpecVersion = DM_SPECVERSION;
3997 dm.dmDriverVersion = 1;
3998 dm.dmSize = sizeof(DEVMODEW);
3999 dm.dmDriverExtra = 0;
4001 DM_ORIENTATION | DM_PAPERSIZE |
4002 DM_PAPERLENGTH | DM_PAPERWIDTH |
4005 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
4006 DM_YRESOLUTION | DM_TTOPTION;
4008 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
4009 dm.u1.s1.dmPaperSize = DMPAPER_A4;
4010 dm.u1.s1.dmPaperLength = 2970;
4011 dm.u1.s1.dmPaperWidth = 2100;
4013 dm.u1.s1.dmScale = 100;
4014 dm.u1.s1.dmCopies = 1;
4015 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
4016 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
4019 dm.dmYResolution = 300; /* 300dpi */
4020 dm.dmTTOption = DMTT_BITMAP;
4023 /* dm.dmLogPixels */
4024 /* dm.dmBitsPerPel */
4025 /* dm.dmPelsWidth */
4026 /* dm.dmPelsHeight */
4027 /* dm.u2.dmDisplayFlags */
4028 /* dm.dmDisplayFrequency */
4029 /* dm.dmICMMethod */
4030 /* dm.dmICMIntent */
4031 /* dm.dmMediaType */
4032 /* dm.dmDitherType */
4033 /* dm.dmReserved1 */
4034 /* dm.dmReserved2 */
4035 /* dm.dmPanningWidth */
4036 /* dm.dmPanningHeight */
4038 if(buflen >= sizeof(DEVMODEW))
4039 memcpy(ptr, &dm, sizeof(DEVMODEW));
4040 *needed = sizeof(DEVMODEW);
4043 /*****************************************************************************
4044 * WINSPOOL_GetDevModeFromReg
4046 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4047 * DevMode is stored either as unicode or ascii.
4049 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4051 DWORD buflen, DWORD *needed)
4053 DWORD sz = buflen, type;
4056 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4057 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4058 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4059 if (sz < sizeof(DEVMODEA))
4061 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4064 /* ensures that dmSize is not erratically bogus if registry is invalid */
4065 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4066 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4067 sz += (CCHDEVICENAME + CCHFORMNAME);
4068 if (ptr && (buflen >= sz)) {
4069 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4070 memcpy(ptr, dmW, sz);
4071 HeapFree(GetProcessHeap(),0,dmW);
4077 /*********************************************************************
4078 * WINSPOOL_GetPrinter_1
4080 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4082 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4083 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4085 DWORD size, left = cbBuf;
4086 BOOL space = (cbBuf > 0);
4091 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4092 if(space && size <= left) {
4093 pi1->pName = (LPWSTR)ptr;
4101 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4102 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4103 if(space && size <= left) {
4104 pi1->pDescription = (LPWSTR)ptr;
4112 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4113 if(space && size <= left) {
4114 pi1->pComment = (LPWSTR)ptr;
4122 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4124 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4125 memset(pi1, 0, sizeof(*pi1));
4129 /*********************************************************************
4130 * WINSPOOL_GetPrinter_2
4132 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4134 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4135 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4137 DWORD size, left = cbBuf;
4138 BOOL space = (cbBuf > 0);
4143 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4144 if(space && size <= left) {
4145 pi2->pPrinterName = (LPWSTR)ptr;
4152 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4153 if(space && size <= left) {
4154 pi2->pShareName = (LPWSTR)ptr;
4161 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4162 if(space && size <= left) {
4163 pi2->pPortName = (LPWSTR)ptr;
4170 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4171 if(space && size <= left) {
4172 pi2->pDriverName = (LPWSTR)ptr;
4179 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4180 if(space && size <= left) {
4181 pi2->pComment = (LPWSTR)ptr;
4188 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4189 if(space && size <= left) {
4190 pi2->pLocation = (LPWSTR)ptr;
4197 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4198 if(space && size <= left) {
4199 pi2->pDevMode = (LPDEVMODEW)ptr;
4208 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4209 if(space && size <= left) {
4210 pi2->pDevMode = (LPDEVMODEW)ptr;
4217 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4218 if(space && size <= left) {
4219 pi2->pSepFile = (LPWSTR)ptr;
4226 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4227 if(space && size <= left) {
4228 pi2->pPrintProcessor = (LPWSTR)ptr;
4235 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4236 if(space && size <= left) {
4237 pi2->pDatatype = (LPWSTR)ptr;
4244 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4245 if(space && size <= left) {
4246 pi2->pParameters = (LPWSTR)ptr;
4254 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4255 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4256 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4257 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4258 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4261 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4262 memset(pi2, 0, sizeof(*pi2));
4267 /*********************************************************************
4268 * WINSPOOL_GetPrinter_4
4270 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4272 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4273 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4275 DWORD size, left = cbBuf;
4276 BOOL space = (cbBuf > 0);
4281 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4282 if(space && size <= left) {
4283 pi4->pPrinterName = (LPWSTR)ptr;
4291 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4294 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4295 memset(pi4, 0, sizeof(*pi4));
4300 /*********************************************************************
4301 * WINSPOOL_GetPrinter_5
4303 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4305 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4306 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4308 DWORD size, left = cbBuf;
4309 BOOL space = (cbBuf > 0);
4314 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4315 if(space && size <= left) {
4316 pi5->pPrinterName = (LPWSTR)ptr;
4323 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4324 if(space && size <= left) {
4325 pi5->pPortName = (LPWSTR)ptr;
4333 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4334 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4335 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4338 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4339 memset(pi5, 0, sizeof(*pi5));
4344 /*********************************************************************
4345 * WINSPOOL_GetPrinter_7
4347 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4349 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4350 DWORD cbBuf, LPDWORD pcbNeeded)
4352 DWORD size, left = cbBuf;
4353 BOOL space = (cbBuf > 0);
4358 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4361 size = sizeof(pi7->pszObjectGUID);
4363 if (space && size <= left) {
4364 pi7->pszObjectGUID = (LPWSTR)ptr;
4371 /* We do not have a Directory Service */
4372 pi7->dwAction = DSPRINT_UNPUBLISH;
4375 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4376 memset(pi7, 0, sizeof(*pi7));
4381 /*********************************************************************
4382 * WINSPOOL_GetPrinter_9
4384 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4386 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4387 DWORD cbBuf, LPDWORD pcbNeeded)
4390 BOOL space = (cbBuf > 0);
4394 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4395 if(space && size <= cbBuf) {
4396 pi9->pDevMode = (LPDEVMODEW)buf;
4403 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4404 if(space && size <= cbBuf) {
4405 pi9->pDevMode = (LPDEVMODEW)buf;
4411 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4412 memset(pi9, 0, sizeof(*pi9));
4417 /*****************************************************************************
4418 * GetPrinterW [WINSPOOL.@]
4420 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4421 DWORD cbBuf, LPDWORD pcbNeeded)
4423 DWORD size, needed = 0, err;
4428 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4430 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4433 SetLastError( err );
4440 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4442 size = sizeof(PRINTER_INFO_2W);
4444 ptr = pPrinter + size;
4446 memset(pPrinter, 0, size);
4451 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4458 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4460 size = sizeof(PRINTER_INFO_4W);
4462 ptr = pPrinter + size;
4464 memset(pPrinter, 0, size);
4469 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4477 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4479 size = sizeof(PRINTER_INFO_5W);
4481 ptr = pPrinter + size;
4483 memset(pPrinter, 0, size);
4489 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4497 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4499 size = sizeof(PRINTER_INFO_6);
4500 if (size <= cbBuf) {
4501 /* FIXME: We do not update the status yet */
4502 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4514 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4516 size = sizeof(PRINTER_INFO_7W);
4517 if (size <= cbBuf) {
4518 ptr = pPrinter + size;
4520 memset(pPrinter, 0, size);
4526 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4533 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4534 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4538 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4540 size = sizeof(PRINTER_INFO_9W);
4542 ptr = pPrinter + size;
4544 memset(pPrinter, 0, size);
4550 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4557 FIXME("Unimplemented level %d\n", Level);
4558 SetLastError(ERROR_INVALID_LEVEL);
4559 RegCloseKey(hkeyPrinter);
4563 RegCloseKey(hkeyPrinter);
4565 TRACE("returning %d needed = %d\n", ret, needed);
4566 if(pcbNeeded) *pcbNeeded = needed;
4568 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4572 /*****************************************************************************
4573 * GetPrinterA [WINSPOOL.@]
4575 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4576 DWORD cbBuf, LPDWORD pcbNeeded)
4582 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4584 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4586 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4587 HeapFree(GetProcessHeap(), 0, buf);
4592 /*****************************************************************************
4593 * WINSPOOL_EnumPrintersW
4595 * Implementation of EnumPrintersW
4597 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4598 DWORD dwLevel, LPBYTE lpbPrinters,
4599 DWORD cbBuf, LPDWORD lpdwNeeded,
4600 LPDWORD lpdwReturned)
4603 HKEY hkeyPrinters, hkeyPrinter;
4604 WCHAR PrinterName[255];
4605 DWORD needed = 0, number = 0;
4606 DWORD used, i, left;
4610 memset(lpbPrinters, 0, cbBuf);
4616 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4617 if(dwType == PRINTER_ENUM_DEFAULT)
4620 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4621 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4622 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4624 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4630 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4631 FIXME("dwType = %08x\n", dwType);
4632 SetLastError(ERROR_INVALID_FLAGS);
4636 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4638 ERR("Can't create Printers key\n");
4642 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4643 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4644 RegCloseKey(hkeyPrinters);
4645 ERR("Can't query Printers key\n");
4648 TRACE("Found %d printers\n", number);
4652 used = number * sizeof(PRINTER_INFO_1W);
4655 used = number * sizeof(PRINTER_INFO_2W);
4658 used = number * sizeof(PRINTER_INFO_4W);
4661 used = number * sizeof(PRINTER_INFO_5W);
4665 SetLastError(ERROR_INVALID_LEVEL);
4666 RegCloseKey(hkeyPrinters);
4669 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4671 for(i = 0; i < number; i++) {
4672 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4674 ERR("Can't enum key number %d\n", i);
4675 RegCloseKey(hkeyPrinters);
4678 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4679 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4681 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4682 RegCloseKey(hkeyPrinters);
4687 buf = lpbPrinters + used;
4688 left = cbBuf - used;
4696 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4699 if(pi) pi += sizeof(PRINTER_INFO_1W);
4702 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4705 if(pi) pi += sizeof(PRINTER_INFO_2W);
4708 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4711 if(pi) pi += sizeof(PRINTER_INFO_4W);
4714 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4717 if(pi) pi += sizeof(PRINTER_INFO_5W);
4720 ERR("Shouldn't be here!\n");
4721 RegCloseKey(hkeyPrinter);
4722 RegCloseKey(hkeyPrinters);
4725 RegCloseKey(hkeyPrinter);
4727 RegCloseKey(hkeyPrinters);
4734 memset(lpbPrinters, 0, cbBuf);
4735 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4739 *lpdwReturned = number;
4740 SetLastError(ERROR_SUCCESS);
4745 /******************************************************************
4746 * EnumPrintersW [WINSPOOL.@]
4748 * Enumerates the available printers, print servers and print
4749 * providers, depending on the specified flags, name and level.
4753 * If level is set to 1:
4754 * Returns an array of PRINTER_INFO_1 data structures in the
4755 * lpbPrinters buffer.
4757 * If level is set to 2:
4758 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4759 * Returns an array of PRINTER_INFO_2 data structures in the
4760 * lpbPrinters buffer. Note that according to MSDN also an
4761 * OpenPrinter should be performed on every remote printer.
4763 * If level is set to 4 (officially WinNT only):
4764 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4765 * Fast: Only the registry is queried to retrieve printer names,
4766 * no connection to the driver is made.
4767 * Returns an array of PRINTER_INFO_4 data structures in the
4768 * lpbPrinters buffer.
4770 * If level is set to 5 (officially WinNT4/Win9x only):
4771 * Fast: Only the registry is queried to retrieve printer names,
4772 * no connection to the driver is made.
4773 * Returns an array of PRINTER_INFO_5 data structures in the
4774 * lpbPrinters buffer.
4776 * If level set to 3 or 6+:
4777 * returns zero (failure!)
4779 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4783 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4784 * - Only levels 2, 4 and 5 are implemented at the moment.
4785 * - 16-bit printer drivers are not enumerated.
4786 * - Returned amount of bytes used/needed does not match the real Windoze
4787 * implementation (as in this implementation, all strings are part
4788 * of the buffer, whereas Win32 keeps them somewhere else)
4789 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4792 * - In a regular Wine installation, no registry settings for printers
4793 * exist, which makes this function return an empty list.
4795 BOOL WINAPI EnumPrintersW(
4796 DWORD dwType, /* [in] Types of print objects to enumerate */
4797 LPWSTR lpszName, /* [in] name of objects to enumerate */
4798 DWORD dwLevel, /* [in] type of printer info structure */
4799 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4800 DWORD cbBuf, /* [in] max size of buffer in bytes */
4801 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4802 LPDWORD lpdwReturned /* [out] number of entries returned */
4805 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4806 lpdwNeeded, lpdwReturned);
4809 /******************************************************************
4810 * EnumPrintersA [WINSPOOL.@]
4815 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4816 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4819 UNICODE_STRING pNameU;
4823 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4824 pPrinters, cbBuf, pcbNeeded, pcReturned);
4826 pNameW = asciitounicode(&pNameU, pName);
4828 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4829 MS Office need this */
4830 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4832 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4834 RtlFreeUnicodeString(&pNameU);
4836 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4838 HeapFree(GetProcessHeap(), 0, pPrintersW);
4842 /*****************************************************************************
4843 * WINSPOOL_GetDriverInfoFromReg [internal]
4845 * Enters the information from the registry into the DRIVER_INFO struct
4848 * zero if the printer driver does not exist in the registry
4849 * (only if Level > 1) otherwise nonzero
4851 static BOOL WINSPOOL_GetDriverInfoFromReg(
4854 const printenv_t * env,
4856 LPBYTE ptr, /* DRIVER_INFO */
4857 LPBYTE pDriverStrings, /* strings buffer */
4858 DWORD cbBuf, /* size of string buffer */
4859 LPDWORD pcbNeeded) /* space needed for str. */
4863 WCHAR driverdir[MAX_PATH];
4865 LPBYTE strPtr = pDriverStrings;
4866 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4868 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4869 debugstr_w(DriverName), env,
4870 Level, di, pDriverStrings, cbBuf);
4872 if (di) ZeroMemory(di, di_sizeof[Level]);
4874 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4875 if (*pcbNeeded <= cbBuf)
4876 strcpyW((LPWSTR)strPtr, DriverName);
4878 /* pName for level 1 has a different offset! */
4880 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4884 /* .cVersion and .pName for level > 1 */
4886 di->cVersion = env->driverversion;
4887 di->pName = (LPWSTR) strPtr;
4888 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4891 /* Reserve Space for the largest subdir and a Backslash*/
4892 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4893 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4894 /* Should never Fail */
4897 lstrcatW(driverdir, env->versionsubdir);
4898 lstrcatW(driverdir, backslashW);
4900 /* dirlen must not include the terminating zero */
4901 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4903 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4904 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4905 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4910 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4913 if (*pcbNeeded <= cbBuf) {
4914 lstrcpyW((LPWSTR)strPtr, env->envname);
4915 if (di) di->pEnvironment = (LPWSTR)strPtr;
4916 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4919 /* .pDriverPath is the Graphics rendering engine.
4920 The full Path is required to avoid a crash in some apps */
4921 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4923 if (*pcbNeeded <= cbBuf)
4924 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4926 if (di) di->pDriverPath = (LPWSTR)strPtr;
4927 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4930 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4931 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4933 if (*pcbNeeded <= cbBuf)
4934 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4936 if (di) di->pDataFile = (LPWSTR)strPtr;
4937 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4940 /* .pConfigFile is the Driver user Interface */
4941 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4943 if (*pcbNeeded <= cbBuf)
4944 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4946 if (di) di->pConfigFile = (LPWSTR)strPtr;
4947 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4951 RegCloseKey(hkeyDriver);
4952 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4957 RegCloseKey(hkeyDriver);
4958 FIXME("level 5: incomplete\n");
4963 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4965 if (*pcbNeeded <= cbBuf)
4966 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4968 if (di) di->pHelpFile = (LPWSTR)strPtr;
4969 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4972 /* .pDependentFiles */
4973 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4975 if (*pcbNeeded <= cbBuf)
4976 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4978 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4979 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4981 else if (GetVersion() & 0x80000000) {
4982 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4983 size = 2 * sizeof(WCHAR);
4985 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4987 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4988 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4991 /* .pMonitorName is the optional Language Monitor */
4992 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4994 if (*pcbNeeded <= cbBuf)
4995 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4997 if (di) di->pMonitorName = (LPWSTR)strPtr;
4998 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5001 /* .pDefaultDataType */
5002 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
5004 if(*pcbNeeded <= cbBuf)
5005 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
5007 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
5008 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5012 RegCloseKey(hkeyDriver);
5013 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5017 /* .pszzPreviousNames */
5018 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
5020 if(*pcbNeeded <= cbBuf)
5021 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
5023 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
5024 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5028 RegCloseKey(hkeyDriver);
5029 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5033 /* support is missing, but not important enough for a FIXME */
5034 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5037 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5039 if(*pcbNeeded <= cbBuf)
5040 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5042 if (di) di->pszMfgName = (LPWSTR)strPtr;
5043 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5047 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5049 if(*pcbNeeded <= cbBuf)
5050 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5052 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5053 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5056 /* .pszHardwareID */
5057 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5059 if(*pcbNeeded <= cbBuf)
5060 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5062 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5063 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5067 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5069 if(*pcbNeeded <= cbBuf)
5070 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5072 if (di) di->pszProvider = (LPWSTR)strPtr;
5073 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5077 RegCloseKey(hkeyDriver);
5081 /* support is missing, but not important enough for a FIXME */
5082 TRACE("level 8: incomplete\n");
5084 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5085 RegCloseKey(hkeyDriver);
5089 /*****************************************************************************
5090 * GetPrinterDriverW [WINSPOOL.@]
5092 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5093 DWORD Level, LPBYTE pDriverInfo,
5094 DWORD cbBuf, LPDWORD pcbNeeded)
5097 WCHAR DriverName[100];
5098 DWORD ret, type, size, needed = 0;
5100 HKEY hkeyPrinter, hkeyDrivers;
5101 const printenv_t * env;
5103 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5104 Level,pDriverInfo,cbBuf, pcbNeeded);
5107 ZeroMemory(pDriverInfo, cbBuf);
5109 if (!(name = get_opened_printer_name(hPrinter))) {
5110 SetLastError(ERROR_INVALID_HANDLE);
5114 if (Level < 1 || Level == 7 || Level > 8) {
5115 SetLastError(ERROR_INVALID_LEVEL);
5119 env = validate_envW(pEnvironment);
5120 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5122 ret = open_printer_reg_key( name, &hkeyPrinter );
5125 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5126 SetLastError( ret );
5130 size = sizeof(DriverName);
5132 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5133 (LPBYTE)DriverName, &size);
5134 RegCloseKey(hkeyPrinter);
5135 if(ret != ERROR_SUCCESS) {
5136 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5140 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5142 ERR("Can't create Drivers key\n");
5146 size = di_sizeof[Level];
5147 if ((size <= cbBuf) && pDriverInfo)
5148 ptr = pDriverInfo + size;
5150 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5151 env, Level, pDriverInfo, ptr,
5152 (cbBuf < size) ? 0 : cbBuf - size,
5154 RegCloseKey(hkeyDrivers);
5158 RegCloseKey(hkeyDrivers);
5160 if(pcbNeeded) *pcbNeeded = size + needed;
5161 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5162 if(cbBuf >= size + needed) return TRUE;
5163 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5167 /*****************************************************************************
5168 * GetPrinterDriverA [WINSPOOL.@]
5170 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5171 DWORD Level, LPBYTE pDriverInfo,
5172 DWORD cbBuf, LPDWORD pcbNeeded)
5175 UNICODE_STRING pEnvW;
5181 ZeroMemory(pDriverInfo, cbBuf);
5182 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5185 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5186 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5189 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5191 HeapFree(GetProcessHeap(), 0, buf);
5193 RtlFreeUnicodeString(&pEnvW);
5197 /*****************************************************************************
5198 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5200 * Return the PATH for the Printer-Drivers (UNICODE)
5203 * pName [I] Servername (NT only) or NULL (local Computer)
5204 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5205 * Level [I] Structure-Level (must be 1)
5206 * pDriverDirectory [O] PTR to Buffer that receives the Result
5207 * cbBuf [I] Size of Buffer at pDriverDirectory
5208 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5209 * required for pDriverDirectory
5212 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5213 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5214 * if cbBuf is too small
5216 * Native Values returned in pDriverDirectory on Success:
5217 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5218 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5219 *| win9x(Windows 4.0): "%winsysdir%"
5221 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5224 *- Only NULL or "" is supported for pName
5227 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5228 DWORD Level, LPBYTE pDriverDirectory,
5229 DWORD cbBuf, LPDWORD pcbNeeded)
5231 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5232 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5234 if ((backend == NULL) && !load_backend()) return FALSE;
5237 /* (Level != 1) is ignored in win9x */
5238 SetLastError(ERROR_INVALID_LEVEL);
5241 if (pcbNeeded == NULL) {
5242 /* (pcbNeeded == NULL) is ignored in win9x */
5243 SetLastError(RPC_X_NULL_REF_POINTER);
5247 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5248 pDriverDirectory, cbBuf, pcbNeeded);
5253 /*****************************************************************************
5254 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5256 * Return the PATH for the Printer-Drivers (ANSI)
5258 * See GetPrinterDriverDirectoryW.
5261 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5264 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5265 DWORD Level, LPBYTE pDriverDirectory,
5266 DWORD cbBuf, LPDWORD pcbNeeded)
5268 UNICODE_STRING nameW, environmentW;
5271 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5272 WCHAR *driverDirectoryW = NULL;
5274 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5275 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5277 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5279 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5280 else nameW.Buffer = NULL;
5281 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5282 else environmentW.Buffer = NULL;
5284 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5285 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5288 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5289 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5291 *pcbNeeded = needed;
5292 ret = needed <= cbBuf;
5294 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5296 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5298 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5299 RtlFreeUnicodeString(&environmentW);
5300 RtlFreeUnicodeString(&nameW);
5305 /*****************************************************************************
5306 * AddPrinterDriverA [WINSPOOL.@]
5308 * See AddPrinterDriverW.
5311 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5313 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5314 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5317 /******************************************************************************
5318 * AddPrinterDriverW (WINSPOOL.@)
5320 * Install a Printer Driver
5323 * pName [I] Servername or NULL (local Computer)
5324 * level [I] Level for the supplied DRIVER_INFO_*W struct
5325 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5332 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5334 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5335 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5338 /*****************************************************************************
5339 * AddPrintProcessorA [WINSPOOL.@]
5341 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5342 LPSTR pPrintProcessorName)
5344 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5345 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5349 /*****************************************************************************
5350 * AddPrintProcessorW [WINSPOOL.@]
5352 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5353 LPWSTR pPrintProcessorName)
5355 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5356 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5360 /*****************************************************************************
5361 * AddPrintProvidorA [WINSPOOL.@]
5363 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5365 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5369 /*****************************************************************************
5370 * AddPrintProvidorW [WINSPOOL.@]
5372 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5374 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5378 /*****************************************************************************
5379 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5381 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5382 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5384 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5385 pDevModeOutput, pDevModeInput);
5389 /*****************************************************************************
5390 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5392 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5393 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5395 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5396 pDevModeOutput, pDevModeInput);
5400 /*****************************************************************************
5401 * PrinterProperties [WINSPOOL.@]
5403 * Displays a dialog to set the properties of the printer.
5406 * nonzero on success or zero on failure
5409 * implemented as stub only
5411 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5412 HANDLE hPrinter /* [in] handle to printer object */
5414 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5415 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5419 /*****************************************************************************
5420 * EnumJobsA [WINSPOOL.@]
5423 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5424 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5427 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5428 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5430 if(pcbNeeded) *pcbNeeded = 0;
5431 if(pcReturned) *pcReturned = 0;
5436 /*****************************************************************************
5437 * EnumJobsW [WINSPOOL.@]
5440 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5441 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5444 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5445 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5447 if(pcbNeeded) *pcbNeeded = 0;
5448 if(pcReturned) *pcReturned = 0;
5452 /*****************************************************************************
5453 * WINSPOOL_EnumPrinterDrivers [internal]
5455 * Delivers information about all printer drivers installed on the
5456 * localhost or a given server
5459 * nonzero on success or zero on failure. If the buffer for the returned
5460 * information is too small the function will return an error
5463 * - only implemented for localhost, foreign hosts will return an error
5465 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5466 DWORD Level, LPBYTE pDriverInfo,
5468 DWORD cbBuf, LPDWORD pcbNeeded,
5469 LPDWORD pcFound, DWORD data_offset)
5473 const printenv_t * env;
5475 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5476 debugstr_w(pName), debugstr_w(pEnvironment),
5477 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5479 env = validate_envW(pEnvironment);
5480 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5484 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5486 ERR("Can't open Drivers key\n");
5490 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5491 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5492 RegCloseKey(hkeyDrivers);
5493 ERR("Can't query Drivers key\n");
5496 TRACE("Found %d Drivers\n", *pcFound);
5498 /* get size of single struct
5499 * unicode and ascii structure have the same size
5501 size = di_sizeof[Level];
5503 if (data_offset == 0)
5504 data_offset = size * (*pcFound);
5505 *pcbNeeded = data_offset;
5507 for( i = 0; i < *pcFound; i++) {
5508 WCHAR DriverNameW[255];
5509 PBYTE table_ptr = NULL;
5510 PBYTE data_ptr = NULL;
5513 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5515 ERR("Can't enum key number %d\n", i);
5516 RegCloseKey(hkeyDrivers);
5520 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5521 table_ptr = pDriverInfo + (driver_index + i) * size;
5522 if (pDriverInfo && *pcbNeeded <= cbBuf)
5523 data_ptr = pDriverInfo + *pcbNeeded;
5525 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5526 env, Level, table_ptr, data_ptr,
5527 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5529 RegCloseKey(hkeyDrivers);
5533 *pcbNeeded += needed;
5536 RegCloseKey(hkeyDrivers);
5538 if(cbBuf < *pcbNeeded){
5539 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5546 /*****************************************************************************
5547 * EnumPrinterDriversW [WINSPOOL.@]
5549 * see function EnumPrinterDrivers for RETURNS, BUGS
5551 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5552 LPBYTE pDriverInfo, DWORD cbBuf,
5553 LPDWORD pcbNeeded, LPDWORD pcReturned)
5555 static const WCHAR allW[] = {'a','l','l',0};
5559 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5561 SetLastError(RPC_X_NULL_REF_POINTER);
5565 /* check for local drivers */
5566 if((pName) && (pName[0])) {
5567 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5568 SetLastError(ERROR_ACCESS_DENIED);
5572 /* check input parameter */
5573 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5574 SetLastError(ERROR_INVALID_LEVEL);
5578 if(pDriverInfo && cbBuf > 0)
5579 memset( pDriverInfo, 0, cbBuf);
5581 /* Exception: pull all printers */
5582 if (pEnvironment && !strcmpW(pEnvironment, allW))
5584 DWORD i, needed, bufsize = cbBuf;
5585 DWORD total_found = 0;
5588 /* Precompute the overall total; we need this to know
5589 where pointers end and data begins (i.e. data_offset) */
5590 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5593 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5594 NULL, 0, 0, &needed, &found, 0);
5595 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5596 total_found += found;
5599 data_offset = di_sizeof[Level] * total_found;
5604 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5607 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5608 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5609 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5611 *pcReturned += found;
5612 *pcbNeeded = needed;
5613 data_offset = needed;
5614 total_found += found;
5619 /* Normal behavior */
5620 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5621 0, cbBuf, pcbNeeded, &found, 0);
5623 *pcReturned = found;
5628 /*****************************************************************************
5629 * EnumPrinterDriversA [WINSPOOL.@]
5631 * see function EnumPrinterDrivers for RETURNS, BUGS
5633 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5634 LPBYTE pDriverInfo, DWORD cbBuf,
5635 LPDWORD pcbNeeded, LPDWORD pcReturned)
5638 UNICODE_STRING pNameW, pEnvironmentW;
5639 PWSTR pwstrNameW, pwstrEnvironmentW;
5643 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5645 pwstrNameW = asciitounicode(&pNameW, pName);
5646 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5648 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5649 buf, cbBuf, pcbNeeded, pcReturned);
5651 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5653 HeapFree(GetProcessHeap(), 0, buf);
5655 RtlFreeUnicodeString(&pNameW);
5656 RtlFreeUnicodeString(&pEnvironmentW);
5661 /******************************************************************************
5662 * EnumPortsA (WINSPOOL.@)
5667 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5668 LPDWORD pcbNeeded, LPDWORD pcReturned)
5671 LPBYTE bufferW = NULL;
5672 LPWSTR nameW = NULL;
5674 DWORD numentries = 0;
5677 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5678 cbBuf, pcbNeeded, pcReturned);
5680 /* convert servername to unicode */
5682 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5683 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5684 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5686 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5687 needed = cbBuf * sizeof(WCHAR);
5688 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5689 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5691 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5692 if (pcbNeeded) needed = *pcbNeeded;
5693 /* HeapReAlloc return NULL, when bufferW was NULL */
5694 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5695 HeapAlloc(GetProcessHeap(), 0, needed);
5697 /* Try again with the large Buffer */
5698 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5700 needed = pcbNeeded ? *pcbNeeded : 0;
5701 numentries = pcReturned ? *pcReturned : 0;
5704 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5705 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5708 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5709 DWORD entrysize = 0;
5712 LPPORT_INFO_2W pi2w;
5713 LPPORT_INFO_2A pi2a;
5716 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5718 /* First pass: calculate the size for all Entries */
5719 pi2w = (LPPORT_INFO_2W) bufferW;
5720 pi2a = (LPPORT_INFO_2A) pPorts;
5722 while (index < numentries) {
5724 needed += entrysize; /* PORT_INFO_?A */
5725 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5727 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5728 NULL, 0, NULL, NULL);
5730 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5731 NULL, 0, NULL, NULL);
5732 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5733 NULL, 0, NULL, NULL);
5735 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5736 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5737 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5740 /* check for errors and quit on failure */
5741 if (cbBuf < needed) {
5742 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5746 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5747 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5748 cbBuf -= len ; /* free Bytes in the user-Buffer */
5749 pi2w = (LPPORT_INFO_2W) bufferW;
5750 pi2a = (LPPORT_INFO_2A) pPorts;
5752 /* Second Pass: Fill the User Buffer (if we have one) */
5753 while ((index < numentries) && pPorts) {
5755 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5756 pi2a->pPortName = ptr;
5757 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5758 ptr, cbBuf , NULL, NULL);
5762 pi2a->pMonitorName = ptr;
5763 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5764 ptr, cbBuf, NULL, NULL);
5768 pi2a->pDescription = ptr;
5769 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5770 ptr, cbBuf, NULL, NULL);
5774 pi2a->fPortType = pi2w->fPortType;
5775 pi2a->Reserved = 0; /* documented: "must be zero" */
5778 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5779 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5780 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5785 if (pcbNeeded) *pcbNeeded = needed;
5786 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5788 HeapFree(GetProcessHeap(), 0, nameW);
5789 HeapFree(GetProcessHeap(), 0, bufferW);
5791 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5792 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5798 /******************************************************************************
5799 * EnumPortsW (WINSPOOL.@)
5801 * Enumerate available Ports
5804 * pName [I] Servername or NULL (local Computer)
5805 * Level [I] Structure-Level (1 or 2)
5806 * pPorts [O] PTR to Buffer that receives the Result
5807 * cbBuf [I] Size of Buffer at pPorts
5808 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5809 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5813 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5816 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5819 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5820 cbBuf, pcbNeeded, pcReturned);
5822 if ((backend == NULL) && !load_backend()) return FALSE;
5824 /* Level is not checked in win9x */
5825 if (!Level || (Level > 2)) {
5826 WARN("level (%d) is ignored in win9x\n", Level);
5827 SetLastError(ERROR_INVALID_LEVEL);
5830 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5831 SetLastError(RPC_X_NULL_REF_POINTER);
5835 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5838 /******************************************************************************
5839 * GetDefaultPrinterW (WINSPOOL.@)
5842 * This function must read the value from data 'device' of key
5843 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5845 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5849 WCHAR *buffer, *ptr;
5853 SetLastError(ERROR_INVALID_PARAMETER);
5857 /* make the buffer big enough for the stuff from the profile/registry,
5858 * the content must fit into the local buffer to compute the correct
5859 * size even if the extern buffer is too small or not given.
5860 * (20 for ,driver,port) */
5862 len = max(100, (insize + 20));
5863 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5865 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5867 SetLastError (ERROR_FILE_NOT_FOUND);
5871 TRACE("%s\n", debugstr_w(buffer));
5873 if ((ptr = strchrW(buffer, ',')) == NULL)
5875 SetLastError(ERROR_INVALID_NAME);
5881 *namesize = strlenW(buffer) + 1;
5882 if(!name || (*namesize > insize))
5884 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5888 strcpyW(name, buffer);
5891 HeapFree( GetProcessHeap(), 0, buffer);
5896 /******************************************************************************
5897 * GetDefaultPrinterA (WINSPOOL.@)
5899 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5903 WCHAR *bufferW = NULL;
5907 SetLastError(ERROR_INVALID_PARAMETER);
5911 if(name && *namesize) {
5913 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5916 if(!GetDefaultPrinterW( bufferW, namesize)) {
5921 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5925 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5928 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5931 HeapFree( GetProcessHeap(), 0, bufferW);
5936 /******************************************************************************
5937 * SetDefaultPrinterW (WINSPOOL.204)
5939 * Set the Name of the Default Printer
5942 * pszPrinter [I] Name of the Printer or NULL
5949 * When the Parameter is NULL or points to an Empty String and
5950 * a Default Printer was already present, then this Function changes nothing.
5951 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5952 * the First enumerated local Printer is used.
5955 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5957 WCHAR default_printer[MAX_PATH];
5958 LPWSTR buffer = NULL;
5964 TRACE("(%s)\n", debugstr_w(pszPrinter));
5965 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5967 default_printer[0] = '\0';
5968 size = sizeof(default_printer)/sizeof(WCHAR);
5970 /* if we have a default Printer, do nothing. */
5971 if (GetDefaultPrinterW(default_printer, &size))
5975 /* we have no default Printer: search local Printers and use the first */
5976 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5978 default_printer[0] = '\0';
5979 size = sizeof(default_printer)/sizeof(WCHAR);
5980 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5982 pszPrinter = default_printer;
5983 TRACE("using %s\n", debugstr_w(pszPrinter));
5988 if (pszPrinter == NULL) {
5989 TRACE("no local printer found\n");
5990 SetLastError(ERROR_FILE_NOT_FOUND);
5995 /* "pszPrinter" is never empty or NULL here. */
5996 namelen = lstrlenW(pszPrinter);
5997 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5998 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
6000 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
6001 HeapFree(GetProcessHeap(), 0, buffer);
6002 SetLastError(ERROR_FILE_NOT_FOUND);
6006 /* read the devices entry for the printer (driver,port) to build the string for the
6007 default device entry (printer,driver,port) */
6008 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
6009 buffer[namelen] = ',';
6010 namelen++; /* move index to the start of the driver */
6012 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
6013 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
6015 TRACE("set device to %s\n", debugstr_w(buffer));
6017 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
6018 TRACE("failed to set the device entry: %d\n", GetLastError());
6019 lres = ERROR_INVALID_PRINTER_NAME;
6022 /* remove the next section, when INIFileMapping is implemented */
6025 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
6026 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6033 if (lres != ERROR_FILE_NOT_FOUND)
6034 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6036 SetLastError(ERROR_INVALID_PRINTER_NAME);
6040 HeapFree(GetProcessHeap(), 0, buffer);
6041 return (lres == ERROR_SUCCESS);
6044 /******************************************************************************
6045 * SetDefaultPrinterA (WINSPOOL.202)
6047 * See SetDefaultPrinterW.
6050 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6052 LPWSTR bufferW = NULL;
6055 TRACE("(%s)\n", debugstr_a(pszPrinter));
6057 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6058 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6059 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6061 res = SetDefaultPrinterW(bufferW);
6062 HeapFree(GetProcessHeap(), 0, bufferW);
6066 /******************************************************************************
6067 * SetPrinterDataExA (WINSPOOL.@)
6069 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6070 LPCSTR pValueName, DWORD Type,
6071 LPBYTE pData, DWORD cbData)
6073 HKEY hkeyPrinter, hkeySubkey;
6076 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6077 debugstr_a(pValueName), Type, pData, cbData);
6079 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6083 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6085 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6086 RegCloseKey(hkeyPrinter);
6089 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6090 RegCloseKey(hkeySubkey);
6091 RegCloseKey(hkeyPrinter);
6095 /******************************************************************************
6096 * SetPrinterDataExW (WINSPOOL.@)
6098 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6099 LPCWSTR pValueName, DWORD Type,
6100 LPBYTE pData, DWORD cbData)
6102 HKEY hkeyPrinter, hkeySubkey;
6105 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6106 debugstr_w(pValueName), Type, pData, cbData);
6108 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6112 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6114 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6115 RegCloseKey(hkeyPrinter);
6118 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6119 RegCloseKey(hkeySubkey);
6120 RegCloseKey(hkeyPrinter);
6124 /******************************************************************************
6125 * SetPrinterDataA (WINSPOOL.@)
6127 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6128 LPBYTE pData, DWORD cbData)
6130 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6134 /******************************************************************************
6135 * SetPrinterDataW (WINSPOOL.@)
6137 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6138 LPBYTE pData, DWORD cbData)
6140 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6144 /******************************************************************************
6145 * GetPrinterDataExA (WINSPOOL.@)
6147 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6148 LPCSTR pValueName, LPDWORD pType,
6149 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6151 opened_printer_t *printer;
6152 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6155 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6156 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6158 printer = get_opened_printer(hPrinter);
6159 if(!printer) return ERROR_INVALID_HANDLE;
6161 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6162 if (ret) return ret;
6164 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6166 if (printer->name) {
6168 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6170 RegCloseKey(hkeyPrinters);
6173 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6174 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6175 RegCloseKey(hkeyPrinter);
6176 RegCloseKey(hkeyPrinters);
6181 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6182 0, pType, pData, pcbNeeded);
6184 if (!ret && !pData) ret = ERROR_MORE_DATA;
6186 RegCloseKey(hkeySubkey);
6187 RegCloseKey(hkeyPrinter);
6188 RegCloseKey(hkeyPrinters);
6190 TRACE("--> %d\n", ret);
6194 /******************************************************************************
6195 * GetPrinterDataExW (WINSPOOL.@)
6197 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6198 LPCWSTR pValueName, LPDWORD pType,
6199 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6201 opened_printer_t *printer;
6202 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6205 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6206 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6208 printer = get_opened_printer(hPrinter);
6209 if(!printer) return ERROR_INVALID_HANDLE;
6211 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6212 if (ret) return ret;
6214 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6216 if (printer->name) {
6218 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6220 RegCloseKey(hkeyPrinters);
6223 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6224 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6225 RegCloseKey(hkeyPrinter);
6226 RegCloseKey(hkeyPrinters);
6231 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6232 0, pType, pData, pcbNeeded);
6234 if (!ret && !pData) ret = ERROR_MORE_DATA;
6236 RegCloseKey(hkeySubkey);
6237 RegCloseKey(hkeyPrinter);
6238 RegCloseKey(hkeyPrinters);
6240 TRACE("--> %d\n", ret);
6244 /******************************************************************************
6245 * GetPrinterDataA (WINSPOOL.@)
6247 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6248 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6250 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6251 pData, nSize, pcbNeeded);
6254 /******************************************************************************
6255 * GetPrinterDataW (WINSPOOL.@)
6257 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6258 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6260 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6261 pData, nSize, pcbNeeded);
6264 /*******************************************************************************
6265 * EnumPrinterDataExW [WINSPOOL.@]
6267 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6268 LPBYTE pEnumValues, DWORD cbEnumValues,
6269 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6271 HKEY hkPrinter, hkSubKey;
6272 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6273 cbValueNameLen, cbMaxValueLen, cbValueLen,
6278 PPRINTER_ENUM_VALUESW ppev;
6280 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6282 if (pKeyName == NULL || *pKeyName == 0)
6283 return ERROR_INVALID_PARAMETER;
6285 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6286 if (ret != ERROR_SUCCESS)
6288 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6293 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6294 if (ret != ERROR_SUCCESS)
6296 r = RegCloseKey (hkPrinter);
6297 if (r != ERROR_SUCCESS)
6298 WARN ("RegCloseKey returned %i\n", r);
6299 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6300 debugstr_w (pKeyName), ret);
6304 ret = RegCloseKey (hkPrinter);
6305 if (ret != ERROR_SUCCESS)
6307 ERR ("RegCloseKey returned %i\n", ret);
6308 r = RegCloseKey (hkSubKey);
6309 if (r != ERROR_SUCCESS)
6310 WARN ("RegCloseKey returned %i\n", r);
6314 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6315 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6316 if (ret != ERROR_SUCCESS)
6318 r = RegCloseKey (hkSubKey);
6319 if (r != ERROR_SUCCESS)
6320 WARN ("RegCloseKey returned %i\n", r);
6321 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6325 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6326 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6328 if (cValues == 0) /* empty key */
6330 r = RegCloseKey (hkSubKey);
6331 if (r != ERROR_SUCCESS)
6332 WARN ("RegCloseKey returned %i\n", r);
6333 *pcbEnumValues = *pnEnumValues = 0;
6334 return ERROR_SUCCESS;
6337 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6339 hHeap = GetProcessHeap ();
6342 ERR ("GetProcessHeap failed\n");
6343 r = RegCloseKey (hkSubKey);
6344 if (r != ERROR_SUCCESS)
6345 WARN ("RegCloseKey returned %i\n", r);
6346 return ERROR_OUTOFMEMORY;
6349 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6350 if (lpValueName == NULL)
6352 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6353 r = RegCloseKey (hkSubKey);
6354 if (r != ERROR_SUCCESS)
6355 WARN ("RegCloseKey returned %i\n", r);
6356 return ERROR_OUTOFMEMORY;
6359 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6360 if (lpValue == NULL)
6362 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6363 if (HeapFree (hHeap, 0, lpValueName) == 0)
6364 WARN ("HeapFree failed with code %i\n", GetLastError ());
6365 r = RegCloseKey (hkSubKey);
6366 if (r != ERROR_SUCCESS)
6367 WARN ("RegCloseKey returned %i\n", r);
6368 return ERROR_OUTOFMEMORY;
6371 TRACE ("pass 1: calculating buffer required for all names and values\n");
6373 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6375 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6377 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6379 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6380 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6381 NULL, NULL, lpValue, &cbValueLen);
6382 if (ret != ERROR_SUCCESS)
6384 if (HeapFree (hHeap, 0, lpValue) == 0)
6385 WARN ("HeapFree failed with code %i\n", GetLastError ());
6386 if (HeapFree (hHeap, 0, lpValueName) == 0)
6387 WARN ("HeapFree failed with code %i\n", GetLastError ());
6388 r = RegCloseKey (hkSubKey);
6389 if (r != ERROR_SUCCESS)
6390 WARN ("RegCloseKey returned %i\n", r);
6391 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6395 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6396 debugstr_w (lpValueName), dwIndex,
6397 cbValueNameLen + 1, cbValueLen);
6399 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6400 cbBufSize += cbValueLen;
6403 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6405 *pcbEnumValues = cbBufSize;
6406 *pnEnumValues = cValues;
6408 if (cbEnumValues < cbBufSize) /* buffer too small */
6410 if (HeapFree (hHeap, 0, lpValue) == 0)
6411 WARN ("HeapFree failed with code %i\n", GetLastError ());
6412 if (HeapFree (hHeap, 0, lpValueName) == 0)
6413 WARN ("HeapFree failed with code %i\n", GetLastError ());
6414 r = RegCloseKey (hkSubKey);
6415 if (r != ERROR_SUCCESS)
6416 WARN ("RegCloseKey returned %i\n", r);
6417 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6418 return ERROR_MORE_DATA;
6421 TRACE ("pass 2: copying all names and values to buffer\n");
6423 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6424 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6426 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6428 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6429 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6430 NULL, &dwType, lpValue, &cbValueLen);
6431 if (ret != ERROR_SUCCESS)
6433 if (HeapFree (hHeap, 0, lpValue) == 0)
6434 WARN ("HeapFree failed with code %i\n", GetLastError ());
6435 if (HeapFree (hHeap, 0, lpValueName) == 0)
6436 WARN ("HeapFree failed with code %i\n", GetLastError ());
6437 r = RegCloseKey (hkSubKey);
6438 if (r != ERROR_SUCCESS)
6439 WARN ("RegCloseKey returned %i\n", r);
6440 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6444 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6445 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6446 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6447 pEnumValues += cbValueNameLen;
6449 /* return # of *bytes* (including trailing \0), not # of chars */
6450 ppev[dwIndex].cbValueName = cbValueNameLen;
6452 ppev[dwIndex].dwType = dwType;
6454 memcpy (pEnumValues, lpValue, cbValueLen);
6455 ppev[dwIndex].pData = pEnumValues;
6456 pEnumValues += cbValueLen;
6458 ppev[dwIndex].cbData = cbValueLen;
6460 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6461 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6464 if (HeapFree (hHeap, 0, lpValue) == 0)
6466 ret = GetLastError ();
6467 ERR ("HeapFree failed with code %i\n", ret);
6468 if (HeapFree (hHeap, 0, lpValueName) == 0)
6469 WARN ("HeapFree failed with code %i\n", GetLastError ());
6470 r = RegCloseKey (hkSubKey);
6471 if (r != ERROR_SUCCESS)
6472 WARN ("RegCloseKey returned %i\n", r);
6476 if (HeapFree (hHeap, 0, lpValueName) == 0)
6478 ret = GetLastError ();
6479 ERR ("HeapFree failed with code %i\n", ret);
6480 r = RegCloseKey (hkSubKey);
6481 if (r != ERROR_SUCCESS)
6482 WARN ("RegCloseKey returned %i\n", r);
6486 ret = RegCloseKey (hkSubKey);
6487 if (ret != ERROR_SUCCESS)
6489 ERR ("RegCloseKey returned %i\n", ret);
6493 return ERROR_SUCCESS;
6496 /*******************************************************************************
6497 * EnumPrinterDataExA [WINSPOOL.@]
6499 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6500 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6501 * what Windows 2000 SP1 does.
6504 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6505 LPBYTE pEnumValues, DWORD cbEnumValues,
6506 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6510 DWORD ret, dwIndex, dwBufSize;
6514 TRACE ("%p %s\n", hPrinter, pKeyName);
6516 if (pKeyName == NULL || *pKeyName == 0)
6517 return ERROR_INVALID_PARAMETER;
6519 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6522 ret = GetLastError ();
6523 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6527 hHeap = GetProcessHeap ();
6530 ERR ("GetProcessHeap failed\n");
6531 return ERROR_OUTOFMEMORY;
6534 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6535 if (pKeyNameW == NULL)
6537 ERR ("Failed to allocate %i bytes from process heap\n",
6538 (LONG)(len * sizeof (WCHAR)));
6539 return ERROR_OUTOFMEMORY;
6542 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6544 ret = GetLastError ();
6545 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6546 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6547 WARN ("HeapFree failed with code %i\n", GetLastError ());
6551 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6552 pcbEnumValues, pnEnumValues);
6553 if (ret != ERROR_SUCCESS)
6555 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6556 WARN ("HeapFree failed with code %i\n", GetLastError ());
6557 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6561 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6563 ret = GetLastError ();
6564 ERR ("HeapFree failed with code %i\n", ret);
6568 if (*pnEnumValues == 0) /* empty key */
6569 return ERROR_SUCCESS;
6572 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6574 PPRINTER_ENUM_VALUESW ppev =
6575 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6577 if (dwBufSize < ppev->cbValueName)
6578 dwBufSize = ppev->cbValueName;
6580 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6581 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6582 dwBufSize = ppev->cbData;
6585 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6587 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6588 if (pBuffer == NULL)
6590 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6591 return ERROR_OUTOFMEMORY;
6594 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6596 PPRINTER_ENUM_VALUESW ppev =
6597 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6599 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6600 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6604 ret = GetLastError ();
6605 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6606 if (HeapFree (hHeap, 0, pBuffer) == 0)
6607 WARN ("HeapFree failed with code %i\n", GetLastError ());
6611 memcpy (ppev->pValueName, pBuffer, len);
6613 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6615 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6616 ppev->dwType != REG_MULTI_SZ)
6619 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6620 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6623 ret = GetLastError ();
6624 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6625 if (HeapFree (hHeap, 0, pBuffer) == 0)
6626 WARN ("HeapFree failed with code %i\n", GetLastError ());
6630 memcpy (ppev->pData, pBuffer, len);
6632 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6633 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6636 if (HeapFree (hHeap, 0, pBuffer) == 0)
6638 ret = GetLastError ();
6639 ERR ("HeapFree failed with code %i\n", ret);
6643 return ERROR_SUCCESS;
6646 /******************************************************************************
6647 * AbortPrinter (WINSPOOL.@)
6649 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6651 FIXME("(%p), stub!\n", hPrinter);
6655 /******************************************************************************
6656 * AddPortA (WINSPOOL.@)
6661 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6663 LPWSTR nameW = NULL;
6664 LPWSTR monitorW = NULL;
6668 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6671 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6672 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6673 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6677 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6678 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6679 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6681 res = AddPortW(nameW, hWnd, monitorW);
6682 HeapFree(GetProcessHeap(), 0, nameW);
6683 HeapFree(GetProcessHeap(), 0, monitorW);
6687 /******************************************************************************
6688 * AddPortW (WINSPOOL.@)
6690 * Add a Port for a specific Monitor
6693 * pName [I] Servername or NULL (local Computer)
6694 * hWnd [I] Handle to parent Window for the Dialog-Box
6695 * pMonitorName [I] Name of the Monitor that manage the Port
6702 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6704 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6706 if ((backend == NULL) && !load_backend()) return FALSE;
6708 if (!pMonitorName) {
6709 SetLastError(RPC_X_NULL_REF_POINTER);
6713 return backend->fpAddPort(pName, hWnd, pMonitorName);
6716 /******************************************************************************
6717 * AddPortExA (WINSPOOL.@)
6722 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6725 PORT_INFO_2A * pi2A;
6726 LPWSTR nameW = NULL;
6727 LPWSTR monitorW = NULL;
6731 pi2A = (PORT_INFO_2A *) pBuffer;
6733 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6734 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6736 if ((level < 1) || (level > 2)) {
6737 SetLastError(ERROR_INVALID_LEVEL);
6742 SetLastError(ERROR_INVALID_PARAMETER);
6747 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6748 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6749 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6753 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6754 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6755 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6758 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6760 if (pi2A->pPortName) {
6761 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6762 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6763 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6767 if (pi2A->pMonitorName) {
6768 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6769 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6770 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6773 if (pi2A->pDescription) {
6774 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6775 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6776 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6778 pi2W.fPortType = pi2A->fPortType;
6779 pi2W.Reserved = pi2A->Reserved;
6782 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6784 HeapFree(GetProcessHeap(), 0, nameW);
6785 HeapFree(GetProcessHeap(), 0, monitorW);
6786 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6787 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6788 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6793 /******************************************************************************
6794 * AddPortExW (WINSPOOL.@)
6796 * Add a Port for a specific Monitor, without presenting a user interface
6799 * pName [I] Servername or NULL (local Computer)
6800 * level [I] Structure-Level (1 or 2) for pBuffer
6801 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6802 * pMonitorName [I] Name of the Monitor that manage the Port
6809 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6813 pi2 = (PORT_INFO_2W *) pBuffer;
6815 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6816 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6817 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6818 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6820 if ((backend == NULL) && !load_backend()) return FALSE;
6822 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6823 SetLastError(ERROR_INVALID_PARAMETER);
6827 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6830 /******************************************************************************
6831 * AddPrinterConnectionA (WINSPOOL.@)
6833 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6835 FIXME("%s\n", debugstr_a(pName));
6839 /******************************************************************************
6840 * AddPrinterConnectionW (WINSPOOL.@)
6842 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6844 FIXME("%s\n", debugstr_w(pName));
6848 /******************************************************************************
6849 * AddPrinterDriverExW (WINSPOOL.@)
6851 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6854 * pName [I] Servername or NULL (local Computer)
6855 * level [I] Level for the supplied DRIVER_INFO_*W struct
6856 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6857 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6864 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6866 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6868 if ((backend == NULL) && !load_backend()) return FALSE;
6870 if (level < 2 || level == 5 || level == 7 || level > 8) {
6871 SetLastError(ERROR_INVALID_LEVEL);
6876 SetLastError(ERROR_INVALID_PARAMETER);
6880 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6883 /******************************************************************************
6884 * AddPrinterDriverExA (WINSPOOL.@)
6886 * See AddPrinterDriverExW.
6889 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6891 DRIVER_INFO_8A *diA;
6893 LPWSTR nameW = NULL;
6898 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6900 diA = (DRIVER_INFO_8A *) pDriverInfo;
6901 ZeroMemory(&diW, sizeof(diW));
6903 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6904 SetLastError(ERROR_INVALID_LEVEL);
6909 SetLastError(ERROR_INVALID_PARAMETER);
6913 /* convert servername to unicode */
6915 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6916 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6917 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6921 diW.cVersion = diA->cVersion;
6924 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6925 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6926 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6929 if (diA->pEnvironment) {
6930 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6931 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6932 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6935 if (diA->pDriverPath) {
6936 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6937 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6938 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6941 if (diA->pDataFile) {
6942 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6943 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6944 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6947 if (diA->pConfigFile) {
6948 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6949 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6950 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6953 if ((Level > 2) && diA->pDependentFiles) {
6954 lenA = multi_sz_lenA(diA->pDependentFiles);
6955 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6956 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6957 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6960 if ((Level > 2) && diA->pMonitorName) {
6961 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6962 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6963 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6966 if ((Level > 3) && diA->pDefaultDataType) {
6967 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6968 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6969 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6972 if ((Level > 3) && diA->pszzPreviousNames) {
6973 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6974 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6975 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6976 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6979 if ((Level > 5) && diA->pszMfgName) {
6980 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6981 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6982 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6985 if ((Level > 5) && diA->pszOEMUrl) {
6986 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6987 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6988 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6991 if ((Level > 5) && diA->pszHardwareID) {
6992 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6993 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6994 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6997 if ((Level > 5) && diA->pszProvider) {
6998 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6999 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7000 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
7004 FIXME("level %u is incomplete\n", Level);
7007 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
7008 TRACE("got %u with %u\n", res, GetLastError());
7009 HeapFree(GetProcessHeap(), 0, nameW);
7010 HeapFree(GetProcessHeap(), 0, diW.pName);
7011 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
7012 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
7013 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
7014 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
7015 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
7016 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
7017 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
7018 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
7019 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
7020 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
7021 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
7022 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
7024 TRACE("=> %u with %u\n", res, GetLastError());
7028 /******************************************************************************
7029 * ConfigurePortA (WINSPOOL.@)
7031 * See ConfigurePortW.
7034 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7036 LPWSTR nameW = NULL;
7037 LPWSTR portW = NULL;
7041 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7043 /* convert servername to unicode */
7045 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7046 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7047 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7050 /* convert portname to unicode */
7052 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7053 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7054 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7057 res = ConfigurePortW(nameW, hWnd, portW);
7058 HeapFree(GetProcessHeap(), 0, nameW);
7059 HeapFree(GetProcessHeap(), 0, portW);
7063 /******************************************************************************
7064 * ConfigurePortW (WINSPOOL.@)
7066 * Display the Configuration-Dialog for a specific Port
7069 * pName [I] Servername or NULL (local Computer)
7070 * hWnd [I] Handle to parent Window for the Dialog-Box
7071 * pPortName [I] Name of the Port, that should be configured
7078 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7081 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7083 if ((backend == NULL) && !load_backend()) return FALSE;
7086 SetLastError(RPC_X_NULL_REF_POINTER);
7090 return backend->fpConfigurePort(pName, hWnd, pPortName);
7093 /******************************************************************************
7094 * ConnectToPrinterDlg (WINSPOOL.@)
7096 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7098 FIXME("%p %x\n", hWnd, Flags);
7102 /******************************************************************************
7103 * DeletePrinterConnectionA (WINSPOOL.@)
7105 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7107 FIXME("%s\n", debugstr_a(pName));
7111 /******************************************************************************
7112 * DeletePrinterConnectionW (WINSPOOL.@)
7114 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7116 FIXME("%s\n", debugstr_w(pName));
7120 /******************************************************************************
7121 * DeletePrinterDriverExW (WINSPOOL.@)
7123 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7124 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7129 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7130 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7132 if(pName && pName[0])
7134 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7135 SetLastError(ERROR_INVALID_PARAMETER);
7141 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7142 SetLastError(ERROR_INVALID_PARAMETER);
7146 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7150 ERR("Can't open drivers key\n");
7154 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7157 RegCloseKey(hkey_drivers);
7162 /******************************************************************************
7163 * DeletePrinterDriverExA (WINSPOOL.@)
7165 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7166 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7168 UNICODE_STRING NameW, EnvW, DriverW;
7171 asciitounicode(&NameW, pName);
7172 asciitounicode(&EnvW, pEnvironment);
7173 asciitounicode(&DriverW, pDriverName);
7175 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7177 RtlFreeUnicodeString(&DriverW);
7178 RtlFreeUnicodeString(&EnvW);
7179 RtlFreeUnicodeString(&NameW);
7184 /******************************************************************************
7185 * DeletePrinterDataExW (WINSPOOL.@)
7187 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7190 FIXME("%p %s %s\n", hPrinter,
7191 debugstr_w(pKeyName), debugstr_w(pValueName));
7192 return ERROR_INVALID_PARAMETER;
7195 /******************************************************************************
7196 * DeletePrinterDataExA (WINSPOOL.@)
7198 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7201 FIXME("%p %s %s\n", hPrinter,
7202 debugstr_a(pKeyName), debugstr_a(pValueName));
7203 return ERROR_INVALID_PARAMETER;
7206 /******************************************************************************
7207 * DeletePrintProcessorA (WINSPOOL.@)
7209 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7211 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7212 debugstr_a(pPrintProcessorName));
7216 /******************************************************************************
7217 * DeletePrintProcessorW (WINSPOOL.@)
7219 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7221 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7222 debugstr_w(pPrintProcessorName));
7226 /******************************************************************************
7227 * DeletePrintProvidorA (WINSPOOL.@)
7229 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7231 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7232 debugstr_a(pPrintProviderName));
7236 /******************************************************************************
7237 * DeletePrintProvidorW (WINSPOOL.@)
7239 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7241 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7242 debugstr_w(pPrintProviderName));
7246 /******************************************************************************
7247 * EnumFormsA (WINSPOOL.@)
7249 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7250 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7252 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7253 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7257 /******************************************************************************
7258 * EnumFormsW (WINSPOOL.@)
7260 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7261 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7263 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7264 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7268 /*****************************************************************************
7269 * EnumMonitorsA [WINSPOOL.@]
7271 * See EnumMonitorsW.
7274 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7275 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7278 LPBYTE bufferW = NULL;
7279 LPWSTR nameW = NULL;
7281 DWORD numentries = 0;
7284 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7285 cbBuf, pcbNeeded, pcReturned);
7287 /* convert servername to unicode */
7289 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7290 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7291 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7293 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7294 needed = cbBuf * sizeof(WCHAR);
7295 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7296 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7298 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7299 if (pcbNeeded) needed = *pcbNeeded;
7300 /* HeapReAlloc return NULL, when bufferW was NULL */
7301 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7302 HeapAlloc(GetProcessHeap(), 0, needed);
7304 /* Try again with the large Buffer */
7305 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7307 numentries = pcReturned ? *pcReturned : 0;
7310 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7311 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7314 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7315 DWORD entrysize = 0;
7318 LPMONITOR_INFO_2W mi2w;
7319 LPMONITOR_INFO_2A mi2a;
7321 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7322 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7324 /* First pass: calculate the size for all Entries */
7325 mi2w = (LPMONITOR_INFO_2W) bufferW;
7326 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7328 while (index < numentries) {
7330 needed += entrysize; /* MONITOR_INFO_?A */
7331 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7333 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7334 NULL, 0, NULL, NULL);
7336 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7337 NULL, 0, NULL, NULL);
7338 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7339 NULL, 0, NULL, NULL);
7341 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7342 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7343 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7346 /* check for errors and quit on failure */
7347 if (cbBuf < needed) {
7348 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7352 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7353 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7354 cbBuf -= len ; /* free Bytes in the user-Buffer */
7355 mi2w = (LPMONITOR_INFO_2W) bufferW;
7356 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7358 /* Second Pass: Fill the User Buffer (if we have one) */
7359 while ((index < numentries) && pMonitors) {
7361 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7363 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7364 ptr, cbBuf , NULL, NULL);
7368 mi2a->pEnvironment = ptr;
7369 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7370 ptr, cbBuf, NULL, NULL);
7374 mi2a->pDLLName = ptr;
7375 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7376 ptr, cbBuf, NULL, NULL);
7380 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7381 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7382 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7386 if (pcbNeeded) *pcbNeeded = needed;
7387 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7389 HeapFree(GetProcessHeap(), 0, nameW);
7390 HeapFree(GetProcessHeap(), 0, bufferW);
7392 TRACE("returning %d with %d (%d byte for %d entries)\n",
7393 (res), GetLastError(), needed, numentries);
7399 /*****************************************************************************
7400 * EnumMonitorsW [WINSPOOL.@]
7402 * Enumerate available Port-Monitors
7405 * pName [I] Servername or NULL (local Computer)
7406 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7407 * pMonitors [O] PTR to Buffer that receives the Result
7408 * cbBuf [I] Size of Buffer at pMonitors
7409 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7410 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7414 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7417 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7418 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7421 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7422 cbBuf, pcbNeeded, pcReturned);
7424 if ((backend == NULL) && !load_backend()) return FALSE;
7426 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7427 SetLastError(RPC_X_NULL_REF_POINTER);
7431 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7434 /******************************************************************************
7435 * SpoolerInit (WINSPOOL.@)
7437 * Initialize the Spooler
7444 * The function fails on windows, when the spooler service is not running
7447 BOOL WINAPI SpoolerInit(void)
7450 if ((backend == NULL) && !load_backend()) return FALSE;
7454 /******************************************************************************
7455 * XcvDataW (WINSPOOL.@)
7457 * Execute commands in the Printmonitor DLL
7460 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7461 * pszDataName [i] Name of the command to execute
7462 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7463 * cbInputData [i] Size in Bytes of Buffer at pInputData
7464 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7465 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7466 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7467 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7474 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7475 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7477 * Minimal List of commands, that a Printmonitor DLL should support:
7479 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7480 *| "AddPort" : Add a Port
7481 *| "DeletePort": Delete a Port
7483 * Many Printmonitors support additional commands. Examples for localspl.dll:
7484 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7485 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7488 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7489 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7490 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7492 opened_printer_t *printer;
7494 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7495 pInputData, cbInputData, pOutputData,
7496 cbOutputData, pcbOutputNeeded, pdwStatus);
7498 if ((backend == NULL) && !load_backend()) return FALSE;
7500 printer = get_opened_printer(hXcv);
7501 if (!printer || (!printer->backend_printer)) {
7502 SetLastError(ERROR_INVALID_HANDLE);
7506 if (!pcbOutputNeeded) {
7507 SetLastError(ERROR_INVALID_PARAMETER);
7511 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7512 SetLastError(RPC_X_NULL_REF_POINTER);
7516 *pcbOutputNeeded = 0;
7518 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7519 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7523 /*****************************************************************************
7524 * EnumPrinterDataA [WINSPOOL.@]
7527 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7528 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7529 DWORD cbData, LPDWORD pcbData )
7531 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7532 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7533 return ERROR_NO_MORE_ITEMS;
7536 /*****************************************************************************
7537 * EnumPrinterDataW [WINSPOOL.@]
7540 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7541 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7542 DWORD cbData, LPDWORD pcbData )
7544 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7545 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7546 return ERROR_NO_MORE_ITEMS;
7549 /*****************************************************************************
7550 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7553 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7554 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7555 LPDWORD pcbNeeded, LPDWORD pcReturned)
7557 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7558 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7559 pcbNeeded, pcReturned);
7563 /*****************************************************************************
7564 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7567 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7568 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7569 LPDWORD pcbNeeded, LPDWORD pcReturned)
7571 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7572 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7573 pcbNeeded, pcReturned);
7577 /*****************************************************************************
7578 * EnumPrintProcessorsA [WINSPOOL.@]
7580 * See EnumPrintProcessorsW.
7583 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7584 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7587 LPBYTE bufferW = NULL;
7588 LPWSTR nameW = NULL;
7591 DWORD numentries = 0;
7594 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7595 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7597 /* convert names to unicode */
7599 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7600 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7601 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7604 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7605 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7606 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7609 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7610 needed = cbBuf * sizeof(WCHAR);
7611 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7612 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7614 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7615 if (pcbNeeded) needed = *pcbNeeded;
7616 /* HeapReAlloc return NULL, when bufferW was NULL */
7617 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7618 HeapAlloc(GetProcessHeap(), 0, needed);
7620 /* Try again with the large Buffer */
7621 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7623 numentries = pcReturned ? *pcReturned : 0;
7627 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7630 PPRINTPROCESSOR_INFO_1W ppiw;
7631 PPRINTPROCESSOR_INFO_1A ppia;
7633 /* First pass: calculate the size for all Entries */
7634 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7635 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7637 while (index < numentries) {
7639 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7640 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7642 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7643 NULL, 0, NULL, NULL);
7645 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7646 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7649 /* check for errors and quit on failure */
7650 if (cbBuf < needed) {
7651 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7656 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7657 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7658 cbBuf -= len ; /* free Bytes in the user-Buffer */
7659 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7660 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7662 /* Second Pass: Fill the User Buffer (if we have one) */
7663 while ((index < numentries) && pPPInfo) {
7665 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7667 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7668 ptr, cbBuf , NULL, NULL);
7672 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7673 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7678 if (pcbNeeded) *pcbNeeded = needed;
7679 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7681 HeapFree(GetProcessHeap(), 0, nameW);
7682 HeapFree(GetProcessHeap(), 0, envW);
7683 HeapFree(GetProcessHeap(), 0, bufferW);
7685 TRACE("returning %d with %d (%d byte for %d entries)\n",
7686 (res), GetLastError(), needed, numentries);
7691 /*****************************************************************************
7692 * EnumPrintProcessorsW [WINSPOOL.@]
7694 * Enumerate available Print Processors
7697 * pName [I] Servername or NULL (local Computer)
7698 * pEnvironment [I] Printing-Environment or NULL (Default)
7699 * Level [I] Structure-Level (Only 1 is allowed)
7700 * pPPInfo [O] PTR to Buffer that receives the Result
7701 * cbBuf [I] Size of Buffer at pPPInfo
7702 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7703 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7707 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7710 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7711 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7714 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7715 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7717 if ((backend == NULL) && !load_backend()) return FALSE;
7719 if (!pcbNeeded || !pcReturned) {
7720 SetLastError(RPC_X_NULL_REF_POINTER);
7724 if (!pPPInfo && (cbBuf > 0)) {
7725 SetLastError(ERROR_INVALID_USER_BUFFER);
7729 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7730 cbBuf, pcbNeeded, pcReturned);
7733 /*****************************************************************************
7734 * ExtDeviceMode [WINSPOOL.@]
7737 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7738 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7741 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7742 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7743 debugstr_a(pProfile), fMode);
7747 /*****************************************************************************
7748 * FindClosePrinterChangeNotification [WINSPOOL.@]
7751 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7753 FIXME("Stub: %p\n", hChange);
7757 /*****************************************************************************
7758 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7761 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7762 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7764 FIXME("Stub: %p %x %x %p\n",
7765 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7766 return INVALID_HANDLE_VALUE;
7769 /*****************************************************************************
7770 * FindNextPrinterChangeNotification [WINSPOOL.@]
7773 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7774 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7776 FIXME("Stub: %p %p %p %p\n",
7777 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7781 /*****************************************************************************
7782 * FreePrinterNotifyInfo [WINSPOOL.@]
7785 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7787 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7791 /*****************************************************************************
7794 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7795 * ansi depending on the unicode parameter.
7797 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7807 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7810 memcpy(ptr, str, *size);
7817 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7820 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7827 /*****************************************************************************
7830 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7831 LPDWORD pcbNeeded, BOOL unicode)
7833 DWORD size, left = cbBuf;
7834 BOOL space = (cbBuf > 0);
7841 ji1->JobId = job->job_id;
7844 string_to_buf(job->document_title, ptr, left, &size, unicode);
7845 if(space && size <= left)
7847 ji1->pDocument = (LPWSTR)ptr;
7855 if (job->printer_name)
7857 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7858 if(space && size <= left)
7860 ji1->pPrinterName = (LPWSTR)ptr;
7872 /*****************************************************************************
7875 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7876 LPDWORD pcbNeeded, BOOL unicode)
7878 DWORD size, left = cbBuf;
7880 BOOL space = (cbBuf > 0);
7882 LPDEVMODEA dmA = NULL;
7889 ji2->JobId = job->job_id;
7892 string_to_buf(job->document_title, ptr, left, &size, unicode);
7893 if(space && size <= left)
7895 ji2->pDocument = (LPWSTR)ptr;
7903 if (job->printer_name)
7905 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7906 if(space && size <= left)
7908 ji2->pPrinterName = (LPWSTR)ptr;
7921 dmA = DEVMODEdupWtoA(job->devmode);
7922 devmode = (LPDEVMODEW) dmA;
7923 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7927 devmode = job->devmode;
7928 size = devmode->dmSize + devmode->dmDriverExtra;
7932 FIXME("Can't convert DEVMODE W to A\n");
7935 /* align DEVMODE to a DWORD boundary */
7936 shift = (4 - (*pcbNeeded & 3)) & 3;
7942 memcpy(ptr, devmode, size-shift);
7943 ji2->pDevMode = (LPDEVMODEW)ptr;
7944 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7957 /*****************************************************************************
7960 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7961 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7964 DWORD needed = 0, size;
7968 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7970 EnterCriticalSection(&printer_handles_cs);
7971 job = get_job(hPrinter, JobId);
7978 size = sizeof(JOB_INFO_1W);
7983 memset(pJob, 0, size);
7987 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7992 size = sizeof(JOB_INFO_2W);
7997 memset(pJob, 0, size);
8001 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
8006 size = sizeof(JOB_INFO_3);
8010 memset(pJob, 0, size);
8019 SetLastError(ERROR_INVALID_LEVEL);
8023 *pcbNeeded = needed;
8025 LeaveCriticalSection(&printer_handles_cs);
8029 /*****************************************************************************
8030 * GetJobA [WINSPOOL.@]
8033 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8034 DWORD cbBuf, LPDWORD pcbNeeded)
8036 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8039 /*****************************************************************************
8040 * GetJobW [WINSPOOL.@]
8043 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8044 DWORD cbBuf, LPDWORD pcbNeeded)
8046 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8049 /*****************************************************************************
8052 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8055 char *unixname, *cmdA;
8057 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8063 if(!(unixname = wine_get_unix_file_name(filename)))
8066 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8067 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8068 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8070 TRACE("printing with: %s\n", cmdA);
8072 if((file_fd = open(unixname, O_RDONLY)) == -1)
8077 ERR("pipe() failed!\n");
8081 if ((pid = fork()) == 0)
8087 /* reset signals that we previously set to SIG_IGN */
8088 signal(SIGPIPE, SIG_DFL);
8090 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8095 ERR("fork() failed!\n");
8101 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8102 write(fds[1], buf, no_read);
8109 wret = waitpid(pid, &status, 0);
8110 } while (wret < 0 && errno == EINTR);
8113 ERR("waitpid() failed!\n");
8116 if (!WIFEXITED(status) || WEXITSTATUS(status))
8118 ERR("child process failed! %d\n", status);
8125 if(file_fd != -1) close(file_fd);
8126 if(fds[0] != -1) close(fds[0]);
8127 if(fds[1] != -1) close(fds[1]);
8129 HeapFree(GetProcessHeap(), 0, cmdA);
8130 HeapFree(GetProcessHeap(), 0, unixname);
8137 /*****************************************************************************
8140 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8143 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8146 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8147 sprintfW(cmd, fmtW, printer_name);
8149 r = schedule_pipe(cmd, filename);
8151 HeapFree(GetProcessHeap(), 0, cmd);
8155 #ifdef SONAME_LIBCUPS
8156 /*****************************************************************************
8157 * get_cups_jobs_ticket_options
8159 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8160 * The CUPS scheduler only looks for these in Print-File requests, and since
8161 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8164 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8166 FILE *fp = fopen( file, "r" );
8167 char buf[257]; /* DSC max of 256 + '\0' */
8168 const char *ps_adobe = "%!PS-Adobe-";
8169 const char *cups_job = "%cupsJobTicket:";
8171 if (!fp) return num_options;
8172 if (!fgets( buf, sizeof(buf), fp )) goto end;
8173 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8174 while (fgets( buf, sizeof(buf), fp ))
8176 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8177 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8186 /*****************************************************************************
8189 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8191 #ifdef SONAME_LIBCUPS
8194 char *unixname, *queue, *unix_doc_title;
8197 int num_options = 0, i;
8198 cups_option_t *options = NULL;
8200 if(!(unixname = wine_get_unix_file_name(filename)))
8203 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8204 queue = HeapAlloc(GetProcessHeap(), 0, len);
8205 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8207 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8208 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8209 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8211 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8213 TRACE( "printing via cups with options:\n" );
8214 for (i = 0; i < num_options; i++)
8215 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8217 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8219 pcupsFreeOptions( num_options, options );
8221 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8222 HeapFree(GetProcessHeap(), 0, queue);
8223 HeapFree(GetProcessHeap(), 0, unixname);
8229 return schedule_lpr(printer_name, filename);
8233 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8240 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8244 if(HIWORD(wparam) == BN_CLICKED)
8246 if(LOWORD(wparam) == IDOK)
8249 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8252 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8253 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8255 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8257 WCHAR caption[200], message[200];
8260 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8261 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8262 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8263 if(mb_ret == IDCANCEL)
8265 HeapFree(GetProcessHeap(), 0, filename);
8269 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8270 if(hf == INVALID_HANDLE_VALUE)
8272 WCHAR caption[200], message[200];
8274 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8275 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8276 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8277 HeapFree(GetProcessHeap(), 0, filename);
8281 DeleteFileW(filename);
8282 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8284 EndDialog(hwnd, IDOK);
8287 if(LOWORD(wparam) == IDCANCEL)
8289 EndDialog(hwnd, IDCANCEL);
8298 /*****************************************************************************
8301 static BOOL get_filename(LPWSTR *filename)
8303 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8304 file_dlg_proc, (LPARAM)filename) == IDOK;
8307 /*****************************************************************************
8310 static BOOL schedule_file(LPCWSTR filename)
8312 LPWSTR output = NULL;
8314 if(get_filename(&output))
8317 TRACE("copy to %s\n", debugstr_w(output));
8318 r = CopyFileW(filename, output, FALSE);
8319 HeapFree(GetProcessHeap(), 0, output);
8325 /*****************************************************************************
8328 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8330 int in_fd, out_fd, no_read;
8333 char *unixname, *outputA;
8336 if(!(unixname = wine_get_unix_file_name(filename)))
8339 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8340 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8341 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8343 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8344 in_fd = open(unixname, O_RDONLY);
8345 if(out_fd == -1 || in_fd == -1)
8348 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8349 write(out_fd, buf, no_read);
8353 if(in_fd != -1) close(in_fd);
8354 if(out_fd != -1) close(out_fd);
8355 HeapFree(GetProcessHeap(), 0, outputA);
8356 HeapFree(GetProcessHeap(), 0, unixname);
8360 /*****************************************************************************
8361 * ScheduleJob [WINSPOOL.@]
8364 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8366 opened_printer_t *printer;
8368 struct list *cursor, *cursor2;
8370 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8371 EnterCriticalSection(&printer_handles_cs);
8372 printer = get_opened_printer(hPrinter);
8376 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8378 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8381 if(job->job_id != dwJobID) continue;
8383 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8384 if(hf != INVALID_HANDLE_VALUE)
8386 PRINTER_INFO_5W *pi5 = NULL;
8387 LPWSTR portname = job->portname;
8391 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8392 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8396 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8397 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8398 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8399 portname = pi5->pPortName;
8401 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8402 debugstr_w(portname));
8406 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8407 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8409 DWORD type, count = sizeof(output);
8410 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8413 if(output[0] == '|')
8415 ret = schedule_pipe(output + 1, job->filename);
8419 ret = schedule_unixfile(output, job->filename);
8421 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8423 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8425 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8427 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8429 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8431 ret = schedule_file(job->filename);
8435 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8437 HeapFree(GetProcessHeap(), 0, pi5);
8439 DeleteFileW(job->filename);
8441 list_remove(cursor);
8442 HeapFree(GetProcessHeap(), 0, job->document_title);
8443 HeapFree(GetProcessHeap(), 0, job->printer_name);
8444 HeapFree(GetProcessHeap(), 0, job->portname);
8445 HeapFree(GetProcessHeap(), 0, job->filename);
8446 HeapFree(GetProcessHeap(), 0, job->devmode);
8447 HeapFree(GetProcessHeap(), 0, job);
8451 LeaveCriticalSection(&printer_handles_cs);
8455 /*****************************************************************************
8456 * StartDocDlgA [WINSPOOL.@]
8458 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8460 UNICODE_STRING usBuffer;
8463 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8466 docW.cbSize = sizeof(docW);
8467 if (doc->lpszDocName)
8469 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8470 if (!(docW.lpszDocName = docnameW)) return NULL;
8472 if (doc->lpszOutput)
8474 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8475 if (!(docW.lpszOutput = outputW)) return NULL;
8477 if (doc->lpszDatatype)
8479 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8480 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8482 docW.fwType = doc->fwType;
8484 retW = StartDocDlgW(hPrinter, &docW);
8488 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8489 ret = HeapAlloc(GetProcessHeap(), 0, len);
8490 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8491 HeapFree(GetProcessHeap(), 0, retW);
8494 HeapFree(GetProcessHeap(), 0, datatypeW);
8495 HeapFree(GetProcessHeap(), 0, outputW);
8496 HeapFree(GetProcessHeap(), 0, docnameW);
8501 /*****************************************************************************
8502 * StartDocDlgW [WINSPOOL.@]
8504 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8505 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8506 * port is "FILE:". Also returns the full path if passed a relative path.
8508 * The caller should free the returned string from the process heap.
8510 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8515 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8517 PRINTER_INFO_5W *pi5;
8518 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8519 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8521 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8522 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8523 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8525 HeapFree(GetProcessHeap(), 0, pi5);
8528 HeapFree(GetProcessHeap(), 0, pi5);
8531 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8535 if (get_filename(&name))
8537 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8539 HeapFree(GetProcessHeap(), 0, name);
8542 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8543 GetFullPathNameW(name, len, ret, NULL);
8544 HeapFree(GetProcessHeap(), 0, name);
8549 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8552 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8553 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8555 attr = GetFileAttributesW(ret);
8556 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8558 HeapFree(GetProcessHeap(), 0, ret);