4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
37 #ifdef HAVE_SYS_WAIT_H
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
48 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
49 #define GetCurrentProcess GetCurrentProcess_Mac
50 #define GetCurrentThread GetCurrentThread_Mac
51 #define LoadResource LoadResource_Mac
52 #define AnimatePalette AnimatePalette_Mac
53 #define EqualRgn EqualRgn_Mac
54 #define FillRgn FillRgn_Mac
55 #define FrameRgn FrameRgn_Mac
56 #define GetPixel GetPixel_Mac
57 #define InvertRgn InvertRgn_Mac
58 #define LineTo LineTo_Mac
59 #define OffsetRgn OffsetRgn_Mac
60 #define PaintRgn PaintRgn_Mac
61 #define Polygon Polygon_Mac
62 #define ResizePalette ResizePalette_Mac
63 #define SetRectRgn SetRectRgn_Mac
64 #define EqualRect EqualRect_Mac
65 #define FillRect FillRect_Mac
66 #define FrameRect FrameRect_Mac
67 #define GetCursor GetCursor_Mac
68 #define InvertRect InvertRect_Mac
69 #define OffsetRect OffsetRect_Mac
70 #define PtInRect PtInRect_Mac
71 #define SetCursor SetCursor_Mac
72 #define SetRect SetRect_Mac
73 #define ShowCursor ShowCursor_Mac
74 #define UnionRect UnionRect_Mac
75 #include <ApplicationServices/ApplicationServices.h>
76 #undef GetCurrentProcess
77 #undef GetCurrentThread
105 #define NONAMELESSUNION
106 #define NONAMELESSSTRUCT
107 #include "wine/library.h"
111 #include "winerror.h"
114 #include "winspool.h"
115 #include "winternl.h"
116 #include "wine/windef16.h"
117 #include "wine/unicode.h"
118 #include "wine/debug.h"
119 #include "wine/list.h"
122 #include "ddk/winsplp.h"
125 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
127 /* ############################### */
129 static CRITICAL_SECTION printer_handles_cs;
130 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
132 0, 0, &printer_handles_cs,
133 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
134 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
136 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
138 /* ############################### */
153 HANDLE backend_printer;
164 WCHAR *document_title;
174 LPCWSTR versionregpath;
175 LPCWSTR versionsubdir;
178 /* ############################### */
180 static opened_printer_t **printer_handles;
181 static UINT nb_printer_handles;
182 static LONG next_job_id = 1;
184 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
185 WORD fwCapability, LPSTR lpszOutput,
187 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
188 LPSTR lpszDevice, LPSTR lpszPort,
189 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
192 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
193 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
194 'c','o','n','t','r','o','l','\\',
195 'P','r','i','n','t','\\',
196 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
197 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
199 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
200 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
201 'C','o','n','t','r','o','l','\\',
202 'P','r','i','n','t','\\',
203 'P','r','i','n','t','e','r','s',0};
205 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
207 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
208 'M','i','c','r','o','s','o','f','t','\\',
209 'W','i','n','d','o','w','s',' ','N','T','\\',
210 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
211 'W','i','n','d','o','w','s',0};
213 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
214 'M','i','c','r','o','s','o','f','t','\\',
215 'W','i','n','d','o','w','s',' ','N','T','\\',
216 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
217 'D','e','v','i','c','e','s',0};
219 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
220 'M','i','c','r','o','s','o','f','t','\\',
221 'W','i','n','d','o','w','s',' ','N','T','\\',
222 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
223 'P','o','r','t','s',0};
225 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
226 'M','i','c','r','o','s','o','f','t','\\',
227 'W','i','n','d','o','w','s',' ','N','T','\\',
228 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
229 'P','r','i','n','t','e','r','P','o','r','t','s',0};
231 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
232 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
233 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
234 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
235 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
236 static const WCHAR subdir_x64W[] = {'x','6','4',0};
237 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
238 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
239 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
240 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
241 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
243 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
245 static const WCHAR AttributesW[] = {'A','t','t','r','i','b','u','t','e','s',0};
246 static const WCHAR backslashW[] = {'\\',0};
247 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
248 'i','o','n',' ','F','i','l','e',0};
249 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
250 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
251 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
252 static const WCHAR Default_PriorityW[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
253 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
254 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
255 static const WCHAR dnsTimeoutW[] = {'d','n','s','T','i','m','e','o','u','t',0};
256 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
257 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
258 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
259 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
260 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
261 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
262 static const WCHAR NameW[] = {'N','a','m','e',0};
263 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
264 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
265 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
266 static const WCHAR PortW[] = {'P','o','r','t',0};
267 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
268 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
269 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
270 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
271 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
272 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
273 static const WCHAR PriorityW[] = {'P','r','i','o','r','i','t','y',0};
274 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
275 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
276 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
277 static const WCHAR StartTimeW[] = {'S','t','a','r','t','T','i','m','e',0};
278 static const WCHAR StatusW[] = {'S','t','a','t','u','s',0};
279 static const WCHAR txTimeoutW[] = {'t','x','T','i','m','e','o','u','t',0};
280 static const WCHAR UntilTimeW[] = {'U','n','t','i','l','T','i','m','e',0};
281 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
282 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
283 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
284 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
285 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
286 static WCHAR rawW[] = {'R','A','W',0};
287 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
288 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
289 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
290 static const WCHAR commaW[] = {',',0};
291 static WCHAR emptyStringW[] = {0};
293 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
295 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
296 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
297 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
299 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
300 'D','o','c','u','m','e','n','t',0};
302 static const WCHAR PPD_Overrides[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
303 static const WCHAR DefaultPageSize[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
305 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
306 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
307 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
308 0, sizeof(DRIVER_INFO_8W)};
311 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
312 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
313 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
314 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
315 sizeof(PRINTER_INFO_9W)};
317 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
318 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
319 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
321 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
323 /******************************************************************
324 * validate the user-supplied printing-environment [internal]
327 * env [I] PTR to Environment-String or NULL
331 * Success: PTR to printenv_t
334 * An empty string is handled the same way as NULL.
335 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
339 static const printenv_t * validate_envW(LPCWSTR env)
341 const printenv_t *result = NULL;
344 TRACE("testing %s\n", debugstr_w(env));
347 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
349 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
351 result = all_printenv[i];
356 if (result == NULL) {
357 FIXME("unsupported Environment: %s\n", debugstr_w(env));
358 SetLastError(ERROR_INVALID_ENVIRONMENT);
360 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
364 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
366 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
372 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
373 if passed a NULL string. This returns NULLs to the result.
375 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
379 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
380 return usBufferPtr->Buffer;
382 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
386 static LPWSTR strdupW(LPCWSTR p)
392 len = (strlenW(p) + 1) * sizeof(WCHAR);
393 ret = HeapAlloc(GetProcessHeap(), 0, len);
398 static LPSTR strdupWtoA( LPCWSTR str )
403 if (!str) return NULL;
404 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
405 ret = HeapAlloc( GetProcessHeap(), 0, len );
406 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
410 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
414 if (!dm) return NULL;
415 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
416 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
420 /***********************************************************
422 * Creates an ansi copy of supplied devmode
424 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
429 if (!dmW) return NULL;
430 size = dmW->dmSize - CCHDEVICENAME -
431 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
433 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
434 if (!dmA) return NULL;
436 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
437 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
439 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
441 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
442 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
446 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
447 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
448 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
449 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
451 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
455 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
460 /******************************************************************
461 * verify, that the filename is a local file
464 static inline BOOL is_local_file(LPWSTR name)
466 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
469 /* ################################ */
471 static int multi_sz_lenA(const char *str)
473 const char *ptr = str;
477 ptr += lstrlenA(ptr) + 1;
480 return ptr - str + 1;
483 /*****************************************************************************
486 * Return DWORD associated with name from hkey.
488 static DWORD get_dword_from_reg( HKEY hkey, const WCHAR *name )
490 DWORD sz = sizeof(DWORD), type, value = 0;
493 ret = RegQueryValueExW( hkey, name, 0, &type, (LPBYTE)&value, &sz );
495 if (ret != ERROR_SUCCESS)
497 WARN( "Got ret = %d on name %s\n", ret, debugstr_w(name) );
500 if (type != REG_DWORD)
502 ERR( "Got type %d\n", type );
508 static inline DWORD set_reg_DWORD( HKEY hkey, const WCHAR *keyname, const DWORD value )
510 return RegSetValueExW( hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value) );
513 /******************************************************************
515 * Get the pointer to the opened printer referred by the handle
517 static opened_printer_t *get_opened_printer(HANDLE hprn)
519 UINT_PTR idx = (UINT_PTR)hprn;
520 opened_printer_t *ret = NULL;
522 EnterCriticalSection(&printer_handles_cs);
524 if ((idx > 0) && (idx <= nb_printer_handles)) {
525 ret = printer_handles[idx - 1];
527 LeaveCriticalSection(&printer_handles_cs);
531 /******************************************************************
532 * get_opened_printer_name
533 * Get the pointer to the opened printer name referred by the handle
535 static LPCWSTR get_opened_printer_name(HANDLE hprn)
537 opened_printer_t *printer = get_opened_printer(hprn);
538 if(!printer) return NULL;
539 return printer->name;
542 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
548 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
551 err = RegOpenKeyW( printers, name, key );
552 if (err) err = ERROR_INVALID_PRINTER_NAME;
553 RegCloseKey( printers );
557 /******************************************************************
558 * WINSPOOL_GetOpenedPrinterRegKey
561 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
563 LPCWSTR name = get_opened_printer_name(hPrinter);
565 if(!name) return ERROR_INVALID_HANDLE;
566 return open_printer_reg_key( name, phkey );
570 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
573 /* If forcing, or no profile string entry for device yet, set the entry
575 * The always change entry if not WINEPS yet is discussable.
578 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
580 !strstr(qbuf,"WINEPS.DRV")
582 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
585 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
586 WriteProfileStringA("windows","device",buf);
587 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
588 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
591 HeapFree(GetProcessHeap(),0,buf);
595 static BOOL add_printer_driver(const WCHAR *name, WCHAR *ppd)
599 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
601 di3.pName = (WCHAR*)name;
602 di3.pEnvironment = envname_x86W;
603 di3.pDriverPath = driver_nt;
605 di3.pConfigFile = driver_nt;
606 di3.pDefaultDataType = rawW;
608 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
609 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
612 di3.pEnvironment = envname_win40W;
613 di3.pDriverPath = driver_9x;
614 di3.pConfigFile = driver_9x;
615 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
616 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
621 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
625 static inline char *expand_env_string( char *str, DWORD type )
627 if (type == REG_EXPAND_SZ)
630 DWORD needed = ExpandEnvironmentStringsA( str, NULL, 0 );
631 tmp = HeapAlloc( GetProcessHeap(), 0, needed );
634 ExpandEnvironmentStringsA( str, tmp, needed );
635 HeapFree( GetProcessHeap(), 0, str );
642 static char *get_fallback_ppd_name( const char *printer_name )
644 static const WCHAR ppds_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
645 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
649 const char *data_dir, *filename;
651 if (RegOpenKeyW( HKEY_CURRENT_USER, ppds_key, &hkey ) == ERROR_SUCCESS )
653 const char *value_name = NULL;
655 if (RegQueryValueExA( hkey, printer_name, 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
656 value_name = printer_name;
657 else if (RegQueryValueExA( hkey, "generic", 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
658 value_name = "generic";
662 ret = HeapAlloc( GetProcessHeap(), 0, needed );
663 if (!ret) return NULL;
664 RegQueryValueExA( hkey, value_name, 0, &type, (BYTE *)ret, &needed );
667 if (ret) return expand_env_string( ret, type );
670 if ((data_dir = wine_get_data_dir())) filename = "/generic.ppd";
671 else if ((data_dir = wine_get_build_dir())) filename = "/dlls/wineps.drv/generic.ppd";
674 ERR( "Error getting PPD file name for printer '%s'\n", debugstr_a(printer_name) );
677 ret = HeapAlloc( GetProcessHeap(), 0, strlen(data_dir) + strlen(filename) + 1 );
680 strcpy( ret, data_dir );
681 strcat( ret, filename );
687 static BOOL copy_file( const char *src, const char *dst )
689 int fds[2] = {-1, -1}, num;
693 fds[0] = open( src, O_RDONLY );
694 fds[1] = open( dst, O_CREAT | O_TRUNC | O_WRONLY, 0666 );
695 if (fds[0] == -1 || fds[1] == -1) goto fail;
697 while ((num = read( fds[0], buf, sizeof(buf) )) != 0)
699 if (num == -1) goto fail;
700 if (write( fds[1], buf, num ) != num) goto fail;
705 if (fds[1] != -1) close( fds[1] );
706 if (fds[0] != -1) close( fds[0] );
710 static BOOL get_fallback_ppd( const char *printer_name, const WCHAR *ppd )
712 char *src = get_fallback_ppd_name( printer_name );
713 char *dst = wine_get_unix_file_name( ppd );
716 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name), debugstr_w(ppd), debugstr_a(src) );
718 if (!src || !dst) goto fail;
720 if (symlink( src, dst ) == -1)
721 if (errno != ENOSYS || !copy_file( src, dst ))
726 HeapFree( GetProcessHeap(), 0, dst );
727 HeapFree( GetProcessHeap(), 0, src );
731 static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
733 static const WCHAR dot_ppd[] = {'.','p','p','d',0};
734 int len = (strlenW( dir ) + strlenW( file_name )) * sizeof(WCHAR) + sizeof(dot_ppd);
735 WCHAR *ppd = HeapAlloc( GetProcessHeap(), 0, len );
737 if (!ppd) return NULL;
739 strcatW( ppd, file_name );
740 strcatW( ppd, dot_ppd );
745 static WCHAR *get_ppd_dir( void )
747 static const WCHAR wine_ppds[] = {'w','i','n','e','_','p','p','d','s','\\',0};
749 WCHAR *dir, tmp_path[MAX_PATH];
752 len = GetTempPathW( sizeof(tmp_path) / sizeof(tmp_path[0]), tmp_path );
753 if (!len) return NULL;
754 dir = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
755 if (!dir) return NULL;
757 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
758 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
759 res = CreateDirectoryW( dir, NULL );
760 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
762 HeapFree( GetProcessHeap(), 0, dir );
765 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
769 static void unlink_ppd( const WCHAR *ppd )
771 char *unix_name = wine_get_unix_file_name( ppd );
773 HeapFree( GetProcessHeap(), 0, unix_name );
776 #ifdef SONAME_LIBCUPS
778 static void *cupshandle;
781 DO_FUNC(cupsFreeDests); \
782 DO_FUNC(cupsFreeOptions); \
783 DO_FUNC(cupsGetDests); \
784 DO_FUNC(cupsGetOption); \
785 DO_FUNC(cupsGetPPD); \
786 DO_FUNC(cupsParseOptions); \
787 DO_FUNC(cupsPrintFile);
788 #define CUPS_OPT_FUNCS \
789 DO_FUNC(cupsGetPPD3);
791 #define DO_FUNC(f) static typeof(f) *p##f
794 static http_status_t (*pcupsGetPPD3)(http_t *,const char *, time_t *, char *, size_t);
796 static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name,
797 time_t *modtime, char *buffer,
802 if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
804 if (!pcupsGetPPD) return HTTP_NOT_FOUND;
806 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
809 ppd = pcupsGetPPD( name );
811 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
813 if (!ppd) return HTTP_NOT_FOUND;
815 if (rename( ppd, buffer ) == -1)
817 BOOL res = copy_file( ppd, buffer );
819 if (!res) return HTTP_NOT_FOUND;
824 static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
827 http_status_t http_status;
828 char *unix_name = wine_get_unix_file_name( ppd );
830 TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
832 if (!unix_name) return FALSE;
834 http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
835 unix_name, strlen( unix_name ) + 1 );
836 HeapFree( GetProcessHeap(), 0, unix_name );
838 if (http_status == HTTP_OK) return TRUE;
840 TRACE( "failed to get ppd for printer %s from cups, calling fallback\n", debugstr_a(printer_name) );
841 return get_fallback_ppd( printer_name, ppd );
844 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
850 value = pcupsGetOption( name, num_options, options );
851 if (!value) return NULL;
853 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
854 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
855 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
860 static cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
862 WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
863 cups_ptype_t ret = 0;
867 ret = (cups_ptype_t)strtoulW( type, &end, 10 );
870 HeapFree( GetProcessHeap(), 0, type );
874 static BOOL CUPS_LoadPrinters(void)
877 BOOL hadprinter = FALSE, haddefault = FALSE;
880 WCHAR *port, *ppd_dir = NULL, *ppd;
881 HKEY hkeyPrinter, hkeyPrinters;
883 WCHAR nameW[MAX_PATH];
884 HANDLE added_printer;
885 cups_ptype_t printer_type;
887 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
889 TRACE("%s\n", loaderror);
892 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
894 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
897 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 );
901 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
903 ERR("Can't create Printers key\n");
907 nrofdests = pcupsGetDests(&dests);
908 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
909 for (i=0;i<nrofdests;i++) {
910 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
911 printer_type = get_cups_printer_type( dests + i );
913 TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
915 if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
917 TRACE( "skipping scanner-only device\n" );
921 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
922 lstrcpyW(port, CUPS_Port);
923 lstrcatW(port, nameW);
925 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
926 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
927 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
929 TRACE("Printer already exists\n");
930 /* overwrite old LPR:* port */
931 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
932 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
933 /* flag that the PPD file should be checked for an update */
934 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
935 RegCloseKey(hkeyPrinter);
937 BOOL added_driver = FALSE;
939 if (!ppd_dir) ppd_dir = get_ppd_dir();
940 ppd = get_ppd_filename( ppd_dir, nameW );
941 if (get_cups_ppd( dests[i].name, ppd ))
943 added_driver = add_printer_driver( nameW, ppd );
946 HeapFree( GetProcessHeap(), 0, ppd );
949 HeapFree( GetProcessHeap(), 0, port );
953 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
954 pi2.pPrinterName = nameW;
955 pi2.pDatatype = rawW;
956 pi2.pPrintProcessor = WinPrintW;
957 pi2.pDriverName = nameW;
958 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
959 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
960 pi2.pPortName = port;
961 pi2.pParameters = emptyStringW;
962 pi2.pShareName = emptyStringW;
963 pi2.pSepFile = emptyStringW;
965 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
966 if (added_printer) ClosePrinter( added_printer );
967 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
968 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
970 HeapFree( GetProcessHeap(), 0, pi2.pComment );
971 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
973 HeapFree( GetProcessHeap(), 0, port );
976 if (dests[i].is_default) {
977 SetDefaultPrinterW(nameW);
984 RemoveDirectoryW( ppd_dir );
985 HeapFree( GetProcessHeap(), 0, ppd_dir );
988 if (hadprinter && !haddefault) {
989 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
990 SetDefaultPrinterW(nameW);
992 pcupsFreeDests(nrofdests, dests);
993 RegCloseKey(hkeyPrinters);
999 static char *get_queue_name( HANDLE printer, BOOL *cups )
1001 WCHAR *port, *name = NULL;
1002 DWORD err, needed, type;
1008 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1009 if (err) return NULL;
1010 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1012 port = HeapAlloc( GetProcessHeap(), 0, needed );
1013 if (!port) goto end;
1014 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1016 if (!strncmpW( port, CUPS_Port, sizeof(CUPS_Port) / sizeof(WCHAR) -1 ))
1018 name = port + sizeof(CUPS_Port) / sizeof(WCHAR) - 1;
1021 else if (!strncmpW( port, LPR_Port, sizeof(LPR_Port) / sizeof(WCHAR) -1 ))
1022 name = port + sizeof(LPR_Port) / sizeof(WCHAR) - 1;
1025 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1026 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1027 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1029 HeapFree( GetProcessHeap(), 0, port );
1036 static void set_ppd_overrides( HANDLE printer )
1040 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1042 PMPrintSession session = NULL;
1043 PMPageFormat format = NULL;
1045 CFStringRef paper_name;
1048 status = PMCreateSession( &session );
1049 if (status) goto end;
1051 status = PMCreatePageFormat( &format );
1052 if (status) goto end;
1054 status = PMSessionDefaultPageFormat( session, format );
1055 if (status) goto end;
1057 status = PMGetPageFormatPaper( format, &paper );
1058 if (status) goto end;
1060 status = PMPaperGetPPDPaperName( paper, &paper_name );
1061 if (status) goto end;
1064 range.length = CFStringGetLength( paper_name );
1065 size = (range.length + 1) * sizeof(WCHAR);
1067 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1068 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1069 wstr[range.length] = 0;
1072 if (format) PMRelease( format );
1073 if (session) PMRelease( session );
1076 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1077 HeapFree( GetProcessHeap(), 0, wstr );
1080 static BOOL update_driver( HANDLE printer )
1083 const WCHAR *name = get_opened_printer_name( printer );
1084 WCHAR *ppd_dir, *ppd;
1087 if (!name) return FALSE;
1088 queue_name = get_queue_name( printer, &is_cups );
1089 if (!queue_name) return FALSE;
1091 ppd_dir = get_ppd_dir();
1092 ppd = get_ppd_filename( ppd_dir, name );
1094 #ifdef SONAME_LIBCUPS
1096 ret = get_cups_ppd( queue_name, ppd );
1099 ret = get_fallback_ppd( queue_name, ppd );
1103 TRACE( "updating driver %s\n", debugstr_w( name ) );
1104 ret = add_printer_driver( name, ppd );
1107 HeapFree( GetProcessHeap(), 0, ppd_dir );
1108 HeapFree( GetProcessHeap(), 0, ppd );
1109 HeapFree( GetProcessHeap(), 0, queue_name );
1111 set_ppd_overrides( printer );
1113 /* call into the driver to update the devmode */
1114 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1119 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1121 PRINTER_INFO_2A pinfo2a;
1124 char *e,*s,*name,*prettyname,*devname;
1125 BOOL ret = FALSE, set_default = FALSE;
1126 char *port = NULL, *env_default;
1127 HKEY hkeyPrinter, hkeyPrinters = NULL;
1128 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1129 HANDLE added_printer;
1131 while (isspace(*pent)) pent++;
1132 r = strchr(pent,':');
1134 name_len = r - pent;
1136 name_len = strlen(pent);
1137 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1138 memcpy(name, pent, name_len);
1139 name[name_len] = '\0';
1145 TRACE("name=%s entry=%s\n",name, pent);
1147 if(ispunct(*name)) { /* a tc entry, not a real printer */
1148 TRACE("skipping tc entry\n");
1152 if(strstr(pent,":server")) { /* server only version so skip */
1153 TRACE("skipping server entry\n");
1157 /* Determine whether this is a postscript printer. */
1160 env_default = getenv("PRINTER");
1162 /* Get longest name, usually the one at the right for later display. */
1163 while((s=strchr(prettyname,'|'))) {
1166 while(isspace(*--e)) *e = '\0';
1167 TRACE("\t%s\n", debugstr_a(prettyname));
1168 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1169 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1172 e = prettyname + strlen(prettyname);
1173 while(isspace(*--e)) *e = '\0';
1174 TRACE("\t%s\n", debugstr_a(prettyname));
1175 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1177 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1178 * if it is too long, we use it as comment below. */
1179 devname = prettyname;
1180 if (strlen(devname)>=CCHDEVICENAME-1)
1182 if (strlen(devname)>=CCHDEVICENAME-1) {
1187 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1188 sprintf(port,"LPR:%s",name);
1190 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1192 ERR("Can't create Printers key\n");
1197 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
1199 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1200 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1201 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1203 TRACE("Printer already exists\n");
1204 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1205 /* flag that the PPD file should be checked for an update */
1206 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1207 RegCloseKey(hkeyPrinter);
1209 static CHAR data_type[] = "RAW",
1210 print_proc[] = "WinPrint",
1211 comment[] = "WINEPS Printer using LPR",
1212 params[] = "<parameters?>",
1213 share_name[] = "<share name?>",
1214 sep_file[] = "<sep file?>";
1215 BOOL added_driver = FALSE;
1217 if (!ppd_dir) ppd_dir = get_ppd_dir();
1218 ppd = get_ppd_filename( ppd_dir, devnameW );
1219 if (get_fallback_ppd( devname, ppd ))
1221 added_driver = add_printer_driver( devnameW, ppd );
1224 HeapFree( GetProcessHeap(), 0, ppd );
1225 if (!added_driver) goto end;
1227 memset(&pinfo2a,0,sizeof(pinfo2a));
1228 pinfo2a.pPrinterName = devname;
1229 pinfo2a.pDatatype = data_type;
1230 pinfo2a.pPrintProcessor = print_proc;
1231 pinfo2a.pDriverName = devname;
1232 pinfo2a.pComment = comment;
1233 pinfo2a.pLocation = prettyname;
1234 pinfo2a.pPortName = port;
1235 pinfo2a.pParameters = params;
1236 pinfo2a.pShareName = share_name;
1237 pinfo2a.pSepFile = sep_file;
1239 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1240 if (added_printer) ClosePrinter( added_printer );
1241 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1242 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1245 if (isfirst || set_default)
1246 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1249 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1252 RemoveDirectoryW( ppd_dir );
1253 HeapFree( GetProcessHeap(), 0, ppd_dir );
1255 HeapFree(GetProcessHeap(), 0, port);
1256 HeapFree(GetProcessHeap(), 0, name);
1261 PRINTCAP_LoadPrinters(void) {
1262 BOOL hadprinter = FALSE;
1266 BOOL had_bash = FALSE;
1268 f = fopen("/etc/printcap","r");
1272 while(fgets(buf,sizeof(buf),f)) {
1275 end=strchr(buf,'\n');
1279 while(isspace(*start)) start++;
1280 if(*start == '#' || *start == '\0')
1283 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1284 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1285 HeapFree(GetProcessHeap(),0,pent);
1289 if (end && *--end == '\\') {
1296 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1299 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1305 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1306 HeapFree(GetProcessHeap(),0,pent);
1312 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1315 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1316 (lstrlenW(value) + 1) * sizeof(WCHAR));
1318 return ERROR_FILE_NOT_FOUND;
1321 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1323 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1324 DWORD ret = ERROR_FILE_NOT_FOUND;
1326 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1327 and we support these drivers. NT writes DEVMODEW so somehow
1328 we'll need to distinguish between these when we support NT
1333 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1334 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1335 HeapFree( GetProcessHeap(), 0, dmA );
1341 /******************************************************************
1342 * get_servername_from_name (internal)
1344 * for an external server, a copy of the serverpart from the full name is returned
1347 static LPWSTR get_servername_from_name(LPCWSTR name)
1351 WCHAR buffer[MAX_PATH];
1354 if (name == NULL) return NULL;
1355 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1357 server = strdupW(&name[2]); /* skip over both backslash */
1358 if (server == NULL) return NULL;
1360 /* strip '\' and the printername */
1361 ptr = strchrW(server, '\\');
1362 if (ptr) ptr[0] = '\0';
1364 TRACE("found %s\n", debugstr_w(server));
1366 len = sizeof(buffer)/sizeof(buffer[0]);
1367 if (GetComputerNameW(buffer, &len)) {
1368 if (lstrcmpW(buffer, server) == 0) {
1369 /* The requested Servername is our computername */
1370 HeapFree(GetProcessHeap(), 0, server);
1377 /******************************************************************
1378 * get_basename_from_name (internal)
1380 * skip over the serverpart from the full name
1383 static LPCWSTR get_basename_from_name(LPCWSTR name)
1385 if (name == NULL) return NULL;
1386 if ((name[0] == '\\') && (name[1] == '\\')) {
1387 /* skip over the servername and search for the following '\' */
1388 name = strchrW(&name[2], '\\');
1389 if ((name) && (name[1])) {
1390 /* found a separator ('\') followed by a name:
1391 skip over the separator and return the rest */
1396 /* no basename present (we found only a servername) */
1403 static void free_printer_entry( opened_printer_t *printer )
1405 /* the queue is shared, so don't free that here */
1406 HeapFree( GetProcessHeap(), 0, printer->printername );
1407 HeapFree( GetProcessHeap(), 0, printer->name );
1408 HeapFree( GetProcessHeap(), 0, printer->devmode );
1409 HeapFree( GetProcessHeap(), 0, printer );
1412 /******************************************************************
1413 * get_opened_printer_entry
1414 * Get the first place empty in the opened printer table
1417 * - pDefault is ignored
1419 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1421 UINT_PTR handle = nb_printer_handles, i;
1422 jobqueue_t *queue = NULL;
1423 opened_printer_t *printer = NULL;
1425 LPCWSTR printername;
1427 if ((backend == NULL) && !load_backend()) return NULL;
1429 servername = get_servername_from_name(name);
1431 FIXME("server %s not supported\n", debugstr_w(servername));
1432 HeapFree(GetProcessHeap(), 0, servername);
1433 SetLastError(ERROR_INVALID_PRINTER_NAME);
1437 printername = get_basename_from_name(name);
1438 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1440 /* an empty printername is invalid */
1441 if (printername && (!printername[0])) {
1442 SetLastError(ERROR_INVALID_PARAMETER);
1446 EnterCriticalSection(&printer_handles_cs);
1448 for (i = 0; i < nb_printer_handles; i++)
1450 if (!printer_handles[i])
1452 if(handle == nb_printer_handles)
1457 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1458 queue = printer_handles[i]->queue;
1462 if (handle >= nb_printer_handles)
1464 opened_printer_t **new_array;
1465 if (printer_handles)
1466 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1467 (nb_printer_handles + 16) * sizeof(*new_array) );
1469 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1470 (nb_printer_handles + 16) * sizeof(*new_array) );
1477 printer_handles = new_array;
1478 nb_printer_handles += 16;
1481 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1487 /* get a printer handle from the backend */
1488 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1493 /* clone the base name. This is NULL for the printserver */
1494 printer->printername = strdupW(printername);
1496 /* clone the full name */
1497 printer->name = strdupW(name);
1498 if (name && (!printer->name)) {
1503 if (pDefault && pDefault->pDevMode)
1504 printer->devmode = dup_devmode( pDefault->pDevMode );
1507 printer->queue = queue;
1510 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1511 if (!printer->queue) {
1515 list_init(&printer->queue->jobs);
1516 printer->queue->ref = 0;
1518 InterlockedIncrement(&printer->queue->ref);
1520 printer_handles[handle] = printer;
1523 LeaveCriticalSection(&printer_handles_cs);
1524 if (!handle && printer) {
1525 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1526 free_printer_entry( printer );
1529 return (HANDLE)handle;
1532 static void old_printer_check( BOOL delete_phase )
1534 PRINTER_INFO_5W* pi;
1535 DWORD needed, type, num, delete, i, size;
1536 const DWORD one = 1;
1540 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1541 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1543 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1544 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1545 for (i = 0; i < num; i++)
1547 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1548 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1551 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1555 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1561 size = sizeof( delete );
1562 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1566 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1567 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1569 DeletePrinter( hprn );
1570 ClosePrinter( hprn );
1572 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1576 HeapFree(GetProcessHeap(), 0, pi);
1579 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1580 'M','U','T','E','X','_','_','\0'};
1581 static HANDLE init_mutex;
1583 void WINSPOOL_LoadSystemPrinters(void)
1585 HKEY hkey, hkeyPrinters;
1586 DWORD needed, num, i;
1587 WCHAR PrinterName[256];
1590 /* FIXME: The init code should be moved to spoolsv.exe */
1591 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1594 ERR( "Failed to create mutex\n" );
1597 if (GetLastError() == ERROR_ALREADY_EXISTS)
1599 WaitForSingleObject( init_mutex, INFINITE );
1600 ReleaseMutex( init_mutex );
1601 TRACE( "Init already done\n" );
1605 /* This ensures that all printer entries have a valid Name value. If causes
1606 problems later if they don't. If one is found to be missed we create one
1607 and set it equal to the name of the key */
1608 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1609 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1610 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1611 for(i = 0; i < num; i++) {
1612 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1613 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1614 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1615 set_reg_szW(hkey, NameW, PrinterName);
1622 RegCloseKey(hkeyPrinters);
1625 old_printer_check( FALSE );
1627 #ifdef SONAME_LIBCUPS
1628 done = CUPS_LoadPrinters();
1631 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1632 PRINTCAP_LoadPrinters();
1634 old_printer_check( TRUE );
1636 ReleaseMutex( init_mutex );
1640 /******************************************************************
1643 * Get the pointer to the specified job.
1644 * Should hold the printer_handles_cs before calling.
1646 static job_t *get_job(HANDLE hprn, DWORD JobId)
1648 opened_printer_t *printer = get_opened_printer(hprn);
1651 if(!printer) return NULL;
1652 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1654 if(job->job_id == JobId)
1660 /***********************************************************
1663 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1666 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1669 Formname = (dmA->dmSize > off_formname);
1670 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1671 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1672 dmW->dmDeviceName, CCHDEVICENAME);
1674 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1675 dmA->dmSize - CCHDEVICENAME);
1677 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1678 off_formname - CCHDEVICENAME);
1679 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1680 dmW->dmFormName, CCHFORMNAME);
1681 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1682 (off_formname + CCHFORMNAME));
1685 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1686 dmA->dmDriverExtra);
1690 /******************************************************************
1691 * convert_printerinfo_W_to_A [internal]
1694 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1695 DWORD level, DWORD outlen, DWORD numentries)
1701 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1703 len = pi_sizeof[level] * numentries;
1704 ptr = (LPSTR) out + len;
1707 /* copy the numbers of all PRINTER_INFO_* first */
1708 memcpy(out, pPrintersW, len);
1710 while (id < numentries) {
1714 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1715 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1717 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1718 if (piW->pDescription) {
1719 piA->pDescription = ptr;
1720 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1721 ptr, outlen, NULL, NULL);
1727 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1728 ptr, outlen, NULL, NULL);
1732 if (piW->pComment) {
1733 piA->pComment = ptr;
1734 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1735 ptr, outlen, NULL, NULL);
1744 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1745 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1748 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1749 if (piW->pServerName) {
1750 piA->pServerName = ptr;
1751 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1752 ptr, outlen, NULL, NULL);
1756 if (piW->pPrinterName) {
1757 piA->pPrinterName = ptr;
1758 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1759 ptr, outlen, NULL, NULL);
1763 if (piW->pShareName) {
1764 piA->pShareName = ptr;
1765 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1766 ptr, outlen, NULL, NULL);
1770 if (piW->pPortName) {
1771 piA->pPortName = ptr;
1772 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1773 ptr, outlen, NULL, NULL);
1777 if (piW->pDriverName) {
1778 piA->pDriverName = ptr;
1779 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1780 ptr, outlen, NULL, NULL);
1784 if (piW->pComment) {
1785 piA->pComment = ptr;
1786 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1787 ptr, outlen, NULL, NULL);
1791 if (piW->pLocation) {
1792 piA->pLocation = ptr;
1793 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1794 ptr, outlen, NULL, NULL);
1799 dmA = DEVMODEdupWtoA(piW->pDevMode);
1801 /* align DEVMODEA to a DWORD boundary */
1802 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1806 piA->pDevMode = (LPDEVMODEA) ptr;
1807 len = dmA->dmSize + dmA->dmDriverExtra;
1808 memcpy(ptr, dmA, len);
1809 HeapFree(GetProcessHeap(), 0, dmA);
1815 if (piW->pSepFile) {
1816 piA->pSepFile = ptr;
1817 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1818 ptr, outlen, NULL, NULL);
1822 if (piW->pPrintProcessor) {
1823 piA->pPrintProcessor = ptr;
1824 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1825 ptr, outlen, NULL, NULL);
1829 if (piW->pDatatype) {
1830 piA->pDatatype = ptr;
1831 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1832 ptr, outlen, NULL, NULL);
1836 if (piW->pParameters) {
1837 piA->pParameters = ptr;
1838 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1839 ptr, outlen, NULL, NULL);
1843 if (piW->pSecurityDescriptor) {
1844 piA->pSecurityDescriptor = NULL;
1845 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1852 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1853 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1855 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1857 if (piW->pPrinterName) {
1858 piA->pPrinterName = ptr;
1859 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1860 ptr, outlen, NULL, NULL);
1864 if (piW->pServerName) {
1865 piA->pServerName = ptr;
1866 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1867 ptr, outlen, NULL, NULL);
1876 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1877 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1879 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1881 if (piW->pPrinterName) {
1882 piA->pPrinterName = ptr;
1883 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1884 ptr, outlen, NULL, NULL);
1888 if (piW->pPortName) {
1889 piA->pPortName = ptr;
1890 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1891 ptr, outlen, NULL, NULL);
1898 case 6: /* 6A and 6W are the same structure */
1903 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1904 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1906 TRACE("(%u) #%u\n", level, id);
1907 if (piW->pszObjectGUID) {
1908 piA->pszObjectGUID = ptr;
1909 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1910 ptr, outlen, NULL, NULL);
1920 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1921 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1924 TRACE("(%u) #%u\n", level, id);
1925 dmA = DEVMODEdupWtoA(piW->pDevMode);
1927 /* align DEVMODEA to a DWORD boundary */
1928 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1932 piA->pDevMode = (LPDEVMODEA) ptr;
1933 len = dmA->dmSize + dmA->dmDriverExtra;
1934 memcpy(ptr, dmA, len);
1935 HeapFree(GetProcessHeap(), 0, dmA);
1945 FIXME("for level %u\n", level);
1947 pPrintersW += pi_sizeof[level];
1948 out += pi_sizeof[level];
1953 /******************************************************************
1954 * convert_driverinfo_W_to_A [internal]
1957 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1958 DWORD level, DWORD outlen, DWORD numentries)
1964 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1966 len = di_sizeof[level] * numentries;
1967 ptr = (LPSTR) out + len;
1970 /* copy the numbers of all PRINTER_INFO_* first */
1971 memcpy(out, pDriversW, len);
1973 #define COPY_STRING(fld) \
1976 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1977 ptr += len; outlen -= len;\
1979 #define COPY_MULTIZ_STRING(fld) \
1980 { LPWSTR p = diW->fld; if (p){ \
1983 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1984 ptr += len; outlen -= len; p += len;\
1986 while(len > 1 && outlen > 0); \
1989 while (id < numentries)
1995 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1996 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1998 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2005 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2006 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2008 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2011 COPY_STRING(pEnvironment);
2012 COPY_STRING(pDriverPath);
2013 COPY_STRING(pDataFile);
2014 COPY_STRING(pConfigFile);
2019 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2020 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2022 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2025 COPY_STRING(pEnvironment);
2026 COPY_STRING(pDriverPath);
2027 COPY_STRING(pDataFile);
2028 COPY_STRING(pConfigFile);
2029 COPY_STRING(pHelpFile);
2030 COPY_MULTIZ_STRING(pDependentFiles);
2031 COPY_STRING(pMonitorName);
2032 COPY_STRING(pDefaultDataType);
2037 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2038 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2040 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2043 COPY_STRING(pEnvironment);
2044 COPY_STRING(pDriverPath);
2045 COPY_STRING(pDataFile);
2046 COPY_STRING(pConfigFile);
2047 COPY_STRING(pHelpFile);
2048 COPY_MULTIZ_STRING(pDependentFiles);
2049 COPY_STRING(pMonitorName);
2050 COPY_STRING(pDefaultDataType);
2051 COPY_MULTIZ_STRING(pszzPreviousNames);
2056 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2057 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2059 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2062 COPY_STRING(pEnvironment);
2063 COPY_STRING(pDriverPath);
2064 COPY_STRING(pDataFile);
2065 COPY_STRING(pConfigFile);
2070 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2071 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2073 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2076 COPY_STRING(pEnvironment);
2077 COPY_STRING(pDriverPath);
2078 COPY_STRING(pDataFile);
2079 COPY_STRING(pConfigFile);
2080 COPY_STRING(pHelpFile);
2081 COPY_MULTIZ_STRING(pDependentFiles);
2082 COPY_STRING(pMonitorName);
2083 COPY_STRING(pDefaultDataType);
2084 COPY_MULTIZ_STRING(pszzPreviousNames);
2085 COPY_STRING(pszMfgName);
2086 COPY_STRING(pszOEMUrl);
2087 COPY_STRING(pszHardwareID);
2088 COPY_STRING(pszProvider);
2093 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2094 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2096 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2099 COPY_STRING(pEnvironment);
2100 COPY_STRING(pDriverPath);
2101 COPY_STRING(pDataFile);
2102 COPY_STRING(pConfigFile);
2103 COPY_STRING(pHelpFile);
2104 COPY_MULTIZ_STRING(pDependentFiles);
2105 COPY_STRING(pMonitorName);
2106 COPY_STRING(pDefaultDataType);
2107 COPY_MULTIZ_STRING(pszzPreviousNames);
2108 COPY_STRING(pszMfgName);
2109 COPY_STRING(pszOEMUrl);
2110 COPY_STRING(pszHardwareID);
2111 COPY_STRING(pszProvider);
2112 COPY_STRING(pszPrintProcessor);
2113 COPY_STRING(pszVendorSetup);
2114 COPY_MULTIZ_STRING(pszzColorProfiles);
2115 COPY_STRING(pszInfPath);
2116 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2122 FIXME("for level %u\n", level);
2125 pDriversW += di_sizeof[level];
2126 out += di_sizeof[level];
2131 #undef COPY_MULTIZ_STRING
2135 /***********************************************************
2138 static void *printer_info_AtoW( const void *data, DWORD level )
2141 UNICODE_STRING usBuffer;
2143 if (!data) return NULL;
2145 if (level < 1 || level > 9) return NULL;
2147 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2148 if (!ret) return NULL;
2150 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2156 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2157 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2159 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2160 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2161 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2162 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2163 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2164 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2165 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2166 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2167 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2168 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2169 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2170 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2177 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2178 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2180 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2185 FIXME( "Unhandled level %d\n", level );
2186 HeapFree( GetProcessHeap(), 0, ret );
2193 /***********************************************************
2196 static void free_printer_info( void *data, DWORD level )
2204 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2206 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2207 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2208 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2209 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2210 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2211 HeapFree( GetProcessHeap(), 0, piW->pComment );
2212 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2213 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2214 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2215 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2216 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2217 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2224 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2226 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2231 FIXME( "Unhandled level %d\n", level );
2234 HeapFree( GetProcessHeap(), 0, data );
2238 /******************************************************************
2239 * DeviceCapabilities [WINSPOOL.@]
2240 * DeviceCapabilitiesA [WINSPOOL.@]
2243 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2244 LPSTR pOutput, LPDEVMODEA lpdm)
2248 if (!GDI_CallDeviceCapabilities16)
2250 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2252 if (!GDI_CallDeviceCapabilities16) return -1;
2254 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2256 /* If DC_PAPERSIZE map POINT16s to POINTs */
2257 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2258 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2259 POINT *pt = (POINT *)pOutput;
2261 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2262 for(i = 0; i < ret; i++, pt++)
2267 HeapFree( GetProcessHeap(), 0, tmp );
2273 /*****************************************************************************
2274 * DeviceCapabilitiesW [WINSPOOL.@]
2276 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2279 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2280 WORD fwCapability, LPWSTR pOutput,
2281 const DEVMODEW *pDevMode)
2283 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2284 LPSTR pDeviceA = strdupWtoA(pDevice);
2285 LPSTR pPortA = strdupWtoA(pPort);
2288 if(pOutput && (fwCapability == DC_BINNAMES ||
2289 fwCapability == DC_FILEDEPENDENCIES ||
2290 fwCapability == DC_PAPERNAMES)) {
2291 /* These need A -> W translation */
2294 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2298 switch(fwCapability) {
2303 case DC_FILEDEPENDENCIES:
2307 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2308 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2310 for(i = 0; i < ret; i++)
2311 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2312 pOutput + (i * size), size);
2313 HeapFree(GetProcessHeap(), 0, pOutputA);
2315 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2316 (LPSTR)pOutput, dmA);
2318 HeapFree(GetProcessHeap(),0,pPortA);
2319 HeapFree(GetProcessHeap(),0,pDeviceA);
2320 HeapFree(GetProcessHeap(),0,dmA);
2324 /******************************************************************
2325 * DocumentPropertiesA [WINSPOOL.@]
2327 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2329 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2330 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2331 LPDEVMODEA pDevModeInput,DWORD fMode )
2333 LPSTR lpName = pDeviceName;
2334 static CHAR port[] = "LPT1:";
2337 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2338 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2342 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2344 ERR("no name from hPrinter?\n");
2345 SetLastError(ERROR_INVALID_HANDLE);
2348 lpName = strdupWtoA(lpNameW);
2351 if (!GDI_CallExtDeviceMode16)
2353 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2355 if (!GDI_CallExtDeviceMode16) {
2356 ERR("No CallExtDeviceMode16?\n");
2360 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2361 pDevModeInput, NULL, fMode);
2364 HeapFree(GetProcessHeap(),0,lpName);
2369 /*****************************************************************************
2370 * DocumentPropertiesW (WINSPOOL.@)
2372 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2374 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2376 LPDEVMODEW pDevModeOutput,
2377 LPDEVMODEW pDevModeInput, DWORD fMode)
2380 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2381 LPDEVMODEA pDevModeInputA;
2382 LPDEVMODEA pDevModeOutputA = NULL;
2385 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2386 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2388 if(pDevModeOutput) {
2389 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2390 if(ret < 0) return ret;
2391 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2393 pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2394 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2395 pDevModeInputA, fMode);
2396 if(pDevModeOutput) {
2397 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2398 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2400 if(fMode == 0 && ret > 0)
2401 ret += (CCHDEVICENAME + CCHFORMNAME);
2402 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2403 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2407 /*****************************************************************************
2408 * IsValidDevmodeA [WINSPOOL.@]
2410 * Validate a DEVMODE structure and fix errors if possible.
2413 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2415 FIXME("(%p,%ld): stub\n", pDevMode, size);
2423 /*****************************************************************************
2424 * IsValidDevmodeW [WINSPOOL.@]
2426 * Validate a DEVMODE structure and fix errors if possible.
2429 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2431 FIXME("(%p,%ld): stub\n", pDevMode, size);
2439 /******************************************************************
2440 * OpenPrinterA [WINSPOOL.@]
2445 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2446 LPPRINTER_DEFAULTSA pDefault)
2448 UNICODE_STRING lpPrinterNameW;
2449 UNICODE_STRING usBuffer;
2450 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2451 PWSTR pwstrPrinterNameW;
2454 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2457 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2458 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2459 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2460 pDefaultW = &DefaultW;
2462 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2464 RtlFreeUnicodeString(&usBuffer);
2465 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2467 RtlFreeUnicodeString(&lpPrinterNameW);
2471 /******************************************************************
2472 * OpenPrinterW [WINSPOOL.@]
2474 * Open a Printer / Printserver or a Printer-Object
2477 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2478 * phPrinter [O] The resulting Handle is stored here
2479 * pDefault [I] PTR to Default Printer Settings or NULL
2486 * lpPrinterName is one of:
2487 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2488 *| Printer: "PrinterName"
2489 *| Printer-Object: "PrinterName,Job xxx"
2490 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2491 *| XcvPort: "Servername,XcvPort PortName"
2494 *| Printer-Object not supported
2495 *| pDefaults is ignored
2498 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2501 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2504 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2505 SetLastError(ERROR_INVALID_PARAMETER);
2509 /* Get the unique handle of the printer or Printserver */
2510 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2515 DWORD deleting = 0, size = sizeof( deleting ), type;
2517 WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key );
2518 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2519 WaitForSingleObject( init_mutex, INFINITE );
2520 status = get_dword_from_reg( key, StatusW );
2521 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2522 ReleaseMutex( init_mutex );
2523 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2524 update_driver( *phPrinter );
2528 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2529 return (*phPrinter != 0);
2532 /******************************************************************
2533 * AddMonitorA [WINSPOOL.@]
2538 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2540 LPWSTR nameW = NULL;
2543 LPMONITOR_INFO_2A mi2a;
2544 MONITOR_INFO_2W mi2w;
2546 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2547 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2548 debugstr_a(mi2a ? mi2a->pName : NULL),
2549 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2550 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2553 SetLastError(ERROR_INVALID_LEVEL);
2557 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2563 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2564 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2565 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2568 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2570 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2571 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2572 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2574 if (mi2a->pEnvironment) {
2575 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2576 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2577 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2579 if (mi2a->pDLLName) {
2580 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2581 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2582 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2585 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2587 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2588 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2589 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2591 HeapFree(GetProcessHeap(), 0, nameW);
2595 /******************************************************************************
2596 * AddMonitorW [WINSPOOL.@]
2598 * Install a Printmonitor
2601 * pName [I] Servername or NULL (local Computer)
2602 * Level [I] Structure-Level (Must be 2)
2603 * pMonitors [I] PTR to MONITOR_INFO_2
2610 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2613 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2615 LPMONITOR_INFO_2W mi2w;
2617 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2618 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2619 debugstr_w(mi2w ? mi2w->pName : NULL),
2620 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2621 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2623 if ((backend == NULL) && !load_backend()) return FALSE;
2626 SetLastError(ERROR_INVALID_LEVEL);
2630 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2635 return backend->fpAddMonitor(pName, Level, pMonitors);
2638 /******************************************************************
2639 * DeletePrinterDriverA [WINSPOOL.@]
2642 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2644 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2647 /******************************************************************
2648 * DeletePrinterDriverW [WINSPOOL.@]
2651 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2653 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2656 /******************************************************************
2657 * DeleteMonitorA [WINSPOOL.@]
2659 * See DeleteMonitorW.
2662 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2664 LPWSTR nameW = NULL;
2665 LPWSTR EnvironmentW = NULL;
2666 LPWSTR MonitorNameW = NULL;
2671 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2672 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2673 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2677 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2678 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2679 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2682 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2683 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2684 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2687 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2689 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2690 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2691 HeapFree(GetProcessHeap(), 0, nameW);
2695 /******************************************************************
2696 * DeleteMonitorW [WINSPOOL.@]
2698 * Delete a specific Printmonitor from a Printing-Environment
2701 * pName [I] Servername or NULL (local Computer)
2702 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2703 * pMonitorName [I] Name of the Monitor, that should be deleted
2710 * pEnvironment is ignored in Windows for the local Computer.
2713 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2716 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2717 debugstr_w(pMonitorName));
2719 if ((backend == NULL) && !load_backend()) return FALSE;
2721 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2725 /******************************************************************
2726 * DeletePortA [WINSPOOL.@]
2731 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2733 LPWSTR nameW = NULL;
2734 LPWSTR portW = NULL;
2738 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2740 /* convert servername to unicode */
2742 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2743 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2744 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2747 /* convert portname to unicode */
2749 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2750 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2751 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2754 res = DeletePortW(nameW, hWnd, portW);
2755 HeapFree(GetProcessHeap(), 0, nameW);
2756 HeapFree(GetProcessHeap(), 0, portW);
2760 /******************************************************************
2761 * DeletePortW [WINSPOOL.@]
2763 * Delete a specific Port
2766 * pName [I] Servername or NULL (local Computer)
2767 * hWnd [I] Handle to parent Window for the Dialog-Box
2768 * pPortName [I] Name of the Port, that should be deleted
2775 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2777 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2779 if ((backend == NULL) && !load_backend()) return FALSE;
2782 SetLastError(RPC_X_NULL_REF_POINTER);
2786 return backend->fpDeletePort(pName, hWnd, pPortName);
2789 /******************************************************************************
2790 * WritePrinter [WINSPOOL.@]
2792 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2794 opened_printer_t *printer;
2797 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2799 EnterCriticalSection(&printer_handles_cs);
2800 printer = get_opened_printer(hPrinter);
2803 SetLastError(ERROR_INVALID_HANDLE);
2809 SetLastError(ERROR_SPL_NO_STARTDOC);
2813 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2815 LeaveCriticalSection(&printer_handles_cs);
2819 /*****************************************************************************
2820 * AddFormA [WINSPOOL.@]
2822 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2824 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2828 /*****************************************************************************
2829 * AddFormW [WINSPOOL.@]
2831 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2833 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2837 /*****************************************************************************
2838 * AddJobA [WINSPOOL.@]
2840 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2843 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2847 SetLastError(ERROR_INVALID_LEVEL);
2851 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2854 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2855 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2856 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2857 if(*pcbNeeded > cbBuf) {
2858 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2861 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2862 addjobA->JobId = addjobW->JobId;
2863 addjobA->Path = (char *)(addjobA + 1);
2864 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2870 /*****************************************************************************
2871 * AddJobW [WINSPOOL.@]
2873 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2875 opened_printer_t *printer;
2878 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2879 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2880 WCHAR path[MAX_PATH], filename[MAX_PATH];
2882 ADDJOB_INFO_1W *addjob;
2884 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2886 EnterCriticalSection(&printer_handles_cs);
2888 printer = get_opened_printer(hPrinter);
2891 SetLastError(ERROR_INVALID_HANDLE);
2896 SetLastError(ERROR_INVALID_LEVEL);
2900 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2904 job->job_id = InterlockedIncrement(&next_job_id);
2906 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2907 if(path[len - 1] != '\\')
2909 memcpy(path + len, spool_path, sizeof(spool_path));
2910 sprintfW(filename, fmtW, path, job->job_id);
2912 len = strlenW(filename);
2913 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2914 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2915 job->portname = NULL;
2916 job->document_title = strdupW(default_doc_title);
2917 job->printer_name = strdupW(printer->name);
2918 job->devmode = dup_devmode( printer->devmode );
2919 list_add_tail(&printer->queue->jobs, &job->entry);
2921 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2922 if(*pcbNeeded <= cbBuf) {
2923 addjob = (ADDJOB_INFO_1W*)pData;
2924 addjob->JobId = job->job_id;
2925 addjob->Path = (WCHAR *)(addjob + 1);
2926 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2929 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2932 LeaveCriticalSection(&printer_handles_cs);
2936 /*****************************************************************************
2937 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2939 * Return the PATH for the Print-Processors
2941 * See GetPrintProcessorDirectoryW.
2945 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2946 DWORD level, LPBYTE Info,
2947 DWORD cbBuf, LPDWORD pcbNeeded)
2949 LPWSTR serverW = NULL;
2954 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2955 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2959 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2960 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2961 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2965 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2966 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2967 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2970 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2971 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2973 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2976 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2977 cbBuf, NULL, NULL) > 0;
2980 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2981 HeapFree(GetProcessHeap(), 0, envW);
2982 HeapFree(GetProcessHeap(), 0, serverW);
2986 /*****************************************************************************
2987 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2989 * Return the PATH for the Print-Processors
2992 * server [I] Servername (NT only) or NULL (local Computer)
2993 * env [I] Printing-Environment (see below) or NULL (Default)
2994 * level [I] Structure-Level (must be 1)
2995 * Info [O] PTR to Buffer that receives the Result
2996 * cbBuf [I] Size of Buffer at "Info"
2997 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2998 * required for the Buffer at "Info"
3001 * Success: TRUE and in pcbNeeded the Bytes used in Info
3002 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3003 * if cbBuf is too small
3005 * Native Values returned in Info on Success:
3006 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3007 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3008 *| win9x(Windows 4.0): "%winsysdir%"
3010 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3013 * Only NULL or "" is supported for server
3016 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3017 DWORD level, LPBYTE Info,
3018 DWORD cbBuf, LPDWORD pcbNeeded)
3021 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3022 Info, cbBuf, pcbNeeded);
3024 if ((backend == NULL) && !load_backend()) return FALSE;
3027 /* (Level != 1) is ignored in win9x */
3028 SetLastError(ERROR_INVALID_LEVEL);
3032 if (pcbNeeded == NULL) {
3033 /* (pcbNeeded == NULL) is ignored in win9x */
3034 SetLastError(RPC_X_NULL_REF_POINTER);
3038 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3041 /*****************************************************************************
3042 * WINSPOOL_OpenDriverReg [internal]
3044 * opens the registry for the printer drivers depending on the given input
3045 * variable pEnvironment
3048 * the opened hkey on success
3051 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3055 const printenv_t * env;
3057 TRACE("(%s)\n", debugstr_w(pEnvironment));
3059 env = validate_envW(pEnvironment);
3060 if (!env) return NULL;
3062 buffer = HeapAlloc( GetProcessHeap(), 0,
3063 (strlenW(DriversW) + strlenW(env->envname) +
3064 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3066 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3067 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3068 HeapFree(GetProcessHeap(), 0, buffer);
3073 /*****************************************************************************
3074 * set_devices_and_printerports [internal]
3076 * set the [Devices] and [PrinterPorts] entries for a printer.
3079 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3081 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3085 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3087 /* FIXME: the driver must change to "winspool" */
3088 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3090 lstrcpyW(devline, driver_nt);
3091 lstrcatW(devline, commaW);
3092 lstrcatW(devline, pi->pPortName);
3094 TRACE("using %s\n", debugstr_w(devline));
3095 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
3096 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3097 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3098 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3102 lstrcatW(devline, timeout_15_45);
3103 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
3104 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3105 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3106 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3109 HeapFree(GetProcessHeap(), 0, devline);
3113 /*****************************************************************************
3114 * AddPrinterW [WINSPOOL.@]
3116 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3118 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3121 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3124 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3127 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3128 SetLastError(ERROR_INVALID_PARAMETER);
3132 ERR("Level = %d, unsupported!\n", Level);
3133 SetLastError(ERROR_INVALID_LEVEL);
3137 SetLastError(ERROR_INVALID_PARAMETER);
3140 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3142 ERR("Can't create Printers key\n");
3145 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3146 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3147 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3148 RegCloseKey(hkeyPrinter);
3149 RegCloseKey(hkeyPrinters);
3152 RegCloseKey(hkeyPrinter);
3154 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3156 ERR("Can't create Drivers key\n");
3157 RegCloseKey(hkeyPrinters);
3160 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3162 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3163 RegCloseKey(hkeyPrinters);
3164 RegCloseKey(hkeyDrivers);
3165 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3168 RegCloseKey(hkeyDriver);
3169 RegCloseKey(hkeyDrivers);
3171 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3172 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3173 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3174 RegCloseKey(hkeyPrinters);
3178 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3180 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3181 SetLastError(ERROR_INVALID_PRINTER_NAME);
3182 RegCloseKey(hkeyPrinters);
3186 set_devices_and_printerports(pi);
3188 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3189 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3190 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3191 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3192 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3193 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3194 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3195 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3196 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3197 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3198 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3199 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3200 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3201 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3202 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3203 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3204 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3205 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3207 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3211 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3212 size = sizeof(DEVMODEW);
3218 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3220 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3222 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3223 HeapFree( GetProcessHeap(), 0, dm );
3228 /* set devmode to printer name */
3229 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3233 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3234 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3236 RegCloseKey(hkeyPrinter);
3237 RegCloseKey(hkeyPrinters);
3238 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3239 ERR("OpenPrinter failing\n");
3245 /*****************************************************************************
3246 * AddPrinterA [WINSPOOL.@]
3248 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3250 UNICODE_STRING pNameW;
3252 PRINTER_INFO_2W *piW;
3253 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3256 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3258 ERR("Level = %d, unsupported!\n", Level);
3259 SetLastError(ERROR_INVALID_LEVEL);
3262 pwstrNameW = asciitounicode(&pNameW,pName);
3263 piW = printer_info_AtoW( piA, Level );
3265 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3267 free_printer_info( piW, Level );
3268 RtlFreeUnicodeString(&pNameW);
3273 /*****************************************************************************
3274 * ClosePrinter [WINSPOOL.@]
3276 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3278 UINT_PTR i = (UINT_PTR)hPrinter;
3279 opened_printer_t *printer = NULL;
3282 TRACE("(%p)\n", hPrinter);
3284 EnterCriticalSection(&printer_handles_cs);
3286 if ((i > 0) && (i <= nb_printer_handles))
3287 printer = printer_handles[i - 1];
3292 struct list *cursor, *cursor2;
3294 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3296 if (printer->backend_printer) {
3297 backend->fpClosePrinter(printer->backend_printer);
3301 EndDocPrinter(hPrinter);
3303 if(InterlockedDecrement(&printer->queue->ref) == 0)
3305 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3307 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3308 ScheduleJob(hPrinter, job->job_id);
3310 HeapFree(GetProcessHeap(), 0, printer->queue);
3313 free_printer_entry( printer );
3314 printer_handles[i - 1] = NULL;
3317 LeaveCriticalSection(&printer_handles_cs);
3321 /*****************************************************************************
3322 * DeleteFormA [WINSPOOL.@]
3324 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3326 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3330 /*****************************************************************************
3331 * DeleteFormW [WINSPOOL.@]
3333 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3335 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3339 /*****************************************************************************
3340 * DeletePrinter [WINSPOOL.@]
3342 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3344 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3345 HKEY hkeyPrinters, hkey;
3346 WCHAR def[MAX_PATH];
3347 DWORD size = sizeof( def ) / sizeof( def[0] );
3350 SetLastError(ERROR_INVALID_HANDLE);
3353 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3354 RegDeleteTreeW(hkeyPrinters, lpNameW);
3355 RegCloseKey(hkeyPrinters);
3357 WriteProfileStringW(devicesW, lpNameW, NULL);
3358 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3360 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3361 RegDeleteValueW(hkey, lpNameW);
3365 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3366 RegDeleteValueW(hkey, lpNameW);
3370 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3372 WriteProfileStringW( windowsW, deviceW, NULL );
3373 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3375 RegDeleteValueW( hkey, deviceW );
3376 RegCloseKey( hkey );
3378 SetDefaultPrinterW( NULL );
3384 /*****************************************************************************
3385 * SetPrinterA [WINSPOOL.@]
3387 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3394 dataW = printer_info_AtoW( data, level );
3395 if (!dataW) return FALSE;
3398 ret = SetPrinterW( printer, level, dataW, command );
3400 if (dataW != data) free_printer_info( dataW, level );
3405 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3407 set_reg_szW( key, NameW, pi->pPrinterName );
3408 set_reg_szW( key, Share_NameW, pi->pShareName );
3409 set_reg_szW( key, PortW, pi->pPortName );
3410 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3411 set_reg_szW( key, DescriptionW, pi->pComment );
3412 set_reg_szW( key, LocationW, pi->pLocation );
3415 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3417 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3418 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3419 set_reg_szW( key, DatatypeW, pi->pDatatype );
3420 set_reg_szW( key, ParametersW, pi->pParameters );
3422 set_reg_DWORD( key, AttributesW, pi->Attributes );
3423 set_reg_DWORD( key, PriorityW, pi->Priority );
3424 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3425 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3426 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3429 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3431 if (!pi->pDevMode) return FALSE;
3433 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3437 /******************************************************************************
3438 * SetPrinterW [WINSPOOL.@]
3440 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3445 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3447 if (command != 0) FIXME( "Ignoring command %d\n", command );
3449 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3456 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3457 set_printer_2( key, pi2 );
3464 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3465 ret = set_printer_9( key, pi );
3470 FIXME( "Unimplemented level %d\n", level );
3471 SetLastError( ERROR_INVALID_LEVEL );
3478 /*****************************************************************************
3479 * SetJobA [WINSPOOL.@]
3481 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3482 LPBYTE pJob, DWORD Command)
3486 UNICODE_STRING usBuffer;
3488 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3490 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3491 are all ignored by SetJob, so we don't bother copying them */
3499 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3500 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3502 JobW = (LPBYTE)info1W;
3503 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3504 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3505 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3506 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3507 info1W->Status = info1A->Status;
3508 info1W->Priority = info1A->Priority;
3509 info1W->Position = info1A->Position;
3510 info1W->PagesPrinted = info1A->PagesPrinted;
3515 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3516 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3518 JobW = (LPBYTE)info2W;
3519 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3520 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3521 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3522 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3523 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3524 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3525 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3526 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3527 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3528 info2W->Status = info2A->Status;
3529 info2W->Priority = info2A->Priority;
3530 info2W->Position = info2A->Position;
3531 info2W->StartTime = info2A->StartTime;
3532 info2W->UntilTime = info2A->UntilTime;
3533 info2W->PagesPrinted = info2A->PagesPrinted;
3537 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3538 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3541 SetLastError(ERROR_INVALID_LEVEL);
3545 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3551 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3552 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3553 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3554 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3555 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3560 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3561 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3562 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3563 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3564 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3565 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3566 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3567 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3568 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3572 HeapFree(GetProcessHeap(), 0, JobW);
3577 /*****************************************************************************
3578 * SetJobW [WINSPOOL.@]
3580 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3581 LPBYTE pJob, DWORD Command)
3586 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3587 FIXME("Ignoring everything other than document title\n");
3589 EnterCriticalSection(&printer_handles_cs);
3590 job = get_job(hPrinter, JobId);
3600 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3601 HeapFree(GetProcessHeap(), 0, job->document_title);
3602 job->document_title = strdupW(info1->pDocument);
3607 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3608 HeapFree(GetProcessHeap(), 0, job->document_title);
3609 job->document_title = strdupW(info2->pDocument);
3610 HeapFree(GetProcessHeap(), 0, job->devmode);
3611 job->devmode = dup_devmode( info2->pDevMode );
3617 SetLastError(ERROR_INVALID_LEVEL);
3622 LeaveCriticalSection(&printer_handles_cs);
3626 /*****************************************************************************
3627 * EndDocPrinter [WINSPOOL.@]
3629 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3631 opened_printer_t *printer;
3633 TRACE("(%p)\n", hPrinter);
3635 EnterCriticalSection(&printer_handles_cs);
3637 printer = get_opened_printer(hPrinter);
3640 SetLastError(ERROR_INVALID_HANDLE);
3646 SetLastError(ERROR_SPL_NO_STARTDOC);
3650 CloseHandle(printer->doc->hf);
3651 ScheduleJob(hPrinter, printer->doc->job_id);
3652 HeapFree(GetProcessHeap(), 0, printer->doc);
3653 printer->doc = NULL;
3656 LeaveCriticalSection(&printer_handles_cs);
3660 /*****************************************************************************
3661 * EndPagePrinter [WINSPOOL.@]
3663 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3665 FIXME("(%p): stub\n", hPrinter);
3669 /*****************************************************************************
3670 * StartDocPrinterA [WINSPOOL.@]
3672 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3674 UNICODE_STRING usBuffer;
3676 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3679 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3680 or one (DOC_INFO_3) extra DWORDs */
3684 doc2W.JobId = doc2->JobId;
3687 doc2W.dwMode = doc2->dwMode;
3690 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3691 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3692 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3696 SetLastError(ERROR_INVALID_LEVEL);
3700 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3702 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3703 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3704 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3709 /*****************************************************************************
3710 * StartDocPrinterW [WINSPOOL.@]
3712 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3714 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3715 opened_printer_t *printer;
3716 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3717 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3718 JOB_INFO_1W job_info;
3719 DWORD needed, ret = 0;
3724 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3725 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3726 debugstr_w(doc->pDatatype));
3728 if(Level < 1 || Level > 3)
3730 SetLastError(ERROR_INVALID_LEVEL);
3734 EnterCriticalSection(&printer_handles_cs);
3735 printer = get_opened_printer(hPrinter);
3738 SetLastError(ERROR_INVALID_HANDLE);
3744 SetLastError(ERROR_INVALID_PRINTER_STATE);
3748 /* Even if we're printing to a file we still add a print job, we'll
3749 just ignore the spool file name */
3751 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3753 ERR("AddJob failed gle %u\n", GetLastError());
3757 /* use pOutputFile only, when it is a real filename */
3758 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3759 filename = doc->pOutputFile;
3761 filename = addjob->Path;
3763 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3764 if(hf == INVALID_HANDLE_VALUE)
3767 memset(&job_info, 0, sizeof(job_info));
3768 job_info.pDocument = doc->pDocName;
3769 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3771 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3772 printer->doc->hf = hf;
3773 ret = printer->doc->job_id = addjob->JobId;
3774 job = get_job(hPrinter, ret);
3775 job->portname = strdupW(doc->pOutputFile);
3778 LeaveCriticalSection(&printer_handles_cs);
3783 /*****************************************************************************
3784 * StartPagePrinter [WINSPOOL.@]
3786 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3788 FIXME("(%p): stub\n", hPrinter);
3792 /*****************************************************************************
3793 * GetFormA [WINSPOOL.@]
3795 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3796 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3798 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3799 Level,pForm,cbBuf,pcbNeeded);
3803 /*****************************************************************************
3804 * GetFormW [WINSPOOL.@]
3806 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3807 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3809 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3810 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3814 /*****************************************************************************
3815 * SetFormA [WINSPOOL.@]
3817 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3820 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3824 /*****************************************************************************
3825 * SetFormW [WINSPOOL.@]
3827 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3830 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3834 /*****************************************************************************
3835 * ReadPrinter [WINSPOOL.@]
3837 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3838 LPDWORD pNoBytesRead)
3840 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3844 /*****************************************************************************
3845 * ResetPrinterA [WINSPOOL.@]
3847 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3849 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3853 /*****************************************************************************
3854 * ResetPrinterW [WINSPOOL.@]
3856 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3858 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3862 /*****************************************************************************
3863 * get_filename_from_reg [internal]
3865 * Get ValueName from hkey storing result in out
3866 * when the Value in the registry has only a filename, use driverdir as prefix
3867 * outlen is space left in out
3868 * String is stored either as unicode or ascii
3872 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3873 LPBYTE out, DWORD outlen, LPDWORD needed)
3875 WCHAR filename[MAX_PATH];
3879 LPWSTR buffer = filename;
3883 size = sizeof(filename);
3885 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3886 if (ret == ERROR_MORE_DATA) {
3887 TRACE("need dynamic buffer: %u\n", size);
3888 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3890 /* No Memory is bad */
3894 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3897 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3898 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3904 /* do we have a full path ? */
3905 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3906 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3909 /* we must build the full Path */
3911 if ((out) && (outlen > dirlen)) {
3912 lstrcpyW((LPWSTR)out, driverdir);
3920 /* write the filename */
3921 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3922 if ((out) && (outlen >= size)) {
3923 lstrcpyW((LPWSTR)out, ptr);
3930 ptr += lstrlenW(ptr)+1;
3931 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3934 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3936 /* write the multisz-termination */
3937 if (type == REG_MULTI_SZ) {
3938 size = sizeof(WCHAR);
3941 if (out && (outlen >= size)) {
3942 memset (out, 0, size);
3948 /*****************************************************************************
3949 * WINSPOOL_GetStringFromReg
3951 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3952 * String is stored as unicode.
3954 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3955 DWORD buflen, DWORD *needed)
3957 DWORD sz = buflen, type;
3960 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3961 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3962 WARN("Got ret = %d\n", ret);
3966 /* add space for terminating '\0' */
3967 sz += sizeof(WCHAR);
3971 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3976 /*****************************************************************************
3977 * WINSPOOL_GetDefaultDevMode
3979 * Get a default DevMode values for wineps.
3983 static void WINSPOOL_GetDefaultDevMode(
3985 DWORD buflen, DWORD *needed)
3988 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3990 /* fill default DEVMODE - should be read from ppd... */
3991 ZeroMemory( &dm, sizeof(dm) );
3992 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3993 dm.dmSpecVersion = DM_SPECVERSION;
3994 dm.dmDriverVersion = 1;
3995 dm.dmSize = sizeof(DEVMODEW);
3996 dm.dmDriverExtra = 0;
3998 DM_ORIENTATION | DM_PAPERSIZE |
3999 DM_PAPERLENGTH | DM_PAPERWIDTH |
4002 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
4003 DM_YRESOLUTION | DM_TTOPTION;
4005 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
4006 dm.u1.s1.dmPaperSize = DMPAPER_A4;
4007 dm.u1.s1.dmPaperLength = 2970;
4008 dm.u1.s1.dmPaperWidth = 2100;
4010 dm.u1.s1.dmScale = 100;
4011 dm.u1.s1.dmCopies = 1;
4012 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
4013 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
4016 dm.dmYResolution = 300; /* 300dpi */
4017 dm.dmTTOption = DMTT_BITMAP;
4020 /* dm.dmLogPixels */
4021 /* dm.dmBitsPerPel */
4022 /* dm.dmPelsWidth */
4023 /* dm.dmPelsHeight */
4024 /* dm.u2.dmDisplayFlags */
4025 /* dm.dmDisplayFrequency */
4026 /* dm.dmICMMethod */
4027 /* dm.dmICMIntent */
4028 /* dm.dmMediaType */
4029 /* dm.dmDitherType */
4030 /* dm.dmReserved1 */
4031 /* dm.dmReserved2 */
4032 /* dm.dmPanningWidth */
4033 /* dm.dmPanningHeight */
4035 if(buflen >= sizeof(DEVMODEW))
4036 memcpy(ptr, &dm, sizeof(DEVMODEW));
4037 *needed = sizeof(DEVMODEW);
4040 /*****************************************************************************
4041 * WINSPOOL_GetDevModeFromReg
4043 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4044 * DevMode is stored either as unicode or ascii.
4046 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4048 DWORD buflen, DWORD *needed)
4050 DWORD sz = buflen, type;
4053 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4054 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4055 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4056 if (sz < sizeof(DEVMODEA))
4058 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4061 /* ensures that dmSize is not erratically bogus if registry is invalid */
4062 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4063 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4064 sz += (CCHDEVICENAME + CCHFORMNAME);
4065 if (ptr && (buflen >= sz)) {
4066 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4067 memcpy(ptr, dmW, sz);
4068 HeapFree(GetProcessHeap(),0,dmW);
4074 /*********************************************************************
4075 * WINSPOOL_GetPrinter_1
4077 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4079 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4080 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4082 DWORD size, left = cbBuf;
4083 BOOL space = (cbBuf > 0);
4088 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4089 if(space && size <= left) {
4090 pi1->pName = (LPWSTR)ptr;
4098 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4099 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4100 if(space && size <= left) {
4101 pi1->pDescription = (LPWSTR)ptr;
4109 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4110 if(space && size <= left) {
4111 pi1->pComment = (LPWSTR)ptr;
4119 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4121 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4122 memset(pi1, 0, sizeof(*pi1));
4126 /*********************************************************************
4127 * WINSPOOL_GetPrinter_2
4129 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4131 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4132 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4134 DWORD size, left = cbBuf;
4135 BOOL space = (cbBuf > 0);
4140 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4141 if(space && size <= left) {
4142 pi2->pPrinterName = (LPWSTR)ptr;
4149 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4150 if(space && size <= left) {
4151 pi2->pShareName = (LPWSTR)ptr;
4158 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4159 if(space && size <= left) {
4160 pi2->pPortName = (LPWSTR)ptr;
4167 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4168 if(space && size <= left) {
4169 pi2->pDriverName = (LPWSTR)ptr;
4176 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4177 if(space && size <= left) {
4178 pi2->pComment = (LPWSTR)ptr;
4185 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4186 if(space && size <= left) {
4187 pi2->pLocation = (LPWSTR)ptr;
4194 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4195 if(space && size <= left) {
4196 pi2->pDevMode = (LPDEVMODEW)ptr;
4205 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4206 if(space && size <= left) {
4207 pi2->pDevMode = (LPDEVMODEW)ptr;
4214 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4215 if(space && size <= left) {
4216 pi2->pSepFile = (LPWSTR)ptr;
4223 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4224 if(space && size <= left) {
4225 pi2->pPrintProcessor = (LPWSTR)ptr;
4232 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4233 if(space && size <= left) {
4234 pi2->pDatatype = (LPWSTR)ptr;
4241 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4242 if(space && size <= left) {
4243 pi2->pParameters = (LPWSTR)ptr;
4251 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4252 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4253 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4254 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4255 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4258 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4259 memset(pi2, 0, sizeof(*pi2));
4264 /*********************************************************************
4265 * WINSPOOL_GetPrinter_4
4267 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4269 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4270 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4272 DWORD size, left = cbBuf;
4273 BOOL space = (cbBuf > 0);
4278 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4279 if(space && size <= left) {
4280 pi4->pPrinterName = (LPWSTR)ptr;
4288 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4291 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4292 memset(pi4, 0, sizeof(*pi4));
4297 /*********************************************************************
4298 * WINSPOOL_GetPrinter_5
4300 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4302 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4303 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4305 DWORD size, left = cbBuf;
4306 BOOL space = (cbBuf > 0);
4311 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4312 if(space && size <= left) {
4313 pi5->pPrinterName = (LPWSTR)ptr;
4320 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4321 if(space && size <= left) {
4322 pi5->pPortName = (LPWSTR)ptr;
4330 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4331 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4332 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4335 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4336 memset(pi5, 0, sizeof(*pi5));
4341 /*********************************************************************
4342 * WINSPOOL_GetPrinter_7
4344 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4346 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4347 DWORD cbBuf, LPDWORD pcbNeeded)
4349 DWORD size, left = cbBuf;
4350 BOOL space = (cbBuf > 0);
4355 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4358 size = sizeof(pi7->pszObjectGUID);
4360 if (space && size <= left) {
4361 pi7->pszObjectGUID = (LPWSTR)ptr;
4368 /* We do not have a Directory Service */
4369 pi7->dwAction = DSPRINT_UNPUBLISH;
4372 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4373 memset(pi7, 0, sizeof(*pi7));
4378 /*********************************************************************
4379 * WINSPOOL_GetPrinter_9
4381 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4383 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4384 DWORD cbBuf, LPDWORD pcbNeeded)
4387 BOOL space = (cbBuf > 0);
4391 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4392 if(space && size <= cbBuf) {
4393 pi9->pDevMode = (LPDEVMODEW)buf;
4400 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4401 if(space && size <= cbBuf) {
4402 pi9->pDevMode = (LPDEVMODEW)buf;
4408 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4409 memset(pi9, 0, sizeof(*pi9));
4414 /*****************************************************************************
4415 * GetPrinterW [WINSPOOL.@]
4417 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4418 DWORD cbBuf, LPDWORD pcbNeeded)
4420 DWORD size, needed = 0, err;
4425 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4427 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4430 SetLastError( err );
4437 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4439 size = sizeof(PRINTER_INFO_2W);
4441 ptr = pPrinter + size;
4443 memset(pPrinter, 0, size);
4448 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4455 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4457 size = sizeof(PRINTER_INFO_4W);
4459 ptr = pPrinter + size;
4461 memset(pPrinter, 0, size);
4466 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4474 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4476 size = sizeof(PRINTER_INFO_5W);
4478 ptr = pPrinter + size;
4480 memset(pPrinter, 0, size);
4486 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4494 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4496 size = sizeof(PRINTER_INFO_6);
4497 if (size <= cbBuf) {
4498 /* FIXME: We do not update the status yet */
4499 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4511 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4513 size = sizeof(PRINTER_INFO_7W);
4514 if (size <= cbBuf) {
4515 ptr = pPrinter + size;
4517 memset(pPrinter, 0, size);
4523 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4530 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4531 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4535 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4537 size = sizeof(PRINTER_INFO_9W);
4539 ptr = pPrinter + size;
4541 memset(pPrinter, 0, size);
4547 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4554 FIXME("Unimplemented level %d\n", Level);
4555 SetLastError(ERROR_INVALID_LEVEL);
4556 RegCloseKey(hkeyPrinter);
4560 RegCloseKey(hkeyPrinter);
4562 TRACE("returning %d needed = %d\n", ret, needed);
4563 if(pcbNeeded) *pcbNeeded = needed;
4565 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4569 /*****************************************************************************
4570 * GetPrinterA [WINSPOOL.@]
4572 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4573 DWORD cbBuf, LPDWORD pcbNeeded)
4579 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4581 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4583 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4584 HeapFree(GetProcessHeap(), 0, buf);
4589 /*****************************************************************************
4590 * WINSPOOL_EnumPrintersW
4592 * Implementation of EnumPrintersW
4594 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4595 DWORD dwLevel, LPBYTE lpbPrinters,
4596 DWORD cbBuf, LPDWORD lpdwNeeded,
4597 LPDWORD lpdwReturned)
4600 HKEY hkeyPrinters, hkeyPrinter;
4601 WCHAR PrinterName[255];
4602 DWORD needed = 0, number = 0;
4603 DWORD used, i, left;
4607 memset(lpbPrinters, 0, cbBuf);
4613 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4614 if(dwType == PRINTER_ENUM_DEFAULT)
4617 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4618 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4619 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4621 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4627 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4628 FIXME("dwType = %08x\n", dwType);
4629 SetLastError(ERROR_INVALID_FLAGS);
4633 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4635 ERR("Can't create Printers key\n");
4639 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4640 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4641 RegCloseKey(hkeyPrinters);
4642 ERR("Can't query Printers key\n");
4645 TRACE("Found %d printers\n", number);
4649 used = number * sizeof(PRINTER_INFO_1W);
4652 used = number * sizeof(PRINTER_INFO_2W);
4655 used = number * sizeof(PRINTER_INFO_4W);
4658 used = number * sizeof(PRINTER_INFO_5W);
4662 SetLastError(ERROR_INVALID_LEVEL);
4663 RegCloseKey(hkeyPrinters);
4666 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4668 for(i = 0; i < number; i++) {
4669 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4671 ERR("Can't enum key number %d\n", i);
4672 RegCloseKey(hkeyPrinters);
4675 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4676 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4678 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4679 RegCloseKey(hkeyPrinters);
4684 buf = lpbPrinters + used;
4685 left = cbBuf - used;
4693 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4696 if(pi) pi += sizeof(PRINTER_INFO_1W);
4699 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4702 if(pi) pi += sizeof(PRINTER_INFO_2W);
4705 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4708 if(pi) pi += sizeof(PRINTER_INFO_4W);
4711 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4714 if(pi) pi += sizeof(PRINTER_INFO_5W);
4717 ERR("Shouldn't be here!\n");
4718 RegCloseKey(hkeyPrinter);
4719 RegCloseKey(hkeyPrinters);
4722 RegCloseKey(hkeyPrinter);
4724 RegCloseKey(hkeyPrinters);
4731 memset(lpbPrinters, 0, cbBuf);
4732 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4736 *lpdwReturned = number;
4737 SetLastError(ERROR_SUCCESS);
4742 /******************************************************************
4743 * EnumPrintersW [WINSPOOL.@]
4745 * Enumerates the available printers, print servers and print
4746 * providers, depending on the specified flags, name and level.
4750 * If level is set to 1:
4751 * Returns an array of PRINTER_INFO_1 data structures in the
4752 * lpbPrinters buffer.
4754 * If level is set to 2:
4755 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4756 * Returns an array of PRINTER_INFO_2 data structures in the
4757 * lpbPrinters buffer. Note that according to MSDN also an
4758 * OpenPrinter should be performed on every remote printer.
4760 * If level is set to 4 (officially WinNT only):
4761 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4762 * Fast: Only the registry is queried to retrieve printer names,
4763 * no connection to the driver is made.
4764 * Returns an array of PRINTER_INFO_4 data structures in the
4765 * lpbPrinters buffer.
4767 * If level is set to 5 (officially WinNT4/Win9x only):
4768 * Fast: Only the registry is queried to retrieve printer names,
4769 * no connection to the driver is made.
4770 * Returns an array of PRINTER_INFO_5 data structures in the
4771 * lpbPrinters buffer.
4773 * If level set to 3 or 6+:
4774 * returns zero (failure!)
4776 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4780 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4781 * - Only levels 2, 4 and 5 are implemented at the moment.
4782 * - 16-bit printer drivers are not enumerated.
4783 * - Returned amount of bytes used/needed does not match the real Windoze
4784 * implementation (as in this implementation, all strings are part
4785 * of the buffer, whereas Win32 keeps them somewhere else)
4786 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4789 * - In a regular Wine installation, no registry settings for printers
4790 * exist, which makes this function return an empty list.
4792 BOOL WINAPI EnumPrintersW(
4793 DWORD dwType, /* [in] Types of print objects to enumerate */
4794 LPWSTR lpszName, /* [in] name of objects to enumerate */
4795 DWORD dwLevel, /* [in] type of printer info structure */
4796 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4797 DWORD cbBuf, /* [in] max size of buffer in bytes */
4798 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4799 LPDWORD lpdwReturned /* [out] number of entries returned */
4802 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4803 lpdwNeeded, lpdwReturned);
4806 /******************************************************************
4807 * EnumPrintersA [WINSPOOL.@]
4812 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4813 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4816 UNICODE_STRING pNameU;
4820 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4821 pPrinters, cbBuf, pcbNeeded, pcReturned);
4823 pNameW = asciitounicode(&pNameU, pName);
4825 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4826 MS Office need this */
4827 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4829 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4831 RtlFreeUnicodeString(&pNameU);
4833 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4835 HeapFree(GetProcessHeap(), 0, pPrintersW);
4839 /*****************************************************************************
4840 * WINSPOOL_GetDriverInfoFromReg [internal]
4842 * Enters the information from the registry into the DRIVER_INFO struct
4845 * zero if the printer driver does not exist in the registry
4846 * (only if Level > 1) otherwise nonzero
4848 static BOOL WINSPOOL_GetDriverInfoFromReg(
4851 const printenv_t * env,
4853 LPBYTE ptr, /* DRIVER_INFO */
4854 LPBYTE pDriverStrings, /* strings buffer */
4855 DWORD cbBuf, /* size of string buffer */
4856 LPDWORD pcbNeeded) /* space needed for str. */
4860 WCHAR driverdir[MAX_PATH];
4862 LPBYTE strPtr = pDriverStrings;
4863 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4865 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4866 debugstr_w(DriverName), env,
4867 Level, di, pDriverStrings, cbBuf);
4869 if (di) ZeroMemory(di, di_sizeof[Level]);
4871 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4872 if (*pcbNeeded <= cbBuf)
4873 strcpyW((LPWSTR)strPtr, DriverName);
4875 /* pName for level 1 has a different offset! */
4877 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4881 /* .cVersion and .pName for level > 1 */
4883 di->cVersion = env->driverversion;
4884 di->pName = (LPWSTR) strPtr;
4885 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4888 /* Reserve Space for the largest subdir and a Backslash*/
4889 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4890 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4891 /* Should never Fail */
4894 lstrcatW(driverdir, env->versionsubdir);
4895 lstrcatW(driverdir, backslashW);
4897 /* dirlen must not include the terminating zero */
4898 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4900 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4901 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4902 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4907 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4910 if (*pcbNeeded <= cbBuf) {
4911 lstrcpyW((LPWSTR)strPtr, env->envname);
4912 if (di) di->pEnvironment = (LPWSTR)strPtr;
4913 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4916 /* .pDriverPath is the Graphics rendering engine.
4917 The full Path is required to avoid a crash in some apps */
4918 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4920 if (*pcbNeeded <= cbBuf)
4921 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4923 if (di) di->pDriverPath = (LPWSTR)strPtr;
4924 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4927 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4928 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4930 if (*pcbNeeded <= cbBuf)
4931 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4933 if (di) di->pDataFile = (LPWSTR)strPtr;
4934 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4937 /* .pConfigFile is the Driver user Interface */
4938 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4940 if (*pcbNeeded <= cbBuf)
4941 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4943 if (di) di->pConfigFile = (LPWSTR)strPtr;
4944 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4948 RegCloseKey(hkeyDriver);
4949 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4954 RegCloseKey(hkeyDriver);
4955 FIXME("level 5: incomplete\n");
4960 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4962 if (*pcbNeeded <= cbBuf)
4963 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4965 if (di) di->pHelpFile = (LPWSTR)strPtr;
4966 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4969 /* .pDependentFiles */
4970 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4972 if (*pcbNeeded <= cbBuf)
4973 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4975 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4976 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4978 else if (GetVersion() & 0x80000000) {
4979 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4980 size = 2 * sizeof(WCHAR);
4982 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4984 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4985 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4988 /* .pMonitorName is the optional Language Monitor */
4989 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4991 if (*pcbNeeded <= cbBuf)
4992 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4994 if (di) di->pMonitorName = (LPWSTR)strPtr;
4995 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4998 /* .pDefaultDataType */
4999 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
5001 if(*pcbNeeded <= cbBuf)
5002 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
5004 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
5005 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5009 RegCloseKey(hkeyDriver);
5010 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5014 /* .pszzPreviousNames */
5015 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
5017 if(*pcbNeeded <= cbBuf)
5018 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
5020 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
5021 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5025 RegCloseKey(hkeyDriver);
5026 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5030 /* support is missing, but not important enough for a FIXME */
5031 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5034 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5036 if(*pcbNeeded <= cbBuf)
5037 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5039 if (di) di->pszMfgName = (LPWSTR)strPtr;
5040 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5044 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5046 if(*pcbNeeded <= cbBuf)
5047 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5049 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5050 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5053 /* .pszHardwareID */
5054 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5056 if(*pcbNeeded <= cbBuf)
5057 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5059 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5060 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5064 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5066 if(*pcbNeeded <= cbBuf)
5067 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5069 if (di) di->pszProvider = (LPWSTR)strPtr;
5070 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5074 RegCloseKey(hkeyDriver);
5078 /* support is missing, but not important enough for a FIXME */
5079 TRACE("level 8: incomplete\n");
5081 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5082 RegCloseKey(hkeyDriver);
5086 /*****************************************************************************
5087 * GetPrinterDriverW [WINSPOOL.@]
5089 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5090 DWORD Level, LPBYTE pDriverInfo,
5091 DWORD cbBuf, LPDWORD pcbNeeded)
5094 WCHAR DriverName[100];
5095 DWORD ret, type, size, needed = 0;
5097 HKEY hkeyPrinter, hkeyDrivers;
5098 const printenv_t * env;
5100 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5101 Level,pDriverInfo,cbBuf, pcbNeeded);
5104 ZeroMemory(pDriverInfo, cbBuf);
5106 if (!(name = get_opened_printer_name(hPrinter))) {
5107 SetLastError(ERROR_INVALID_HANDLE);
5111 if (Level < 1 || Level == 7 || Level > 8) {
5112 SetLastError(ERROR_INVALID_LEVEL);
5116 env = validate_envW(pEnvironment);
5117 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5119 ret = open_printer_reg_key( name, &hkeyPrinter );
5122 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5123 SetLastError( ret );
5127 size = sizeof(DriverName);
5129 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5130 (LPBYTE)DriverName, &size);
5131 RegCloseKey(hkeyPrinter);
5132 if(ret != ERROR_SUCCESS) {
5133 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5137 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5139 ERR("Can't create Drivers key\n");
5143 size = di_sizeof[Level];
5144 if ((size <= cbBuf) && pDriverInfo)
5145 ptr = pDriverInfo + size;
5147 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5148 env, Level, pDriverInfo, ptr,
5149 (cbBuf < size) ? 0 : cbBuf - size,
5151 RegCloseKey(hkeyDrivers);
5155 RegCloseKey(hkeyDrivers);
5157 if(pcbNeeded) *pcbNeeded = size + needed;
5158 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5159 if(cbBuf >= size + needed) return TRUE;
5160 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5164 /*****************************************************************************
5165 * GetPrinterDriverA [WINSPOOL.@]
5167 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5168 DWORD Level, LPBYTE pDriverInfo,
5169 DWORD cbBuf, LPDWORD pcbNeeded)
5172 UNICODE_STRING pEnvW;
5178 ZeroMemory(pDriverInfo, cbBuf);
5179 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5182 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5183 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5186 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5188 HeapFree(GetProcessHeap(), 0, buf);
5190 RtlFreeUnicodeString(&pEnvW);
5194 /*****************************************************************************
5195 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5197 * Return the PATH for the Printer-Drivers (UNICODE)
5200 * pName [I] Servername (NT only) or NULL (local Computer)
5201 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5202 * Level [I] Structure-Level (must be 1)
5203 * pDriverDirectory [O] PTR to Buffer that receives the Result
5204 * cbBuf [I] Size of Buffer at pDriverDirectory
5205 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5206 * required for pDriverDirectory
5209 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5210 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5211 * if cbBuf is too small
5213 * Native Values returned in pDriverDirectory on Success:
5214 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5215 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5216 *| win9x(Windows 4.0): "%winsysdir%"
5218 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5221 *- Only NULL or "" is supported for pName
5224 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5225 DWORD Level, LPBYTE pDriverDirectory,
5226 DWORD cbBuf, LPDWORD pcbNeeded)
5228 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5229 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5231 if ((backend == NULL) && !load_backend()) return FALSE;
5234 /* (Level != 1) is ignored in win9x */
5235 SetLastError(ERROR_INVALID_LEVEL);
5238 if (pcbNeeded == NULL) {
5239 /* (pcbNeeded == NULL) is ignored in win9x */
5240 SetLastError(RPC_X_NULL_REF_POINTER);
5244 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5245 pDriverDirectory, cbBuf, pcbNeeded);
5250 /*****************************************************************************
5251 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5253 * Return the PATH for the Printer-Drivers (ANSI)
5255 * See GetPrinterDriverDirectoryW.
5258 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5261 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5262 DWORD Level, LPBYTE pDriverDirectory,
5263 DWORD cbBuf, LPDWORD pcbNeeded)
5265 UNICODE_STRING nameW, environmentW;
5268 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5269 WCHAR *driverDirectoryW = NULL;
5271 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5272 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5274 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5276 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5277 else nameW.Buffer = NULL;
5278 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5279 else environmentW.Buffer = NULL;
5281 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5282 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5285 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5286 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5288 *pcbNeeded = needed;
5289 ret = needed <= cbBuf;
5291 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5293 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5295 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5296 RtlFreeUnicodeString(&environmentW);
5297 RtlFreeUnicodeString(&nameW);
5302 /*****************************************************************************
5303 * AddPrinterDriverA [WINSPOOL.@]
5305 * See AddPrinterDriverW.
5308 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5310 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5311 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5314 /******************************************************************************
5315 * AddPrinterDriverW (WINSPOOL.@)
5317 * Install a Printer Driver
5320 * pName [I] Servername or NULL (local Computer)
5321 * level [I] Level for the supplied DRIVER_INFO_*W struct
5322 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5329 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5331 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5332 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5335 /*****************************************************************************
5336 * AddPrintProcessorA [WINSPOOL.@]
5338 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5339 LPSTR pPrintProcessorName)
5341 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5342 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5346 /*****************************************************************************
5347 * AddPrintProcessorW [WINSPOOL.@]
5349 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5350 LPWSTR pPrintProcessorName)
5352 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5353 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5357 /*****************************************************************************
5358 * AddPrintProvidorA [WINSPOOL.@]
5360 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5362 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5366 /*****************************************************************************
5367 * AddPrintProvidorW [WINSPOOL.@]
5369 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5371 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5375 /*****************************************************************************
5376 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5378 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5379 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5381 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5382 pDevModeOutput, pDevModeInput);
5386 /*****************************************************************************
5387 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5389 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5390 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5392 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5393 pDevModeOutput, pDevModeInput);
5397 /*****************************************************************************
5398 * PrinterProperties [WINSPOOL.@]
5400 * Displays a dialog to set the properties of the printer.
5403 * nonzero on success or zero on failure
5406 * implemented as stub only
5408 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5409 HANDLE hPrinter /* [in] handle to printer object */
5411 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5412 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5416 /*****************************************************************************
5417 * EnumJobsA [WINSPOOL.@]
5420 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5421 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5424 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5425 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5427 if(pcbNeeded) *pcbNeeded = 0;
5428 if(pcReturned) *pcReturned = 0;
5433 /*****************************************************************************
5434 * EnumJobsW [WINSPOOL.@]
5437 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5438 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5441 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5442 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5444 if(pcbNeeded) *pcbNeeded = 0;
5445 if(pcReturned) *pcReturned = 0;
5449 /*****************************************************************************
5450 * WINSPOOL_EnumPrinterDrivers [internal]
5452 * Delivers information about all printer drivers installed on the
5453 * localhost or a given server
5456 * nonzero on success or zero on failure. If the buffer for the returned
5457 * information is too small the function will return an error
5460 * - only implemented for localhost, foreign hosts will return an error
5462 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5463 DWORD Level, LPBYTE pDriverInfo,
5465 DWORD cbBuf, LPDWORD pcbNeeded,
5466 LPDWORD pcFound, DWORD data_offset)
5470 const printenv_t * env;
5472 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5473 debugstr_w(pName), debugstr_w(pEnvironment),
5474 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5476 env = validate_envW(pEnvironment);
5477 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5481 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5483 ERR("Can't open Drivers key\n");
5487 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5488 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5489 RegCloseKey(hkeyDrivers);
5490 ERR("Can't query Drivers key\n");
5493 TRACE("Found %d Drivers\n", *pcFound);
5495 /* get size of single struct
5496 * unicode and ascii structure have the same size
5498 size = di_sizeof[Level];
5500 if (data_offset == 0)
5501 data_offset = size * (*pcFound);
5502 *pcbNeeded = data_offset;
5504 for( i = 0; i < *pcFound; i++) {
5505 WCHAR DriverNameW[255];
5506 PBYTE table_ptr = NULL;
5507 PBYTE data_ptr = NULL;
5510 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5512 ERR("Can't enum key number %d\n", i);
5513 RegCloseKey(hkeyDrivers);
5517 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5518 table_ptr = pDriverInfo + (driver_index + i) * size;
5519 if (pDriverInfo && *pcbNeeded <= cbBuf)
5520 data_ptr = pDriverInfo + *pcbNeeded;
5522 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5523 env, Level, table_ptr, data_ptr,
5524 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5526 RegCloseKey(hkeyDrivers);
5530 *pcbNeeded += needed;
5533 RegCloseKey(hkeyDrivers);
5535 if(cbBuf < *pcbNeeded){
5536 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5543 /*****************************************************************************
5544 * EnumPrinterDriversW [WINSPOOL.@]
5546 * see function EnumPrinterDrivers for RETURNS, BUGS
5548 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5549 LPBYTE pDriverInfo, DWORD cbBuf,
5550 LPDWORD pcbNeeded, LPDWORD pcReturned)
5552 static const WCHAR allW[] = {'a','l','l',0};
5556 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5558 SetLastError(RPC_X_NULL_REF_POINTER);
5562 /* check for local drivers */
5563 if((pName) && (pName[0])) {
5564 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5565 SetLastError(ERROR_ACCESS_DENIED);
5569 /* check input parameter */
5570 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5571 SetLastError(ERROR_INVALID_LEVEL);
5575 if(pDriverInfo && cbBuf > 0)
5576 memset( pDriverInfo, 0, cbBuf);
5578 /* Exception: pull all printers */
5579 if (pEnvironment && !strcmpW(pEnvironment, allW))
5581 DWORD i, needed, bufsize = cbBuf;
5582 DWORD total_needed = 0;
5583 DWORD total_found = 0;
5586 /* Precompute the overall total; we need this to know
5587 where pointers end and data begins (i.e. data_offset) */
5588 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5591 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5592 NULL, 0, 0, &needed, &found, 0);
5593 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5594 total_needed += needed;
5595 total_found += found;
5598 data_offset = di_sizeof[Level] * total_found;
5603 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5606 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5607 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5608 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5610 *pcReturned += found;
5611 *pcbNeeded = needed;
5612 data_offset = needed;
5613 total_found += found;
5618 /* Normal behavior */
5619 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5620 0, cbBuf, pcbNeeded, &found, 0);
5622 *pcReturned = found;
5627 /*****************************************************************************
5628 * EnumPrinterDriversA [WINSPOOL.@]
5630 * see function EnumPrinterDrivers for RETURNS, BUGS
5632 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5633 LPBYTE pDriverInfo, DWORD cbBuf,
5634 LPDWORD pcbNeeded, LPDWORD pcReturned)
5637 UNICODE_STRING pNameW, pEnvironmentW;
5638 PWSTR pwstrNameW, pwstrEnvironmentW;
5642 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5644 pwstrNameW = asciitounicode(&pNameW, pName);
5645 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5647 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5648 buf, cbBuf, pcbNeeded, pcReturned);
5650 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5652 HeapFree(GetProcessHeap(), 0, buf);
5654 RtlFreeUnicodeString(&pNameW);
5655 RtlFreeUnicodeString(&pEnvironmentW);
5660 /******************************************************************************
5661 * EnumPortsA (WINSPOOL.@)
5666 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5667 LPDWORD pcbNeeded, LPDWORD pcReturned)
5670 LPBYTE bufferW = NULL;
5671 LPWSTR nameW = NULL;
5673 DWORD numentries = 0;
5676 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5677 cbBuf, pcbNeeded, pcReturned);
5679 /* convert servername to unicode */
5681 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5682 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5683 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5685 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5686 needed = cbBuf * sizeof(WCHAR);
5687 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5688 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5690 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5691 if (pcbNeeded) needed = *pcbNeeded;
5692 /* HeapReAlloc return NULL, when bufferW was NULL */
5693 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5694 HeapAlloc(GetProcessHeap(), 0, needed);
5696 /* Try again with the large Buffer */
5697 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5699 needed = pcbNeeded ? *pcbNeeded : 0;
5700 numentries = pcReturned ? *pcReturned : 0;
5703 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5704 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5707 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5708 DWORD entrysize = 0;
5711 LPPORT_INFO_2W pi2w;
5712 LPPORT_INFO_2A pi2a;
5715 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5717 /* First pass: calculate the size for all Entries */
5718 pi2w = (LPPORT_INFO_2W) bufferW;
5719 pi2a = (LPPORT_INFO_2A) pPorts;
5721 while (index < numentries) {
5723 needed += entrysize; /* PORT_INFO_?A */
5724 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5726 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5727 NULL, 0, NULL, NULL);
5729 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5730 NULL, 0, NULL, NULL);
5731 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5732 NULL, 0, NULL, NULL);
5734 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5735 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5736 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5739 /* check for errors and quit on failure */
5740 if (cbBuf < needed) {
5741 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5745 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5746 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5747 cbBuf -= len ; /* free Bytes in the user-Buffer */
5748 pi2w = (LPPORT_INFO_2W) bufferW;
5749 pi2a = (LPPORT_INFO_2A) pPorts;
5751 /* Second Pass: Fill the User Buffer (if we have one) */
5752 while ((index < numentries) && pPorts) {
5754 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5755 pi2a->pPortName = ptr;
5756 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5757 ptr, cbBuf , NULL, NULL);
5761 pi2a->pMonitorName = ptr;
5762 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5763 ptr, cbBuf, NULL, NULL);
5767 pi2a->pDescription = ptr;
5768 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5769 ptr, cbBuf, NULL, NULL);
5773 pi2a->fPortType = pi2w->fPortType;
5774 pi2a->Reserved = 0; /* documented: "must be zero" */
5777 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5778 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5779 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5784 if (pcbNeeded) *pcbNeeded = needed;
5785 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5787 HeapFree(GetProcessHeap(), 0, nameW);
5788 HeapFree(GetProcessHeap(), 0, bufferW);
5790 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5791 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5797 /******************************************************************************
5798 * EnumPortsW (WINSPOOL.@)
5800 * Enumerate available Ports
5803 * pName [I] Servername or NULL (local Computer)
5804 * Level [I] Structure-Level (1 or 2)
5805 * pPorts [O] PTR to Buffer that receives the Result
5806 * cbBuf [I] Size of Buffer at pPorts
5807 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5808 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5812 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5815 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5818 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5819 cbBuf, pcbNeeded, pcReturned);
5821 if ((backend == NULL) && !load_backend()) return FALSE;
5823 /* Level is not checked in win9x */
5824 if (!Level || (Level > 2)) {
5825 WARN("level (%d) is ignored in win9x\n", Level);
5826 SetLastError(ERROR_INVALID_LEVEL);
5829 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5830 SetLastError(RPC_X_NULL_REF_POINTER);
5834 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5837 /******************************************************************************
5838 * GetDefaultPrinterW (WINSPOOL.@)
5841 * This function must read the value from data 'device' of key
5842 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5844 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5848 WCHAR *buffer, *ptr;
5852 SetLastError(ERROR_INVALID_PARAMETER);
5856 /* make the buffer big enough for the stuff from the profile/registry,
5857 * the content must fit into the local buffer to compute the correct
5858 * size even if the extern buffer is too small or not given.
5859 * (20 for ,driver,port) */
5861 len = max(100, (insize + 20));
5862 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5864 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5866 SetLastError (ERROR_FILE_NOT_FOUND);
5870 TRACE("%s\n", debugstr_w(buffer));
5872 if ((ptr = strchrW(buffer, ',')) == NULL)
5874 SetLastError(ERROR_INVALID_NAME);
5880 *namesize = strlenW(buffer) + 1;
5881 if(!name || (*namesize > insize))
5883 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5887 strcpyW(name, buffer);
5890 HeapFree( GetProcessHeap(), 0, buffer);
5895 /******************************************************************************
5896 * GetDefaultPrinterA (WINSPOOL.@)
5898 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5902 WCHAR *bufferW = NULL;
5906 SetLastError(ERROR_INVALID_PARAMETER);
5910 if(name && *namesize) {
5912 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5915 if(!GetDefaultPrinterW( bufferW, namesize)) {
5920 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5924 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5927 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5930 HeapFree( GetProcessHeap(), 0, bufferW);
5935 /******************************************************************************
5936 * SetDefaultPrinterW (WINSPOOL.204)
5938 * Set the Name of the Default Printer
5941 * pszPrinter [I] Name of the Printer or NULL
5948 * When the Parameter is NULL or points to an Empty String and
5949 * a Default Printer was already present, then this Function changes nothing.
5950 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5951 * the First enumerated local Printer is used.
5954 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5956 WCHAR default_printer[MAX_PATH];
5957 LPWSTR buffer = NULL;
5963 TRACE("(%s)\n", debugstr_w(pszPrinter));
5964 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5966 default_printer[0] = '\0';
5967 size = sizeof(default_printer)/sizeof(WCHAR);
5969 /* if we have a default Printer, do nothing. */
5970 if (GetDefaultPrinterW(default_printer, &size))
5974 /* we have no default Printer: search local Printers and use the first */
5975 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5977 default_printer[0] = '\0';
5978 size = sizeof(default_printer)/sizeof(WCHAR);
5979 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5981 pszPrinter = default_printer;
5982 TRACE("using %s\n", debugstr_w(pszPrinter));
5987 if (pszPrinter == NULL) {
5988 TRACE("no local printer found\n");
5989 SetLastError(ERROR_FILE_NOT_FOUND);
5994 /* "pszPrinter" is never empty or NULL here. */
5995 namelen = lstrlenW(pszPrinter);
5996 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5997 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5999 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
6000 HeapFree(GetProcessHeap(), 0, buffer);
6001 SetLastError(ERROR_FILE_NOT_FOUND);
6005 /* read the devices entry for the printer (driver,port) to build the string for the
6006 default device entry (printer,driver,port) */
6007 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
6008 buffer[namelen] = ',';
6009 namelen++; /* move index to the start of the driver */
6011 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
6012 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
6014 TRACE("set device to %s\n", debugstr_w(buffer));
6016 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
6017 TRACE("failed to set the device entry: %d\n", GetLastError());
6018 lres = ERROR_INVALID_PRINTER_NAME;
6021 /* remove the next section, when INIFileMapping is implemented */
6024 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
6025 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6032 if (lres != ERROR_FILE_NOT_FOUND)
6033 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6035 SetLastError(ERROR_INVALID_PRINTER_NAME);
6039 HeapFree(GetProcessHeap(), 0, buffer);
6040 return (lres == ERROR_SUCCESS);
6043 /******************************************************************************
6044 * SetDefaultPrinterA (WINSPOOL.202)
6046 * See SetDefaultPrinterW.
6049 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6051 LPWSTR bufferW = NULL;
6054 TRACE("(%s)\n", debugstr_a(pszPrinter));
6056 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6057 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6058 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6060 res = SetDefaultPrinterW(bufferW);
6061 HeapFree(GetProcessHeap(), 0, bufferW);
6065 /******************************************************************************
6066 * SetPrinterDataExA (WINSPOOL.@)
6068 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6069 LPCSTR pValueName, DWORD Type,
6070 LPBYTE pData, DWORD cbData)
6072 HKEY hkeyPrinter, hkeySubkey;
6075 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6076 debugstr_a(pValueName), Type, pData, cbData);
6078 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6082 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6084 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6085 RegCloseKey(hkeyPrinter);
6088 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6089 RegCloseKey(hkeySubkey);
6090 RegCloseKey(hkeyPrinter);
6094 /******************************************************************************
6095 * SetPrinterDataExW (WINSPOOL.@)
6097 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6098 LPCWSTR pValueName, DWORD Type,
6099 LPBYTE pData, DWORD cbData)
6101 HKEY hkeyPrinter, hkeySubkey;
6104 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6105 debugstr_w(pValueName), Type, pData, cbData);
6107 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6111 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6113 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6114 RegCloseKey(hkeyPrinter);
6117 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6118 RegCloseKey(hkeySubkey);
6119 RegCloseKey(hkeyPrinter);
6123 /******************************************************************************
6124 * SetPrinterDataA (WINSPOOL.@)
6126 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6127 LPBYTE pData, DWORD cbData)
6129 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6133 /******************************************************************************
6134 * SetPrinterDataW (WINSPOOL.@)
6136 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6137 LPBYTE pData, DWORD cbData)
6139 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6143 /******************************************************************************
6144 * GetPrinterDataExA (WINSPOOL.@)
6146 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6147 LPCSTR pValueName, LPDWORD pType,
6148 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6150 opened_printer_t *printer;
6151 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6154 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6155 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6157 printer = get_opened_printer(hPrinter);
6158 if(!printer) return ERROR_INVALID_HANDLE;
6160 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6161 if (ret) return ret;
6163 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6165 if (printer->name) {
6167 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6169 RegCloseKey(hkeyPrinters);
6172 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6173 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6174 RegCloseKey(hkeyPrinter);
6175 RegCloseKey(hkeyPrinters);
6180 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6181 0, pType, pData, pcbNeeded);
6183 if (!ret && !pData) ret = ERROR_MORE_DATA;
6185 RegCloseKey(hkeySubkey);
6186 RegCloseKey(hkeyPrinter);
6187 RegCloseKey(hkeyPrinters);
6189 TRACE("--> %d\n", ret);
6193 /******************************************************************************
6194 * GetPrinterDataExW (WINSPOOL.@)
6196 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6197 LPCWSTR pValueName, LPDWORD pType,
6198 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6200 opened_printer_t *printer;
6201 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6204 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6205 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6207 printer = get_opened_printer(hPrinter);
6208 if(!printer) return ERROR_INVALID_HANDLE;
6210 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6211 if (ret) return ret;
6213 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6215 if (printer->name) {
6217 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6219 RegCloseKey(hkeyPrinters);
6222 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6223 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6224 RegCloseKey(hkeyPrinter);
6225 RegCloseKey(hkeyPrinters);
6230 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6231 0, pType, pData, pcbNeeded);
6233 if (!ret && !pData) ret = ERROR_MORE_DATA;
6235 RegCloseKey(hkeySubkey);
6236 RegCloseKey(hkeyPrinter);
6237 RegCloseKey(hkeyPrinters);
6239 TRACE("--> %d\n", ret);
6243 /******************************************************************************
6244 * GetPrinterDataA (WINSPOOL.@)
6246 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6247 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6249 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6250 pData, nSize, pcbNeeded);
6253 /******************************************************************************
6254 * GetPrinterDataW (WINSPOOL.@)
6256 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6257 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6259 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6260 pData, nSize, pcbNeeded);
6263 /*******************************************************************************
6264 * EnumPrinterDataExW [WINSPOOL.@]
6266 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6267 LPBYTE pEnumValues, DWORD cbEnumValues,
6268 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6270 HKEY hkPrinter, hkSubKey;
6271 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6272 cbValueNameLen, cbMaxValueLen, cbValueLen,
6277 PPRINTER_ENUM_VALUESW ppev;
6279 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6281 if (pKeyName == NULL || *pKeyName == 0)
6282 return ERROR_INVALID_PARAMETER;
6284 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6285 if (ret != ERROR_SUCCESS)
6287 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6292 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6293 if (ret != ERROR_SUCCESS)
6295 r = RegCloseKey (hkPrinter);
6296 if (r != ERROR_SUCCESS)
6297 WARN ("RegCloseKey returned %i\n", r);
6298 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6299 debugstr_w (pKeyName), ret);
6303 ret = RegCloseKey (hkPrinter);
6304 if (ret != ERROR_SUCCESS)
6306 ERR ("RegCloseKey returned %i\n", ret);
6307 r = RegCloseKey (hkSubKey);
6308 if (r != ERROR_SUCCESS)
6309 WARN ("RegCloseKey returned %i\n", r);
6313 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6314 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6315 if (ret != ERROR_SUCCESS)
6317 r = RegCloseKey (hkSubKey);
6318 if (r != ERROR_SUCCESS)
6319 WARN ("RegCloseKey returned %i\n", r);
6320 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6324 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6325 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6327 if (cValues == 0) /* empty key */
6329 r = RegCloseKey (hkSubKey);
6330 if (r != ERROR_SUCCESS)
6331 WARN ("RegCloseKey returned %i\n", r);
6332 *pcbEnumValues = *pnEnumValues = 0;
6333 return ERROR_SUCCESS;
6336 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6338 hHeap = GetProcessHeap ();
6341 ERR ("GetProcessHeap failed\n");
6342 r = RegCloseKey (hkSubKey);
6343 if (r != ERROR_SUCCESS)
6344 WARN ("RegCloseKey returned %i\n", r);
6345 return ERROR_OUTOFMEMORY;
6348 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6349 if (lpValueName == NULL)
6351 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6352 r = RegCloseKey (hkSubKey);
6353 if (r != ERROR_SUCCESS)
6354 WARN ("RegCloseKey returned %i\n", r);
6355 return ERROR_OUTOFMEMORY;
6358 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6359 if (lpValue == NULL)
6361 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6362 if (HeapFree (hHeap, 0, lpValueName) == 0)
6363 WARN ("HeapFree failed with code %i\n", GetLastError ());
6364 r = RegCloseKey (hkSubKey);
6365 if (r != ERROR_SUCCESS)
6366 WARN ("RegCloseKey returned %i\n", r);
6367 return ERROR_OUTOFMEMORY;
6370 TRACE ("pass 1: calculating buffer required for all names and values\n");
6372 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6374 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6376 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6378 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6379 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6380 NULL, NULL, lpValue, &cbValueLen);
6381 if (ret != ERROR_SUCCESS)
6383 if (HeapFree (hHeap, 0, lpValue) == 0)
6384 WARN ("HeapFree failed with code %i\n", GetLastError ());
6385 if (HeapFree (hHeap, 0, lpValueName) == 0)
6386 WARN ("HeapFree failed with code %i\n", GetLastError ());
6387 r = RegCloseKey (hkSubKey);
6388 if (r != ERROR_SUCCESS)
6389 WARN ("RegCloseKey returned %i\n", r);
6390 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6394 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6395 debugstr_w (lpValueName), dwIndex,
6396 cbValueNameLen + 1, cbValueLen);
6398 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6399 cbBufSize += cbValueLen;
6402 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6404 *pcbEnumValues = cbBufSize;
6405 *pnEnumValues = cValues;
6407 if (cbEnumValues < cbBufSize) /* buffer too small */
6409 if (HeapFree (hHeap, 0, lpValue) == 0)
6410 WARN ("HeapFree failed with code %i\n", GetLastError ());
6411 if (HeapFree (hHeap, 0, lpValueName) == 0)
6412 WARN ("HeapFree failed with code %i\n", GetLastError ());
6413 r = RegCloseKey (hkSubKey);
6414 if (r != ERROR_SUCCESS)
6415 WARN ("RegCloseKey returned %i\n", r);
6416 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6417 return ERROR_MORE_DATA;
6420 TRACE ("pass 2: copying all names and values to buffer\n");
6422 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6423 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6425 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6427 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6428 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6429 NULL, &dwType, lpValue, &cbValueLen);
6430 if (ret != ERROR_SUCCESS)
6432 if (HeapFree (hHeap, 0, lpValue) == 0)
6433 WARN ("HeapFree failed with code %i\n", GetLastError ());
6434 if (HeapFree (hHeap, 0, lpValueName) == 0)
6435 WARN ("HeapFree failed with code %i\n", GetLastError ());
6436 r = RegCloseKey (hkSubKey);
6437 if (r != ERROR_SUCCESS)
6438 WARN ("RegCloseKey returned %i\n", r);
6439 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6443 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6444 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6445 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6446 pEnumValues += cbValueNameLen;
6448 /* return # of *bytes* (including trailing \0), not # of chars */
6449 ppev[dwIndex].cbValueName = cbValueNameLen;
6451 ppev[dwIndex].dwType = dwType;
6453 memcpy (pEnumValues, lpValue, cbValueLen);
6454 ppev[dwIndex].pData = pEnumValues;
6455 pEnumValues += cbValueLen;
6457 ppev[dwIndex].cbData = cbValueLen;
6459 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6460 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6463 if (HeapFree (hHeap, 0, lpValue) == 0)
6465 ret = GetLastError ();
6466 ERR ("HeapFree failed with code %i\n", ret);
6467 if (HeapFree (hHeap, 0, lpValueName) == 0)
6468 WARN ("HeapFree failed with code %i\n", GetLastError ());
6469 r = RegCloseKey (hkSubKey);
6470 if (r != ERROR_SUCCESS)
6471 WARN ("RegCloseKey returned %i\n", r);
6475 if (HeapFree (hHeap, 0, lpValueName) == 0)
6477 ret = GetLastError ();
6478 ERR ("HeapFree failed with code %i\n", ret);
6479 r = RegCloseKey (hkSubKey);
6480 if (r != ERROR_SUCCESS)
6481 WARN ("RegCloseKey returned %i\n", r);
6485 ret = RegCloseKey (hkSubKey);
6486 if (ret != ERROR_SUCCESS)
6488 ERR ("RegCloseKey returned %i\n", ret);
6492 return ERROR_SUCCESS;
6495 /*******************************************************************************
6496 * EnumPrinterDataExA [WINSPOOL.@]
6498 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6499 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6500 * what Windows 2000 SP1 does.
6503 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6504 LPBYTE pEnumValues, DWORD cbEnumValues,
6505 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6509 DWORD ret, dwIndex, dwBufSize;
6513 TRACE ("%p %s\n", hPrinter, pKeyName);
6515 if (pKeyName == NULL || *pKeyName == 0)
6516 return ERROR_INVALID_PARAMETER;
6518 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6521 ret = GetLastError ();
6522 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6526 hHeap = GetProcessHeap ();
6529 ERR ("GetProcessHeap failed\n");
6530 return ERROR_OUTOFMEMORY;
6533 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6534 if (pKeyNameW == NULL)
6536 ERR ("Failed to allocate %i bytes from process heap\n",
6537 (LONG)(len * sizeof (WCHAR)));
6538 return ERROR_OUTOFMEMORY;
6541 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6543 ret = GetLastError ();
6544 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6545 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6546 WARN ("HeapFree failed with code %i\n", GetLastError ());
6550 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6551 pcbEnumValues, pnEnumValues);
6552 if (ret != ERROR_SUCCESS)
6554 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6555 WARN ("HeapFree failed with code %i\n", GetLastError ());
6556 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6560 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6562 ret = GetLastError ();
6563 ERR ("HeapFree failed with code %i\n", ret);
6567 if (*pnEnumValues == 0) /* empty key */
6568 return ERROR_SUCCESS;
6571 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6573 PPRINTER_ENUM_VALUESW ppev =
6574 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6576 if (dwBufSize < ppev->cbValueName)
6577 dwBufSize = ppev->cbValueName;
6579 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6580 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6581 dwBufSize = ppev->cbData;
6584 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6586 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6587 if (pBuffer == NULL)
6589 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6590 return ERROR_OUTOFMEMORY;
6593 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6595 PPRINTER_ENUM_VALUESW ppev =
6596 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6598 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6599 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6603 ret = GetLastError ();
6604 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6605 if (HeapFree (hHeap, 0, pBuffer) == 0)
6606 WARN ("HeapFree failed with code %i\n", GetLastError ());
6610 memcpy (ppev->pValueName, pBuffer, len);
6612 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6614 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6615 ppev->dwType != REG_MULTI_SZ)
6618 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6619 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6622 ret = GetLastError ();
6623 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6624 if (HeapFree (hHeap, 0, pBuffer) == 0)
6625 WARN ("HeapFree failed with code %i\n", GetLastError ());
6629 memcpy (ppev->pData, pBuffer, len);
6631 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6632 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6635 if (HeapFree (hHeap, 0, pBuffer) == 0)
6637 ret = GetLastError ();
6638 ERR ("HeapFree failed with code %i\n", ret);
6642 return ERROR_SUCCESS;
6645 /******************************************************************************
6646 * AbortPrinter (WINSPOOL.@)
6648 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6650 FIXME("(%p), stub!\n", hPrinter);
6654 /******************************************************************************
6655 * AddPortA (WINSPOOL.@)
6660 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6662 LPWSTR nameW = NULL;
6663 LPWSTR monitorW = NULL;
6667 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6670 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6671 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6672 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6676 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6677 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6678 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6680 res = AddPortW(nameW, hWnd, monitorW);
6681 HeapFree(GetProcessHeap(), 0, nameW);
6682 HeapFree(GetProcessHeap(), 0, monitorW);
6686 /******************************************************************************
6687 * AddPortW (WINSPOOL.@)
6689 * Add a Port for a specific Monitor
6692 * pName [I] Servername or NULL (local Computer)
6693 * hWnd [I] Handle to parent Window for the Dialog-Box
6694 * pMonitorName [I] Name of the Monitor that manage the Port
6701 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6703 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6705 if ((backend == NULL) && !load_backend()) return FALSE;
6707 if (!pMonitorName) {
6708 SetLastError(RPC_X_NULL_REF_POINTER);
6712 return backend->fpAddPort(pName, hWnd, pMonitorName);
6715 /******************************************************************************
6716 * AddPortExA (WINSPOOL.@)
6721 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6724 PORT_INFO_2A * pi2A;
6725 LPWSTR nameW = NULL;
6726 LPWSTR monitorW = NULL;
6730 pi2A = (PORT_INFO_2A *) pBuffer;
6732 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6733 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6735 if ((level < 1) || (level > 2)) {
6736 SetLastError(ERROR_INVALID_LEVEL);
6741 SetLastError(ERROR_INVALID_PARAMETER);
6746 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6747 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6748 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6752 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6753 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6754 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6757 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6759 if (pi2A->pPortName) {
6760 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6761 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6762 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6766 if (pi2A->pMonitorName) {
6767 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6768 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6769 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6772 if (pi2A->pDescription) {
6773 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6774 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6775 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6777 pi2W.fPortType = pi2A->fPortType;
6778 pi2W.Reserved = pi2A->Reserved;
6781 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6783 HeapFree(GetProcessHeap(), 0, nameW);
6784 HeapFree(GetProcessHeap(), 0, monitorW);
6785 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6786 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6787 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6792 /******************************************************************************
6793 * AddPortExW (WINSPOOL.@)
6795 * Add a Port for a specific Monitor, without presenting a user interface
6798 * pName [I] Servername or NULL (local Computer)
6799 * level [I] Structure-Level (1 or 2) for pBuffer
6800 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6801 * pMonitorName [I] Name of the Monitor that manage the Port
6808 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6812 pi2 = (PORT_INFO_2W *) pBuffer;
6814 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6815 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6816 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6817 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6819 if ((backend == NULL) && !load_backend()) return FALSE;
6821 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6822 SetLastError(ERROR_INVALID_PARAMETER);
6826 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6829 /******************************************************************************
6830 * AddPrinterConnectionA (WINSPOOL.@)
6832 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6834 FIXME("%s\n", debugstr_a(pName));
6838 /******************************************************************************
6839 * AddPrinterConnectionW (WINSPOOL.@)
6841 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6843 FIXME("%s\n", debugstr_w(pName));
6847 /******************************************************************************
6848 * AddPrinterDriverExW (WINSPOOL.@)
6850 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6853 * pName [I] Servername or NULL (local Computer)
6854 * level [I] Level for the supplied DRIVER_INFO_*W struct
6855 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6856 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6863 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6865 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6867 if ((backend == NULL) && !load_backend()) return FALSE;
6869 if (level < 2 || level == 5 || level == 7 || level > 8) {
6870 SetLastError(ERROR_INVALID_LEVEL);
6875 SetLastError(ERROR_INVALID_PARAMETER);
6879 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6882 /******************************************************************************
6883 * AddPrinterDriverExA (WINSPOOL.@)
6885 * See AddPrinterDriverExW.
6888 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6890 DRIVER_INFO_8A *diA;
6892 LPWSTR nameW = NULL;
6897 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6899 diA = (DRIVER_INFO_8A *) pDriverInfo;
6900 ZeroMemory(&diW, sizeof(diW));
6902 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6903 SetLastError(ERROR_INVALID_LEVEL);
6908 SetLastError(ERROR_INVALID_PARAMETER);
6912 /* convert servername to unicode */
6914 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6915 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6916 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6920 diW.cVersion = diA->cVersion;
6923 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6924 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6925 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6928 if (diA->pEnvironment) {
6929 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6930 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6931 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6934 if (diA->pDriverPath) {
6935 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6936 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6937 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6940 if (diA->pDataFile) {
6941 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6942 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6943 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6946 if (diA->pConfigFile) {
6947 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6948 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6949 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6952 if ((Level > 2) && diA->pDependentFiles) {
6953 lenA = multi_sz_lenA(diA->pDependentFiles);
6954 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6955 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6956 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6959 if ((Level > 2) && diA->pMonitorName) {
6960 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6961 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6962 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6965 if ((Level > 3) && diA->pDefaultDataType) {
6966 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6967 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6968 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6971 if ((Level > 3) && diA->pszzPreviousNames) {
6972 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6973 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6974 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6975 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6978 if ((Level > 5) && diA->pszMfgName) {
6979 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6980 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6981 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6984 if ((Level > 5) && diA->pszOEMUrl) {
6985 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6986 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6987 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6990 if ((Level > 5) && diA->pszHardwareID) {
6991 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6992 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6993 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6996 if ((Level > 5) && diA->pszProvider) {
6997 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6998 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6999 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
7003 FIXME("level %u is incomplete\n", Level);
7006 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
7007 TRACE("got %u with %u\n", res, GetLastError());
7008 HeapFree(GetProcessHeap(), 0, nameW);
7009 HeapFree(GetProcessHeap(), 0, diW.pName);
7010 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
7011 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
7012 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
7013 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
7014 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
7015 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
7016 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
7017 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
7018 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
7019 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
7020 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
7021 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
7023 TRACE("=> %u with %u\n", res, GetLastError());
7027 /******************************************************************************
7028 * ConfigurePortA (WINSPOOL.@)
7030 * See ConfigurePortW.
7033 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7035 LPWSTR nameW = NULL;
7036 LPWSTR portW = NULL;
7040 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7042 /* convert servername to unicode */
7044 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7045 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7046 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7049 /* convert portname to unicode */
7051 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7052 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7053 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7056 res = ConfigurePortW(nameW, hWnd, portW);
7057 HeapFree(GetProcessHeap(), 0, nameW);
7058 HeapFree(GetProcessHeap(), 0, portW);
7062 /******************************************************************************
7063 * ConfigurePortW (WINSPOOL.@)
7065 * Display the Configuration-Dialog for a specific Port
7068 * pName [I] Servername or NULL (local Computer)
7069 * hWnd [I] Handle to parent Window for the Dialog-Box
7070 * pPortName [I] Name of the Port, that should be configured
7077 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7080 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7082 if ((backend == NULL) && !load_backend()) return FALSE;
7085 SetLastError(RPC_X_NULL_REF_POINTER);
7089 return backend->fpConfigurePort(pName, hWnd, pPortName);
7092 /******************************************************************************
7093 * ConnectToPrinterDlg (WINSPOOL.@)
7095 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7097 FIXME("%p %x\n", hWnd, Flags);
7101 /******************************************************************************
7102 * DeletePrinterConnectionA (WINSPOOL.@)
7104 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7106 FIXME("%s\n", debugstr_a(pName));
7110 /******************************************************************************
7111 * DeletePrinterConnectionW (WINSPOOL.@)
7113 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7115 FIXME("%s\n", debugstr_w(pName));
7119 /******************************************************************************
7120 * DeletePrinterDriverExW (WINSPOOL.@)
7122 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7123 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7128 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7129 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7131 if(pName && pName[0])
7133 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7134 SetLastError(ERROR_INVALID_PARAMETER);
7140 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7141 SetLastError(ERROR_INVALID_PARAMETER);
7145 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7149 ERR("Can't open drivers key\n");
7153 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7156 RegCloseKey(hkey_drivers);
7161 /******************************************************************************
7162 * DeletePrinterDriverExA (WINSPOOL.@)
7164 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7165 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7167 UNICODE_STRING NameW, EnvW, DriverW;
7170 asciitounicode(&NameW, pName);
7171 asciitounicode(&EnvW, pEnvironment);
7172 asciitounicode(&DriverW, pDriverName);
7174 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7176 RtlFreeUnicodeString(&DriverW);
7177 RtlFreeUnicodeString(&EnvW);
7178 RtlFreeUnicodeString(&NameW);
7183 /******************************************************************************
7184 * DeletePrinterDataExW (WINSPOOL.@)
7186 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7189 FIXME("%p %s %s\n", hPrinter,
7190 debugstr_w(pKeyName), debugstr_w(pValueName));
7191 return ERROR_INVALID_PARAMETER;
7194 /******************************************************************************
7195 * DeletePrinterDataExA (WINSPOOL.@)
7197 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7200 FIXME("%p %s %s\n", hPrinter,
7201 debugstr_a(pKeyName), debugstr_a(pValueName));
7202 return ERROR_INVALID_PARAMETER;
7205 /******************************************************************************
7206 * DeletePrintProcessorA (WINSPOOL.@)
7208 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7210 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7211 debugstr_a(pPrintProcessorName));
7215 /******************************************************************************
7216 * DeletePrintProcessorW (WINSPOOL.@)
7218 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7220 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7221 debugstr_w(pPrintProcessorName));
7225 /******************************************************************************
7226 * DeletePrintProvidorA (WINSPOOL.@)
7228 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7230 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7231 debugstr_a(pPrintProviderName));
7235 /******************************************************************************
7236 * DeletePrintProvidorW (WINSPOOL.@)
7238 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7240 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7241 debugstr_w(pPrintProviderName));
7245 /******************************************************************************
7246 * EnumFormsA (WINSPOOL.@)
7248 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7249 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7251 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7252 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7256 /******************************************************************************
7257 * EnumFormsW (WINSPOOL.@)
7259 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7260 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7262 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7263 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7267 /*****************************************************************************
7268 * EnumMonitorsA [WINSPOOL.@]
7270 * See EnumMonitorsW.
7273 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7274 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7277 LPBYTE bufferW = NULL;
7278 LPWSTR nameW = NULL;
7280 DWORD numentries = 0;
7283 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7284 cbBuf, pcbNeeded, pcReturned);
7286 /* convert servername to unicode */
7288 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7289 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7290 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7292 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7293 needed = cbBuf * sizeof(WCHAR);
7294 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7295 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7297 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7298 if (pcbNeeded) needed = *pcbNeeded;
7299 /* HeapReAlloc return NULL, when bufferW was NULL */
7300 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7301 HeapAlloc(GetProcessHeap(), 0, needed);
7303 /* Try again with the large Buffer */
7304 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7306 numentries = pcReturned ? *pcReturned : 0;
7309 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7310 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7313 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7314 DWORD entrysize = 0;
7317 LPMONITOR_INFO_2W mi2w;
7318 LPMONITOR_INFO_2A mi2a;
7320 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7321 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7323 /* First pass: calculate the size for all Entries */
7324 mi2w = (LPMONITOR_INFO_2W) bufferW;
7325 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7327 while (index < numentries) {
7329 needed += entrysize; /* MONITOR_INFO_?A */
7330 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7332 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7333 NULL, 0, NULL, NULL);
7335 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7336 NULL, 0, NULL, NULL);
7337 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7338 NULL, 0, NULL, NULL);
7340 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7341 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7342 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7345 /* check for errors and quit on failure */
7346 if (cbBuf < needed) {
7347 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7351 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7352 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7353 cbBuf -= len ; /* free Bytes in the user-Buffer */
7354 mi2w = (LPMONITOR_INFO_2W) bufferW;
7355 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7357 /* Second Pass: Fill the User Buffer (if we have one) */
7358 while ((index < numentries) && pMonitors) {
7360 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7362 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7363 ptr, cbBuf , NULL, NULL);
7367 mi2a->pEnvironment = ptr;
7368 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7369 ptr, cbBuf, NULL, NULL);
7373 mi2a->pDLLName = ptr;
7374 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7375 ptr, cbBuf, NULL, NULL);
7379 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7380 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7381 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7385 if (pcbNeeded) *pcbNeeded = needed;
7386 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7388 HeapFree(GetProcessHeap(), 0, nameW);
7389 HeapFree(GetProcessHeap(), 0, bufferW);
7391 TRACE("returning %d with %d (%d byte for %d entries)\n",
7392 (res), GetLastError(), needed, numentries);
7398 /*****************************************************************************
7399 * EnumMonitorsW [WINSPOOL.@]
7401 * Enumerate available Port-Monitors
7404 * pName [I] Servername or NULL (local Computer)
7405 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7406 * pMonitors [O] PTR to Buffer that receives the Result
7407 * cbBuf [I] Size of Buffer at pMonitors
7408 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7409 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7413 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7416 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7417 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7420 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7421 cbBuf, pcbNeeded, pcReturned);
7423 if ((backend == NULL) && !load_backend()) return FALSE;
7425 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7426 SetLastError(RPC_X_NULL_REF_POINTER);
7430 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7433 /******************************************************************************
7434 * SpoolerInit (WINSPOOL.@)
7436 * Initialize the Spooler
7443 * The function fails on windows, when the spooler service is not running
7446 BOOL WINAPI SpoolerInit(void)
7449 if ((backend == NULL) && !load_backend()) return FALSE;
7453 /******************************************************************************
7454 * XcvDataW (WINSPOOL.@)
7456 * Execute commands in the Printmonitor DLL
7459 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7460 * pszDataName [i] Name of the command to execute
7461 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7462 * cbInputData [i] Size in Bytes of Buffer at pInputData
7463 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7464 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7465 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7466 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7473 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7474 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7476 * Minimal List of commands, that a Printmonitor DLL should support:
7478 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7479 *| "AddPort" : Add a Port
7480 *| "DeletePort": Delete a Port
7482 * Many Printmonitors support additional commands. Examples for localspl.dll:
7483 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7484 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7487 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7488 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7489 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7491 opened_printer_t *printer;
7493 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7494 pInputData, cbInputData, pOutputData,
7495 cbOutputData, pcbOutputNeeded, pdwStatus);
7497 if ((backend == NULL) && !load_backend()) return FALSE;
7499 printer = get_opened_printer(hXcv);
7500 if (!printer || (!printer->backend_printer)) {
7501 SetLastError(ERROR_INVALID_HANDLE);
7505 if (!pcbOutputNeeded) {
7506 SetLastError(ERROR_INVALID_PARAMETER);
7510 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7511 SetLastError(RPC_X_NULL_REF_POINTER);
7515 *pcbOutputNeeded = 0;
7517 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7518 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7522 /*****************************************************************************
7523 * EnumPrinterDataA [WINSPOOL.@]
7526 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7527 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7528 DWORD cbData, LPDWORD pcbData )
7530 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7531 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7532 return ERROR_NO_MORE_ITEMS;
7535 /*****************************************************************************
7536 * EnumPrinterDataW [WINSPOOL.@]
7539 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7540 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7541 DWORD cbData, LPDWORD pcbData )
7543 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7544 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7545 return ERROR_NO_MORE_ITEMS;
7548 /*****************************************************************************
7549 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7552 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7553 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7554 LPDWORD pcbNeeded, LPDWORD pcReturned)
7556 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7557 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7558 pcbNeeded, pcReturned);
7562 /*****************************************************************************
7563 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7566 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7567 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7568 LPDWORD pcbNeeded, LPDWORD pcReturned)
7570 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7571 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7572 pcbNeeded, pcReturned);
7576 /*****************************************************************************
7577 * EnumPrintProcessorsA [WINSPOOL.@]
7579 * See EnumPrintProcessorsW.
7582 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7583 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7586 LPBYTE bufferW = NULL;
7587 LPWSTR nameW = NULL;
7590 DWORD numentries = 0;
7593 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7594 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7596 /* convert names to unicode */
7598 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7599 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7600 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7603 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7604 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7605 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7608 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7609 needed = cbBuf * sizeof(WCHAR);
7610 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7611 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7613 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7614 if (pcbNeeded) needed = *pcbNeeded;
7615 /* HeapReAlloc return NULL, when bufferW was NULL */
7616 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7617 HeapAlloc(GetProcessHeap(), 0, needed);
7619 /* Try again with the large Buffer */
7620 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7622 numentries = pcReturned ? *pcReturned : 0;
7626 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7629 PPRINTPROCESSOR_INFO_1W ppiw;
7630 PPRINTPROCESSOR_INFO_1A ppia;
7632 /* First pass: calculate the size for all Entries */
7633 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7634 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7636 while (index < numentries) {
7638 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7639 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7641 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7642 NULL, 0, NULL, NULL);
7644 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7645 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7648 /* check for errors and quit on failure */
7649 if (cbBuf < needed) {
7650 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7655 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7656 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7657 cbBuf -= len ; /* free Bytes in the user-Buffer */
7658 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7659 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7661 /* Second Pass: Fill the User Buffer (if we have one) */
7662 while ((index < numentries) && pPPInfo) {
7664 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7666 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7667 ptr, cbBuf , NULL, NULL);
7671 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7672 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7677 if (pcbNeeded) *pcbNeeded = needed;
7678 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7680 HeapFree(GetProcessHeap(), 0, nameW);
7681 HeapFree(GetProcessHeap(), 0, envW);
7682 HeapFree(GetProcessHeap(), 0, bufferW);
7684 TRACE("returning %d with %d (%d byte for %d entries)\n",
7685 (res), GetLastError(), needed, numentries);
7690 /*****************************************************************************
7691 * EnumPrintProcessorsW [WINSPOOL.@]
7693 * Enumerate available Print Processors
7696 * pName [I] Servername or NULL (local Computer)
7697 * pEnvironment [I] Printing-Environment or NULL (Default)
7698 * Level [I] Structure-Level (Only 1 is allowed)
7699 * pPPInfo [O] PTR to Buffer that receives the Result
7700 * cbBuf [I] Size of Buffer at pPPInfo
7701 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7702 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7706 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7709 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7710 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7713 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7714 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7716 if ((backend == NULL) && !load_backend()) return FALSE;
7718 if (!pcbNeeded || !pcReturned) {
7719 SetLastError(RPC_X_NULL_REF_POINTER);
7723 if (!pPPInfo && (cbBuf > 0)) {
7724 SetLastError(ERROR_INVALID_USER_BUFFER);
7728 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7729 cbBuf, pcbNeeded, pcReturned);
7732 /*****************************************************************************
7733 * ExtDeviceMode [WINSPOOL.@]
7736 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7737 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7740 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7741 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7742 debugstr_a(pProfile), fMode);
7746 /*****************************************************************************
7747 * FindClosePrinterChangeNotification [WINSPOOL.@]
7750 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7752 FIXME("Stub: %p\n", hChange);
7756 /*****************************************************************************
7757 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7760 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7761 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7763 FIXME("Stub: %p %x %x %p\n",
7764 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7765 return INVALID_HANDLE_VALUE;
7768 /*****************************************************************************
7769 * FindNextPrinterChangeNotification [WINSPOOL.@]
7772 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7773 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7775 FIXME("Stub: %p %p %p %p\n",
7776 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7780 /*****************************************************************************
7781 * FreePrinterNotifyInfo [WINSPOOL.@]
7784 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7786 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7790 /*****************************************************************************
7793 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7794 * ansi depending on the unicode parameter.
7796 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7806 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7809 memcpy(ptr, str, *size);
7816 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7819 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7826 /*****************************************************************************
7829 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7830 LPDWORD pcbNeeded, BOOL unicode)
7832 DWORD size, left = cbBuf;
7833 BOOL space = (cbBuf > 0);
7840 ji1->JobId = job->job_id;
7843 string_to_buf(job->document_title, ptr, left, &size, unicode);
7844 if(space && size <= left)
7846 ji1->pDocument = (LPWSTR)ptr;
7854 if (job->printer_name)
7856 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7857 if(space && size <= left)
7859 ji1->pPrinterName = (LPWSTR)ptr;
7871 /*****************************************************************************
7874 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7875 LPDWORD pcbNeeded, BOOL unicode)
7877 DWORD size, left = cbBuf;
7879 BOOL space = (cbBuf > 0);
7881 LPDEVMODEA dmA = NULL;
7888 ji2->JobId = job->job_id;
7891 string_to_buf(job->document_title, ptr, left, &size, unicode);
7892 if(space && size <= left)
7894 ji2->pDocument = (LPWSTR)ptr;
7902 if (job->printer_name)
7904 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7905 if(space && size <= left)
7907 ji2->pPrinterName = (LPWSTR)ptr;
7920 dmA = DEVMODEdupWtoA(job->devmode);
7921 devmode = (LPDEVMODEW) dmA;
7922 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7926 devmode = job->devmode;
7927 size = devmode->dmSize + devmode->dmDriverExtra;
7931 FIXME("Can't convert DEVMODE W to A\n");
7934 /* align DEVMODE to a DWORD boundary */
7935 shift = (4 - (*pcbNeeded & 3)) & 3;
7941 memcpy(ptr, devmode, size-shift);
7942 ji2->pDevMode = (LPDEVMODEW)ptr;
7943 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7956 /*****************************************************************************
7959 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7960 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7963 DWORD needed = 0, size;
7967 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7969 EnterCriticalSection(&printer_handles_cs);
7970 job = get_job(hPrinter, JobId);
7977 size = sizeof(JOB_INFO_1W);
7982 memset(pJob, 0, size);
7986 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7991 size = sizeof(JOB_INFO_2W);
7996 memset(pJob, 0, size);
8000 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
8005 size = sizeof(JOB_INFO_3);
8009 memset(pJob, 0, size);
8018 SetLastError(ERROR_INVALID_LEVEL);
8022 *pcbNeeded = needed;
8024 LeaveCriticalSection(&printer_handles_cs);
8028 /*****************************************************************************
8029 * GetJobA [WINSPOOL.@]
8032 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8033 DWORD cbBuf, LPDWORD pcbNeeded)
8035 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8038 /*****************************************************************************
8039 * GetJobW [WINSPOOL.@]
8042 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8043 DWORD cbBuf, LPDWORD pcbNeeded)
8045 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8048 /*****************************************************************************
8051 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8054 char *unixname, *cmdA;
8056 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8062 if(!(unixname = wine_get_unix_file_name(filename)))
8065 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8066 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8067 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8069 TRACE("printing with: %s\n", cmdA);
8071 if((file_fd = open(unixname, O_RDONLY)) == -1)
8076 ERR("pipe() failed!\n");
8080 if ((pid = fork()) == 0)
8086 /* reset signals that we previously set to SIG_IGN */
8087 signal(SIGPIPE, SIG_DFL);
8089 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8094 ERR("fork() failed!\n");
8098 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8099 write(fds[1], buf, no_read);
8106 wret = waitpid(pid, &status, 0);
8107 } while (wret < 0 && errno == EINTR);
8110 ERR("waitpid() failed!\n");
8113 if (!WIFEXITED(status) || WEXITSTATUS(status))
8115 ERR("child process failed! %d\n", status);
8122 if(file_fd != -1) close(file_fd);
8123 if(fds[0] != -1) close(fds[0]);
8124 if(fds[1] != -1) close(fds[1]);
8126 HeapFree(GetProcessHeap(), 0, cmdA);
8127 HeapFree(GetProcessHeap(), 0, unixname);
8134 /*****************************************************************************
8137 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8140 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8143 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8144 sprintfW(cmd, fmtW, printer_name);
8146 r = schedule_pipe(cmd, filename);
8148 HeapFree(GetProcessHeap(), 0, cmd);
8152 #ifdef SONAME_LIBCUPS
8153 /*****************************************************************************
8154 * get_cups_jobs_ticket_options
8156 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8157 * The CUPS scheduler only looks for these in Print-File requests, and since
8158 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8161 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8163 FILE *fp = fopen( file, "r" );
8164 char buf[257]; /* DSC max of 256 + '\0' */
8165 const char *ps_adobe = "%!PS-Adobe-";
8166 const char *cups_job = "%cupsJobTicket:";
8168 if (!fp) return num_options;
8169 if (!fgets( buf, sizeof(buf), fp )) goto end;
8170 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8171 while (fgets( buf, sizeof(buf), fp ))
8173 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8174 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8183 /*****************************************************************************
8186 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8188 #ifdef SONAME_LIBCUPS
8191 char *unixname, *queue, *unix_doc_title;
8194 int num_options = 0, i;
8195 cups_option_t *options = NULL;
8197 if(!(unixname = wine_get_unix_file_name(filename)))
8200 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8201 queue = HeapAlloc(GetProcessHeap(), 0, len);
8202 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8204 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8205 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8206 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8208 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8210 TRACE( "printing via cups with options:\n" );
8211 for (i = 0; i < num_options; i++)
8212 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8214 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8216 pcupsFreeOptions( num_options, options );
8218 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8219 HeapFree(GetProcessHeap(), 0, queue);
8220 HeapFree(GetProcessHeap(), 0, unixname);
8226 return schedule_lpr(printer_name, filename);
8230 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8237 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8241 if(HIWORD(wparam) == BN_CLICKED)
8243 if(LOWORD(wparam) == IDOK)
8246 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8249 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8250 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8252 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8254 WCHAR caption[200], message[200];
8257 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8258 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8259 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8260 if(mb_ret == IDCANCEL)
8262 HeapFree(GetProcessHeap(), 0, filename);
8266 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8267 if(hf == INVALID_HANDLE_VALUE)
8269 WCHAR caption[200], message[200];
8271 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8272 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8273 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8274 HeapFree(GetProcessHeap(), 0, filename);
8278 DeleteFileW(filename);
8279 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8281 EndDialog(hwnd, IDOK);
8284 if(LOWORD(wparam) == IDCANCEL)
8286 EndDialog(hwnd, IDCANCEL);
8295 /*****************************************************************************
8298 static BOOL get_filename(LPWSTR *filename)
8300 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8301 file_dlg_proc, (LPARAM)filename) == IDOK;
8304 /*****************************************************************************
8307 static BOOL schedule_file(LPCWSTR filename)
8309 LPWSTR output = NULL;
8311 if(get_filename(&output))
8314 TRACE("copy to %s\n", debugstr_w(output));
8315 r = CopyFileW(filename, output, FALSE);
8316 HeapFree(GetProcessHeap(), 0, output);
8322 /*****************************************************************************
8325 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8327 int in_fd, out_fd, no_read;
8330 char *unixname, *outputA;
8333 if(!(unixname = wine_get_unix_file_name(filename)))
8336 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8337 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8338 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8340 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8341 in_fd = open(unixname, O_RDONLY);
8342 if(out_fd == -1 || in_fd == -1)
8345 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8346 write(out_fd, buf, no_read);
8350 if(in_fd != -1) close(in_fd);
8351 if(out_fd != -1) close(out_fd);
8352 HeapFree(GetProcessHeap(), 0, outputA);
8353 HeapFree(GetProcessHeap(), 0, unixname);
8357 /*****************************************************************************
8358 * ScheduleJob [WINSPOOL.@]
8361 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8363 opened_printer_t *printer;
8365 struct list *cursor, *cursor2;
8367 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8368 EnterCriticalSection(&printer_handles_cs);
8369 printer = get_opened_printer(hPrinter);
8373 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8375 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8378 if(job->job_id != dwJobID) continue;
8380 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8381 if(hf != INVALID_HANDLE_VALUE)
8383 PRINTER_INFO_5W *pi5 = NULL;
8384 LPWSTR portname = job->portname;
8388 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8389 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8393 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8394 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8395 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8396 portname = pi5->pPortName;
8398 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8399 debugstr_w(portname));
8403 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8404 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8406 DWORD type, count = sizeof(output);
8407 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8410 if(output[0] == '|')
8412 ret = schedule_pipe(output + 1, job->filename);
8416 ret = schedule_unixfile(output, job->filename);
8418 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8420 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8422 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8424 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8426 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8428 ret = schedule_file(job->filename);
8432 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8434 HeapFree(GetProcessHeap(), 0, pi5);
8436 DeleteFileW(job->filename);
8438 list_remove(cursor);
8439 HeapFree(GetProcessHeap(), 0, job->document_title);
8440 HeapFree(GetProcessHeap(), 0, job->printer_name);
8441 HeapFree(GetProcessHeap(), 0, job->portname);
8442 HeapFree(GetProcessHeap(), 0, job->filename);
8443 HeapFree(GetProcessHeap(), 0, job->devmode);
8444 HeapFree(GetProcessHeap(), 0, job);
8448 LeaveCriticalSection(&printer_handles_cs);
8452 /*****************************************************************************
8453 * StartDocDlgA [WINSPOOL.@]
8455 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8457 UNICODE_STRING usBuffer;
8460 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8463 docW.cbSize = sizeof(docW);
8464 if (doc->lpszDocName)
8466 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8467 if (!(docW.lpszDocName = docnameW)) return NULL;
8469 if (doc->lpszOutput)
8471 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8472 if (!(docW.lpszOutput = outputW)) return NULL;
8474 if (doc->lpszDatatype)
8476 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8477 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8479 docW.fwType = doc->fwType;
8481 retW = StartDocDlgW(hPrinter, &docW);
8485 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8486 ret = HeapAlloc(GetProcessHeap(), 0, len);
8487 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8488 HeapFree(GetProcessHeap(), 0, retW);
8491 HeapFree(GetProcessHeap(), 0, datatypeW);
8492 HeapFree(GetProcessHeap(), 0, outputW);
8493 HeapFree(GetProcessHeap(), 0, docnameW);
8498 /*****************************************************************************
8499 * StartDocDlgW [WINSPOOL.@]
8501 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8502 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8503 * port is "FILE:". Also returns the full path if passed a relative path.
8505 * The caller should free the returned string from the process heap.
8507 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8512 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8514 PRINTER_INFO_5W *pi5;
8515 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8516 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8518 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8519 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8520 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8522 HeapFree(GetProcessHeap(), 0, pi5);
8525 HeapFree(GetProcessHeap(), 0, pi5);
8528 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8532 if (get_filename(&name))
8534 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8536 HeapFree(GetProcessHeap(), 0, name);
8539 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8540 GetFullPathNameW(name, len, ret, NULL);
8541 HeapFree(GetProcessHeap(), 0, name);
8546 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8549 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8550 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8552 attr = GetFileAttributesW(ret);
8553 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8555 HeapFree(GetProcessHeap(), 0, ret);