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 #define NONAMELESSUNION
49 #define NONAMELESSSTRUCT
50 #include "wine/library.h"
59 #include "wine/windef16.h"
60 #include "wine/unicode.h"
61 #include "wine/debug.h"
62 #include "wine/list.h"
65 #include "ddk/winsplp.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
70 /* ############################### */
72 static CRITICAL_SECTION printer_handles_cs;
73 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
75 0, 0, &printer_handles_cs,
76 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
77 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
79 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
81 /* ############################### */
96 HANDLE backend_printer;
107 WCHAR *document_title;
117 LPCWSTR versionregpath;
118 LPCWSTR versionsubdir;
121 /* ############################### */
123 static opened_printer_t **printer_handles;
124 static UINT nb_printer_handles;
125 static LONG next_job_id = 1;
127 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
128 WORD fwCapability, LPSTR lpszOutput,
130 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
131 LPSTR lpszDevice, LPSTR lpszPort,
132 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
135 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
136 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
137 'c','o','n','t','r','o','l','\\',
138 'P','r','i','n','t','\\',
139 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
140 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
142 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
143 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
144 'C','o','n','t','r','o','l','\\',
145 'P','r','i','n','t','\\',
146 'P','r','i','n','t','e','r','s',0};
148 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
150 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
151 'M','i','c','r','o','s','o','f','t','\\',
152 'W','i','n','d','o','w','s',' ','N','T','\\',
153 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
154 'W','i','n','d','o','w','s',0};
156 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
157 'M','i','c','r','o','s','o','f','t','\\',
158 'W','i','n','d','o','w','s',' ','N','T','\\',
159 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
160 'D','e','v','i','c','e','s',0};
162 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
163 'M','i','c','r','o','s','o','f','t','\\',
164 'W','i','n','d','o','w','s',' ','N','T','\\',
165 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
166 'P','o','r','t','s',0};
168 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
169 'M','i','c','r','o','s','o','f','t','\\',
170 'W','i','n','d','o','w','s',' ','N','T','\\',
171 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
172 'P','r','i','n','t','e','r','P','o','r','t','s',0};
174 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
175 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
176 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
177 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
178 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
179 static const WCHAR subdir_x64W[] = {'x','6','4',0};
180 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
181 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
182 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
183 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
184 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
186 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
188 static const WCHAR AttributesW[] = {'A','t','t','r','i','b','u','t','e','s',0};
189 static const WCHAR backslashW[] = {'\\',0};
190 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
191 'i','o','n',' ','F','i','l','e',0};
192 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
193 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
194 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
195 static const WCHAR Default_PriorityW[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
196 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
197 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
198 static const WCHAR dnsTimeoutW[] = {'d','n','s','T','i','m','e','o','u','t',0};
199 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
200 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
201 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
202 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
203 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
204 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
205 static const WCHAR NameW[] = {'N','a','m','e',0};
206 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
207 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
208 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
209 static const WCHAR PortW[] = {'P','o','r','t',0};
210 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
211 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
212 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
213 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
214 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
215 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
216 static const WCHAR PriorityW[] = {'P','r','i','o','r','i','t','y',0};
217 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
218 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
219 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
220 static const WCHAR StartTimeW[] = {'S','t','a','r','t','T','i','m','e',0};
221 static const WCHAR StatusW[] = {'S','t','a','t','u','s',0};
222 static const WCHAR txTimeoutW[] = {'t','x','T','i','m','e','o','u','t',0};
223 static const WCHAR UntilTimeW[] = {'U','n','t','i','l','T','i','m','e',0};
224 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
225 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
226 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
227 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
228 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
229 static WCHAR rawW[] = {'R','A','W',0};
230 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
231 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
232 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
233 static const WCHAR commaW[] = {',',0};
234 static WCHAR emptyStringW[] = {0};
236 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
238 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
239 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
240 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
242 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
243 'D','o','c','u','m','e','n','t',0};
245 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
246 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
247 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
248 0, sizeof(DRIVER_INFO_8W)};
251 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
252 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
253 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
254 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
255 sizeof(PRINTER_INFO_9W)};
257 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
258 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
259 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
261 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
263 /******************************************************************
264 * validate the user-supplied printing-environment [internal]
267 * env [I] PTR to Environment-String or NULL
271 * Success: PTR to printenv_t
274 * An empty string is handled the same way as NULL.
275 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
279 static const printenv_t * validate_envW(LPCWSTR env)
281 const printenv_t *result = NULL;
284 TRACE("testing %s\n", debugstr_w(env));
287 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
289 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
291 result = all_printenv[i];
296 if (result == NULL) {
297 FIXME("unsupported Environment: %s\n", debugstr_w(env));
298 SetLastError(ERROR_INVALID_ENVIRONMENT);
300 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
304 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
306 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
312 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
313 if passed a NULL string. This returns NULLs to the result.
315 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
319 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
320 return usBufferPtr->Buffer;
322 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
326 static LPWSTR strdupW(LPCWSTR p)
332 len = (strlenW(p) + 1) * sizeof(WCHAR);
333 ret = HeapAlloc(GetProcessHeap(), 0, len);
338 static LPSTR strdupWtoA( LPCWSTR str )
343 if (!str) return NULL;
344 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
345 ret = HeapAlloc( GetProcessHeap(), 0, len );
346 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
350 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
354 if (!dm) return NULL;
355 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
356 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
360 /***********************************************************
362 * Creates an ansi copy of supplied devmode
364 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
369 if (!dmW) return NULL;
370 size = dmW->dmSize - CCHDEVICENAME -
371 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
373 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
374 if (!dmA) return NULL;
376 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
377 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
379 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
381 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
382 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
386 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
387 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
388 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
389 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
391 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
395 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
400 /******************************************************************
401 * verify, that the filename is a local file
404 static inline BOOL is_local_file(LPWSTR name)
406 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
409 /* ################################ */
411 static int multi_sz_lenA(const char *str)
413 const char *ptr = str;
417 ptr += lstrlenA(ptr) + 1;
420 return ptr - str + 1;
423 /*****************************************************************************
426 * Return DWORD associated with name from hkey.
428 static DWORD get_dword_from_reg( HKEY hkey, const WCHAR *name )
430 DWORD sz = sizeof(DWORD), type, value = 0;
433 ret = RegQueryValueExW( hkey, name, 0, &type, (LPBYTE)&value, &sz );
435 if (ret != ERROR_SUCCESS)
437 WARN( "Got ret = %d on name %s\n", ret, debugstr_w(name) );
440 if (type != REG_DWORD)
442 ERR( "Got type %d\n", type );
448 static inline DWORD set_reg_DWORD( HKEY hkey, const WCHAR *keyname, const DWORD value )
450 return RegSetValueExW( hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value) );
454 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
457 /* If forcing, or no profile string entry for device yet, set the entry
459 * The always change entry if not WINEPS yet is discussable.
462 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
464 !strstr(qbuf,"WINEPS.DRV")
466 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
469 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
470 WriteProfileStringA("windows","device",buf);
471 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
472 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
475 HeapFree(GetProcessHeap(),0,buf);
479 static BOOL add_printer_driver(WCHAR *name, WCHAR *ppd)
483 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
486 di3.pEnvironment = envname_x86W;
487 di3.pDriverPath = driver_nt;
489 di3.pConfigFile = driver_nt;
490 di3.pDefaultDataType = rawW;
492 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
493 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
496 di3.pEnvironment = envname_win40W;
497 di3.pDriverPath = driver_9x;
498 di3.pConfigFile = driver_9x;
499 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
500 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
505 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
509 static inline char *expand_env_string( char *str, DWORD type )
511 if (type == REG_EXPAND_SZ)
514 DWORD needed = ExpandEnvironmentStringsA( str, NULL, 0 );
515 tmp = HeapAlloc( GetProcessHeap(), 0, needed );
518 ExpandEnvironmentStringsA( str, tmp, needed );
519 HeapFree( GetProcessHeap(), 0, str );
526 static char *get_fallback_ppd_name( const char *printer_name )
528 static const WCHAR ppds_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
529 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
533 const char *data_dir, *filename;
535 if (RegOpenKeyW( HKEY_CURRENT_USER, ppds_key, &hkey ) == ERROR_SUCCESS )
537 const char *value_name = NULL;
539 if (RegQueryValueExA( hkey, printer_name, 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
540 value_name = printer_name;
541 else if (RegQueryValueExA( hkey, "generic", 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
542 value_name = "generic";
546 ret = HeapAlloc( GetProcessHeap(), 0, needed );
547 if (!ret) return NULL;
548 RegQueryValueExA( hkey, value_name, 0, &type, (BYTE *)ret, &needed );
551 if (ret) return expand_env_string( ret, type );
554 if ((data_dir = wine_get_data_dir())) filename = "/generic.ppd";
555 else if ((data_dir = wine_get_build_dir())) filename = "/dlls/wineps.drv/generic.ppd";
558 ERR( "Error getting PPD file name for printer '%s'\n", debugstr_a(printer_name) );
561 ret = HeapAlloc( GetProcessHeap(), 0, strlen(data_dir) + strlen(filename) + 1 );
564 strcpy( ret, data_dir );
565 strcat( ret, filename );
571 static BOOL copy_file( const char *src, const char *dst )
573 int fds[2] = {-1, -1}, num;
577 fds[0] = open( src, O_RDONLY );
578 fds[1] = open( dst, O_CREAT | O_TRUNC | O_WRONLY, 0666 );
579 if (fds[0] == -1 || fds[1] == -1) goto fail;
581 while ((num = read( fds[0], buf, sizeof(buf) )) != 0)
583 if (num == -1) goto fail;
584 if (write( fds[1], buf, num ) != num) goto fail;
589 if (fds[1] != -1) close( fds[1] );
590 if (fds[0] != -1) close( fds[0] );
594 static BOOL get_fallback_ppd( const char *printer_name, const WCHAR *ppd )
596 char *src = get_fallback_ppd_name( printer_name );
597 char *dst = wine_get_unix_file_name( ppd );
600 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name), debugstr_w(ppd), debugstr_a(src) );
602 if (!src || !dst) goto fail;
604 if (symlink( src, dst ) == -1)
605 if (errno != ENOSYS || !copy_file( src, dst ))
610 HeapFree( GetProcessHeap(), 0, dst );
611 HeapFree( GetProcessHeap(), 0, src );
615 static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
617 static const WCHAR dot_ppd[] = {'.','p','p','d',0};
618 int len = (strlenW( dir ) + strlenW( file_name )) * sizeof(WCHAR) + sizeof(dot_ppd);
619 WCHAR *ppd = HeapAlloc( GetProcessHeap(), 0, len );
621 if (!ppd) return NULL;
623 strcatW( ppd, file_name );
624 strcatW( ppd, dot_ppd );
629 static WCHAR *get_ppd_dir( void )
631 static const WCHAR wine_ppds[] = {'w','i','n','e','_','p','p','d','s','\\',0};
633 WCHAR *dir, tmp_path[MAX_PATH];
636 len = GetTempPathW( sizeof(tmp_path) / sizeof(tmp_path[0]), tmp_path );
637 if (!len) return NULL;
638 dir = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
639 if (!dir) return NULL;
641 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
642 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
643 res = CreateDirectoryW( dir, NULL );
644 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
646 HeapFree( GetProcessHeap(), 0, dir );
649 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
653 static void unlink_ppd( const WCHAR *ppd )
655 char *unix_name = wine_get_unix_file_name( ppd );
657 HeapFree( GetProcessHeap(), 0, unix_name );
660 #ifdef SONAME_LIBCUPS
662 static void *cupshandle;
665 DO_FUNC(cupsFreeDests); \
666 DO_FUNC(cupsFreeOptions); \
667 DO_FUNC(cupsGetDests); \
668 DO_FUNC(cupsGetPPD); \
669 DO_FUNC(cupsParseOptions); \
670 DO_FUNC(cupsPrintFile);
671 #define CUPS_OPT_FUNCS \
672 DO_FUNC(cupsGetPPD3);
674 #define DO_FUNC(f) static typeof(f) *p##f
677 static http_status_t (*pcupsGetPPD3)(http_t *,const char *, time_t *, char *, size_t);
679 static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name,
680 time_t *modtime, char *buffer,
685 if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
687 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
690 ppd = pcupsGetPPD( name );
692 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
694 if (!ppd) return HTTP_NOT_FOUND;
696 if (rename( ppd, buffer ) == -1)
698 BOOL res = copy_file( ppd, buffer );
700 if (!res) return HTTP_NOT_FOUND;
705 static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
708 http_status_t http_status;
709 char *unix_name = wine_get_unix_file_name( ppd );
711 TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
713 if (!unix_name) return FALSE;
715 http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
716 unix_name, strlen( unix_name ) + 1 );
717 HeapFree( GetProcessHeap(), 0, unix_name );
719 if (http_status == HTTP_OK) return TRUE;
721 TRACE( "failed to get ppd for printer %s from cups, calling fallback\n", debugstr_a(printer_name) );
722 return get_fallback_ppd( printer_name, ppd );
725 static WCHAR comment_cups[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
726 ' ','u','s','i','n','g',' ','C','U','P','S',0};
728 static BOOL CUPS_LoadPrinters(void)
731 BOOL hadprinter = FALSE, haddefault = FALSE;
734 WCHAR *port, *ppd_dir = NULL, *ppd;
735 HKEY hkeyPrinter, hkeyPrinters;
737 WCHAR nameW[MAX_PATH];
738 HANDLE added_printer;
740 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
742 TRACE("%s\n", loaderror);
745 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
747 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
750 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 );
754 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
756 ERR("Can't create Printers key\n");
760 nrofdests = pcupsGetDests(&dests);
761 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
762 for (i=0;i<nrofdests;i++) {
763 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
765 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
766 lstrcpyW(port, CUPS_Port);
767 lstrcatW(port, nameW);
769 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
770 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
771 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
772 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
774 TRACE("Printer already exists\n");
775 /* overwrite old LPR:* port */
776 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
777 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
778 /* flag that the PPD file should be checked for an update */
779 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
780 RegCloseKey(hkeyPrinter);
782 BOOL added_driver = FALSE;
784 if (!ppd_dir) ppd_dir = get_ppd_dir();
785 ppd = get_ppd_filename( ppd_dir, nameW );
786 if (get_cups_ppd( dests[i].name, ppd ))
788 added_driver = add_printer_driver( nameW, ppd );
791 HeapFree( GetProcessHeap(), 0, ppd );
792 if (!added_driver) continue;
794 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
795 pi2.pPrinterName = nameW;
796 pi2.pDatatype = rawW;
797 pi2.pPrintProcessor = WinPrintW;
798 pi2.pDriverName = nameW;
799 pi2.pComment = comment_cups;
800 pi2.pLocation = emptyStringW;
801 pi2.pPortName = port;
802 pi2.pParameters = emptyStringW;
803 pi2.pShareName = emptyStringW;
804 pi2.pSepFile = emptyStringW;
806 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
807 if (added_printer) ClosePrinter( added_printer );
808 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
809 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
811 HeapFree(GetProcessHeap(),0,port);
814 if (dests[i].is_default) {
815 SetDefaultPrinterW(nameW);
822 RemoveDirectoryW( ppd_dir );
823 HeapFree( GetProcessHeap(), 0, ppd_dir );
826 if (hadprinter && !haddefault) {
827 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
828 SetDefaultPrinterW(nameW);
830 pcupsFreeDests(nrofdests, dests);
831 RegCloseKey(hkeyPrinters);
836 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
838 PRINTER_INFO_2A pinfo2a;
841 char *e,*s,*name,*prettyname,*devname;
842 BOOL ret = FALSE, set_default = FALSE;
843 char *port = NULL, *env_default;
844 HKEY hkeyPrinter, hkeyPrinters = NULL;
845 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
846 HANDLE added_printer;
848 while (isspace(*pent)) pent++;
849 r = strchr(pent,':');
853 name_len = strlen(pent);
854 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
855 memcpy(name, pent, name_len);
856 name[name_len] = '\0';
862 TRACE("name=%s entry=%s\n",name, pent);
864 if(ispunct(*name)) { /* a tc entry, not a real printer */
865 TRACE("skipping tc entry\n");
869 if(strstr(pent,":server")) { /* server only version so skip */
870 TRACE("skipping server entry\n");
874 /* Determine whether this is a postscript printer. */
877 env_default = getenv("PRINTER");
879 /* Get longest name, usually the one at the right for later display. */
880 while((s=strchr(prettyname,'|'))) {
883 while(isspace(*--e)) *e = '\0';
884 TRACE("\t%s\n", debugstr_a(prettyname));
885 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
886 for(prettyname = s+1; isspace(*prettyname); prettyname++)
889 e = prettyname + strlen(prettyname);
890 while(isspace(*--e)) *e = '\0';
891 TRACE("\t%s\n", debugstr_a(prettyname));
892 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
894 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
895 * if it is too long, we use it as comment below. */
896 devname = prettyname;
897 if (strlen(devname)>=CCHDEVICENAME-1)
899 if (strlen(devname)>=CCHDEVICENAME-1) {
904 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
905 sprintf(port,"LPR:%s",name);
907 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
909 ERR("Can't create Printers key\n");
914 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
916 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
917 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
919 TRACE("Printer already exists\n");
920 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
921 RegCloseKey(hkeyPrinter);
923 static CHAR data_type[] = "RAW",
924 print_proc[] = "WinPrint",
925 comment[] = "WINEPS Printer using LPR",
926 params[] = "<parameters?>",
927 share_name[] = "<share name?>",
928 sep_file[] = "<sep file?>";
929 BOOL added_driver = FALSE;
931 if (!ppd_dir) ppd_dir = get_ppd_dir();
932 ppd = get_ppd_filename( ppd_dir, devnameW );
933 if (get_fallback_ppd( devname, ppd ))
935 added_driver = add_printer_driver( devnameW, ppd );
938 HeapFree( GetProcessHeap(), 0, ppd );
939 if (!added_driver) goto end;
941 memset(&pinfo2a,0,sizeof(pinfo2a));
942 pinfo2a.pPrinterName = devname;
943 pinfo2a.pDatatype = data_type;
944 pinfo2a.pPrintProcessor = print_proc;
945 pinfo2a.pDriverName = devname;
946 pinfo2a.pComment = comment;
947 pinfo2a.pLocation = prettyname;
948 pinfo2a.pPortName = port;
949 pinfo2a.pParameters = params;
950 pinfo2a.pShareName = share_name;
951 pinfo2a.pSepFile = sep_file;
953 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
954 if (added_printer) ClosePrinter( added_printer );
955 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
956 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
959 if (isfirst || set_default)
960 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
963 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
966 RemoveDirectoryW( ppd_dir );
967 HeapFree( GetProcessHeap(), 0, ppd_dir );
969 HeapFree(GetProcessHeap(), 0, port);
970 HeapFree(GetProcessHeap(), 0, name);
975 PRINTCAP_LoadPrinters(void) {
976 BOOL hadprinter = FALSE;
980 BOOL had_bash = FALSE;
982 f = fopen("/etc/printcap","r");
986 while(fgets(buf,sizeof(buf),f)) {
989 end=strchr(buf,'\n');
993 while(isspace(*start)) start++;
994 if(*start == '#' || *start == '\0')
997 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
998 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
999 HeapFree(GetProcessHeap(),0,pent);
1003 if (end && *--end == '\\') {
1010 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1013 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1019 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1020 HeapFree(GetProcessHeap(),0,pent);
1026 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1029 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1030 (lstrlenW(value) + 1) * sizeof(WCHAR));
1032 return ERROR_FILE_NOT_FOUND;
1035 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1037 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1038 DWORD ret = ERROR_FILE_NOT_FOUND;
1040 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1041 and we support these drivers. NT writes DEVMODEW so somehow
1042 we'll need to distinguish between these when we support NT
1047 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1048 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1049 HeapFree( GetProcessHeap(), 0, dmA );
1055 /******************************************************************
1056 * get_servername_from_name (internal)
1058 * for an external server, a copy of the serverpart from the full name is returned
1061 static LPWSTR get_servername_from_name(LPCWSTR name)
1065 WCHAR buffer[MAX_PATH];
1068 if (name == NULL) return NULL;
1069 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1071 server = strdupW(&name[2]); /* skip over both backslash */
1072 if (server == NULL) return NULL;
1074 /* strip '\' and the printername */
1075 ptr = strchrW(server, '\\');
1076 if (ptr) ptr[0] = '\0';
1078 TRACE("found %s\n", debugstr_w(server));
1080 len = sizeof(buffer)/sizeof(buffer[0]);
1081 if (GetComputerNameW(buffer, &len)) {
1082 if (lstrcmpW(buffer, server) == 0) {
1083 /* The requested Servername is our computername */
1084 HeapFree(GetProcessHeap(), 0, server);
1091 /******************************************************************
1092 * get_basename_from_name (internal)
1094 * skip over the serverpart from the full name
1097 static LPCWSTR get_basename_from_name(LPCWSTR name)
1099 if (name == NULL) return NULL;
1100 if ((name[0] == '\\') && (name[1] == '\\')) {
1101 /* skip over the servername and search for the following '\' */
1102 name = strchrW(&name[2], '\\');
1103 if ((name) && (name[1])) {
1104 /* found a separator ('\') followed by a name:
1105 skip over the separator and return the rest */
1110 /* no basename present (we found only a servername) */
1117 static void free_printer_entry( opened_printer_t *printer )
1119 /* the queue is shared, so don't free that here */
1120 HeapFree( GetProcessHeap(), 0, printer->printername );
1121 HeapFree( GetProcessHeap(), 0, printer->name );
1122 HeapFree( GetProcessHeap(), 0, printer->devmode );
1123 HeapFree( GetProcessHeap(), 0, printer );
1126 /******************************************************************
1127 * get_opened_printer_entry
1128 * Get the first place empty in the opened printer table
1131 * - pDefault is ignored
1133 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1135 UINT_PTR handle = nb_printer_handles, i;
1136 jobqueue_t *queue = NULL;
1137 opened_printer_t *printer = NULL;
1139 LPCWSTR printername;
1141 if ((backend == NULL) && !load_backend()) return NULL;
1143 servername = get_servername_from_name(name);
1145 FIXME("server %s not supported\n", debugstr_w(servername));
1146 HeapFree(GetProcessHeap(), 0, servername);
1147 SetLastError(ERROR_INVALID_PRINTER_NAME);
1151 printername = get_basename_from_name(name);
1152 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1154 /* an empty printername is invalid */
1155 if (printername && (!printername[0])) {
1156 SetLastError(ERROR_INVALID_PARAMETER);
1160 EnterCriticalSection(&printer_handles_cs);
1162 for (i = 0; i < nb_printer_handles; i++)
1164 if (!printer_handles[i])
1166 if(handle == nb_printer_handles)
1171 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1172 queue = printer_handles[i]->queue;
1176 if (handle >= nb_printer_handles)
1178 opened_printer_t **new_array;
1179 if (printer_handles)
1180 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1181 (nb_printer_handles + 16) * sizeof(*new_array) );
1183 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1184 (nb_printer_handles + 16) * sizeof(*new_array) );
1191 printer_handles = new_array;
1192 nb_printer_handles += 16;
1195 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1201 /* get a printer handle from the backend */
1202 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1207 /* clone the base name. This is NULL for the printserver */
1208 printer->printername = strdupW(printername);
1210 /* clone the full name */
1211 printer->name = strdupW(name);
1212 if (name && (!printer->name)) {
1217 if (pDefault && pDefault->pDevMode)
1218 printer->devmode = dup_devmode( pDefault->pDevMode );
1221 printer->queue = queue;
1224 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1225 if (!printer->queue) {
1229 list_init(&printer->queue->jobs);
1230 printer->queue->ref = 0;
1232 InterlockedIncrement(&printer->queue->ref);
1234 printer_handles[handle] = printer;
1237 LeaveCriticalSection(&printer_handles_cs);
1238 if (!handle && printer) {
1239 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1240 free_printer_entry( printer );
1243 return (HANDLE)handle;
1246 /******************************************************************
1247 * get_opened_printer
1248 * Get the pointer to the opened printer referred by the handle
1250 static opened_printer_t *get_opened_printer(HANDLE hprn)
1252 UINT_PTR idx = (UINT_PTR)hprn;
1253 opened_printer_t *ret = NULL;
1255 EnterCriticalSection(&printer_handles_cs);
1257 if ((idx > 0) && (idx <= nb_printer_handles)) {
1258 ret = printer_handles[idx - 1];
1260 LeaveCriticalSection(&printer_handles_cs);
1264 /******************************************************************
1265 * get_opened_printer_name
1266 * Get the pointer to the opened printer name referred by the handle
1268 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1270 opened_printer_t *printer = get_opened_printer(hprn);
1271 if(!printer) return NULL;
1272 return printer->name;
1275 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
1281 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
1282 if (err) return err;
1284 err = RegOpenKeyW( printers, name, key );
1285 if (err) err = ERROR_INVALID_PRINTER_NAME;
1286 RegCloseKey( printers );
1290 /******************************************************************
1291 * WINSPOOL_GetOpenedPrinterRegKey
1294 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1296 LPCWSTR name = get_opened_printer_name(hPrinter);
1298 if(!name) return ERROR_INVALID_HANDLE;
1299 return open_printer_reg_key( name, phkey );
1302 static void old_printer_check( BOOL delete_phase )
1304 PRINTER_INFO_5W* pi;
1305 DWORD needed, type, num, delete, i, size;
1306 const DWORD one = 1;
1310 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1311 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1313 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1314 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1315 for (i = 0; i < num; i++)
1317 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1318 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1321 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1325 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1331 size = sizeof( delete );
1332 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1336 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1337 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1339 DeletePrinter( hprn );
1340 ClosePrinter( hprn );
1342 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1346 HeapFree(GetProcessHeap(), 0, pi);
1349 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1350 'M','U','T','E','X','_','_','\0'};
1352 void WINSPOOL_LoadSystemPrinters(void)
1354 HKEY hkey, hkeyPrinters;
1355 DWORD needed, num, i;
1356 WCHAR PrinterName[256];
1360 /* FIXME: The init code should be moved to spoolsv.exe */
1361 mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1364 ERR( "Failed to create mutex\n" );
1367 if (GetLastError() == ERROR_ALREADY_EXISTS)
1369 WaitForSingleObject( mutex, INFINITE );
1370 ReleaseMutex( mutex );
1371 TRACE( "Init already done\n" );
1375 /* This ensures that all printer entries have a valid Name value. If causes
1376 problems later if they don't. If one is found to be missed we create one
1377 and set it equal to the name of the key */
1378 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1379 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1380 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1381 for(i = 0; i < num; i++) {
1382 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1383 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1384 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1385 set_reg_szW(hkey, NameW, PrinterName);
1392 RegCloseKey(hkeyPrinters);
1395 old_printer_check( FALSE );
1397 #ifdef SONAME_LIBCUPS
1398 done = CUPS_LoadPrinters();
1401 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1402 PRINTCAP_LoadPrinters();
1404 old_printer_check( TRUE );
1406 ReleaseMutex( mutex );
1410 /******************************************************************
1413 * Get the pointer to the specified job.
1414 * Should hold the printer_handles_cs before calling.
1416 static job_t *get_job(HANDLE hprn, DWORD JobId)
1418 opened_printer_t *printer = get_opened_printer(hprn);
1421 if(!printer) return NULL;
1422 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1424 if(job->job_id == JobId)
1430 /***********************************************************
1433 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1436 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1439 Formname = (dmA->dmSize > off_formname);
1440 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1441 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1442 dmW->dmDeviceName, CCHDEVICENAME);
1444 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1445 dmA->dmSize - CCHDEVICENAME);
1447 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1448 off_formname - CCHDEVICENAME);
1449 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1450 dmW->dmFormName, CCHFORMNAME);
1451 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1452 (off_formname + CCHFORMNAME));
1455 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1456 dmA->dmDriverExtra);
1460 /******************************************************************
1461 * convert_printerinfo_W_to_A [internal]
1464 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1465 DWORD level, DWORD outlen, DWORD numentries)
1471 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1473 len = pi_sizeof[level] * numentries;
1474 ptr = (LPSTR) out + len;
1477 /* copy the numbers of all PRINTER_INFO_* first */
1478 memcpy(out, pPrintersW, len);
1480 while (id < numentries) {
1484 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1485 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1487 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1488 if (piW->pDescription) {
1489 piA->pDescription = ptr;
1490 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1491 ptr, outlen, NULL, NULL);
1497 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1498 ptr, outlen, NULL, NULL);
1502 if (piW->pComment) {
1503 piA->pComment = ptr;
1504 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1505 ptr, outlen, NULL, NULL);
1514 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1515 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1518 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1519 if (piW->pServerName) {
1520 piA->pServerName = ptr;
1521 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1522 ptr, outlen, NULL, NULL);
1526 if (piW->pPrinterName) {
1527 piA->pPrinterName = ptr;
1528 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1529 ptr, outlen, NULL, NULL);
1533 if (piW->pShareName) {
1534 piA->pShareName = ptr;
1535 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1536 ptr, outlen, NULL, NULL);
1540 if (piW->pPortName) {
1541 piA->pPortName = ptr;
1542 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1543 ptr, outlen, NULL, NULL);
1547 if (piW->pDriverName) {
1548 piA->pDriverName = ptr;
1549 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1550 ptr, outlen, NULL, NULL);
1554 if (piW->pComment) {
1555 piA->pComment = ptr;
1556 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1557 ptr, outlen, NULL, NULL);
1561 if (piW->pLocation) {
1562 piA->pLocation = ptr;
1563 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1564 ptr, outlen, NULL, NULL);
1569 dmA = DEVMODEdupWtoA(piW->pDevMode);
1571 /* align DEVMODEA to a DWORD boundary */
1572 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1576 piA->pDevMode = (LPDEVMODEA) ptr;
1577 len = dmA->dmSize + dmA->dmDriverExtra;
1578 memcpy(ptr, dmA, len);
1579 HeapFree(GetProcessHeap(), 0, dmA);
1585 if (piW->pSepFile) {
1586 piA->pSepFile = ptr;
1587 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1588 ptr, outlen, NULL, NULL);
1592 if (piW->pPrintProcessor) {
1593 piA->pPrintProcessor = ptr;
1594 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1595 ptr, outlen, NULL, NULL);
1599 if (piW->pDatatype) {
1600 piA->pDatatype = ptr;
1601 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1602 ptr, outlen, NULL, NULL);
1606 if (piW->pParameters) {
1607 piA->pParameters = ptr;
1608 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1609 ptr, outlen, NULL, NULL);
1613 if (piW->pSecurityDescriptor) {
1614 piA->pSecurityDescriptor = NULL;
1615 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1622 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1623 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1625 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1627 if (piW->pPrinterName) {
1628 piA->pPrinterName = ptr;
1629 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1630 ptr, outlen, NULL, NULL);
1634 if (piW->pServerName) {
1635 piA->pServerName = ptr;
1636 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1637 ptr, outlen, NULL, NULL);
1646 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1647 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1649 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1651 if (piW->pPrinterName) {
1652 piA->pPrinterName = ptr;
1653 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1654 ptr, outlen, NULL, NULL);
1658 if (piW->pPortName) {
1659 piA->pPortName = ptr;
1660 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1661 ptr, outlen, NULL, NULL);
1668 case 6: /* 6A and 6W are the same structure */
1673 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1674 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1676 TRACE("(%u) #%u\n", level, id);
1677 if (piW->pszObjectGUID) {
1678 piA->pszObjectGUID = ptr;
1679 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1680 ptr, outlen, NULL, NULL);
1690 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1691 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1694 TRACE("(%u) #%u\n", level, id);
1695 dmA = DEVMODEdupWtoA(piW->pDevMode);
1697 /* align DEVMODEA to a DWORD boundary */
1698 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1702 piA->pDevMode = (LPDEVMODEA) ptr;
1703 len = dmA->dmSize + dmA->dmDriverExtra;
1704 memcpy(ptr, dmA, len);
1705 HeapFree(GetProcessHeap(), 0, dmA);
1715 FIXME("for level %u\n", level);
1717 pPrintersW += pi_sizeof[level];
1718 out += pi_sizeof[level];
1723 /******************************************************************
1724 * convert_driverinfo_W_to_A [internal]
1727 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1728 DWORD level, DWORD outlen, DWORD numentries)
1734 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1736 len = di_sizeof[level] * numentries;
1737 ptr = (LPSTR) out + len;
1740 /* copy the numbers of all PRINTER_INFO_* first */
1741 memcpy(out, pDriversW, len);
1743 #define COPY_STRING(fld) \
1746 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1747 ptr += len; outlen -= len;\
1749 #define COPY_MULTIZ_STRING(fld) \
1750 { LPWSTR p = diW->fld; if (p){ \
1753 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1754 ptr += len; outlen -= len; p += len;\
1756 while(len > 1 && outlen > 0); \
1759 while (id < numentries)
1765 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1766 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1768 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1775 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1776 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1778 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1781 COPY_STRING(pEnvironment);
1782 COPY_STRING(pDriverPath);
1783 COPY_STRING(pDataFile);
1784 COPY_STRING(pConfigFile);
1789 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1790 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1792 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1795 COPY_STRING(pEnvironment);
1796 COPY_STRING(pDriverPath);
1797 COPY_STRING(pDataFile);
1798 COPY_STRING(pConfigFile);
1799 COPY_STRING(pHelpFile);
1800 COPY_MULTIZ_STRING(pDependentFiles);
1801 COPY_STRING(pMonitorName);
1802 COPY_STRING(pDefaultDataType);
1807 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1808 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1810 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1813 COPY_STRING(pEnvironment);
1814 COPY_STRING(pDriverPath);
1815 COPY_STRING(pDataFile);
1816 COPY_STRING(pConfigFile);
1817 COPY_STRING(pHelpFile);
1818 COPY_MULTIZ_STRING(pDependentFiles);
1819 COPY_STRING(pMonitorName);
1820 COPY_STRING(pDefaultDataType);
1821 COPY_MULTIZ_STRING(pszzPreviousNames);
1826 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1827 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1829 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1832 COPY_STRING(pEnvironment);
1833 COPY_STRING(pDriverPath);
1834 COPY_STRING(pDataFile);
1835 COPY_STRING(pConfigFile);
1840 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1841 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1843 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1846 COPY_STRING(pEnvironment);
1847 COPY_STRING(pDriverPath);
1848 COPY_STRING(pDataFile);
1849 COPY_STRING(pConfigFile);
1850 COPY_STRING(pHelpFile);
1851 COPY_MULTIZ_STRING(pDependentFiles);
1852 COPY_STRING(pMonitorName);
1853 COPY_STRING(pDefaultDataType);
1854 COPY_MULTIZ_STRING(pszzPreviousNames);
1855 COPY_STRING(pszMfgName);
1856 COPY_STRING(pszOEMUrl);
1857 COPY_STRING(pszHardwareID);
1858 COPY_STRING(pszProvider);
1863 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1864 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1866 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1869 COPY_STRING(pEnvironment);
1870 COPY_STRING(pDriverPath);
1871 COPY_STRING(pDataFile);
1872 COPY_STRING(pConfigFile);
1873 COPY_STRING(pHelpFile);
1874 COPY_MULTIZ_STRING(pDependentFiles);
1875 COPY_STRING(pMonitorName);
1876 COPY_STRING(pDefaultDataType);
1877 COPY_MULTIZ_STRING(pszzPreviousNames);
1878 COPY_STRING(pszMfgName);
1879 COPY_STRING(pszOEMUrl);
1880 COPY_STRING(pszHardwareID);
1881 COPY_STRING(pszProvider);
1882 COPY_STRING(pszPrintProcessor);
1883 COPY_STRING(pszVendorSetup);
1884 COPY_MULTIZ_STRING(pszzColorProfiles);
1885 COPY_STRING(pszInfPath);
1886 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1892 FIXME("for level %u\n", level);
1895 pDriversW += di_sizeof[level];
1896 out += di_sizeof[level];
1901 #undef COPY_MULTIZ_STRING
1905 /***********************************************************
1908 static void *printer_info_AtoW( const void *data, DWORD level )
1911 UNICODE_STRING usBuffer;
1913 if (!data) return NULL;
1915 if (level < 1 || level > 9) return NULL;
1917 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
1918 if (!ret) return NULL;
1920 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
1926 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
1927 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
1929 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
1930 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
1931 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
1932 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
1933 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
1934 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
1935 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
1936 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1937 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
1938 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
1939 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
1940 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
1947 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
1948 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
1950 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1955 FIXME( "Unhandled level %d\n", level );
1956 HeapFree( GetProcessHeap(), 0, ret );
1963 /***********************************************************
1966 static void free_printer_info( void *data, DWORD level )
1974 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
1976 HeapFree( GetProcessHeap(), 0, piW->pServerName );
1977 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
1978 HeapFree( GetProcessHeap(), 0, piW->pShareName );
1979 HeapFree( GetProcessHeap(), 0, piW->pPortName );
1980 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
1981 HeapFree( GetProcessHeap(), 0, piW->pComment );
1982 HeapFree( GetProcessHeap(), 0, piW->pLocation );
1983 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1984 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
1985 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
1986 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
1987 HeapFree( GetProcessHeap(), 0, piW->pParameters );
1994 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
1996 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2001 FIXME( "Unhandled level %d\n", level );
2004 HeapFree( GetProcessHeap(), 0, data );
2008 /******************************************************************
2009 * DeviceCapabilities [WINSPOOL.@]
2010 * DeviceCapabilitiesA [WINSPOOL.@]
2013 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2014 LPSTR pOutput, LPDEVMODEA lpdm)
2018 if (!GDI_CallDeviceCapabilities16)
2020 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2022 if (!GDI_CallDeviceCapabilities16) return -1;
2024 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2026 /* If DC_PAPERSIZE map POINT16s to POINTs */
2027 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2028 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2029 POINT *pt = (POINT *)pOutput;
2031 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2032 for(i = 0; i < ret; i++, pt++)
2037 HeapFree( GetProcessHeap(), 0, tmp );
2043 /*****************************************************************************
2044 * DeviceCapabilitiesW [WINSPOOL.@]
2046 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2049 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2050 WORD fwCapability, LPWSTR pOutput,
2051 const DEVMODEW *pDevMode)
2053 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2054 LPSTR pDeviceA = strdupWtoA(pDevice);
2055 LPSTR pPortA = strdupWtoA(pPort);
2058 if(pOutput && (fwCapability == DC_BINNAMES ||
2059 fwCapability == DC_FILEDEPENDENCIES ||
2060 fwCapability == DC_PAPERNAMES)) {
2061 /* These need A -> W translation */
2064 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2068 switch(fwCapability) {
2073 case DC_FILEDEPENDENCIES:
2077 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2078 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2080 for(i = 0; i < ret; i++)
2081 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2082 pOutput + (i * size), size);
2083 HeapFree(GetProcessHeap(), 0, pOutputA);
2085 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2086 (LPSTR)pOutput, dmA);
2088 HeapFree(GetProcessHeap(),0,pPortA);
2089 HeapFree(GetProcessHeap(),0,pDeviceA);
2090 HeapFree(GetProcessHeap(),0,dmA);
2094 /******************************************************************
2095 * DocumentPropertiesA [WINSPOOL.@]
2097 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2099 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2100 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2101 LPDEVMODEA pDevModeInput,DWORD fMode )
2103 LPSTR lpName = pDeviceName;
2104 static CHAR port[] = "LPT1:";
2107 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2108 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2112 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2114 ERR("no name from hPrinter?\n");
2115 SetLastError(ERROR_INVALID_HANDLE);
2118 lpName = strdupWtoA(lpNameW);
2121 if (!GDI_CallExtDeviceMode16)
2123 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2125 if (!GDI_CallExtDeviceMode16) {
2126 ERR("No CallExtDeviceMode16?\n");
2130 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2131 pDevModeInput, NULL, fMode);
2134 HeapFree(GetProcessHeap(),0,lpName);
2139 /*****************************************************************************
2140 * DocumentPropertiesW (WINSPOOL.@)
2142 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2144 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2146 LPDEVMODEW pDevModeOutput,
2147 LPDEVMODEW pDevModeInput, DWORD fMode)
2150 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2151 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2152 LPDEVMODEA pDevModeOutputA = NULL;
2155 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2156 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2158 if(pDevModeOutput) {
2159 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2160 if(ret < 0) return ret;
2161 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2163 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2164 pDevModeInputA, fMode);
2165 if(pDevModeOutput) {
2166 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2167 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2169 if(fMode == 0 && ret > 0)
2170 ret += (CCHDEVICENAME + CCHFORMNAME);
2171 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2172 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2176 /*****************************************************************************
2177 * IsValidDevmodeA [WINSPOOL.@]
2179 * Validate a DEVMODE structure and fix errors if possible.
2182 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2184 FIXME("(%p,%ld): stub\n", pDevMode, size);
2192 /*****************************************************************************
2193 * IsValidDevmodeW [WINSPOOL.@]
2195 * Validate a DEVMODE structure and fix errors if possible.
2198 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2200 FIXME("(%p,%ld): stub\n", pDevMode, size);
2208 /******************************************************************
2209 * OpenPrinterA [WINSPOOL.@]
2214 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2215 LPPRINTER_DEFAULTSA pDefault)
2217 UNICODE_STRING lpPrinterNameW;
2218 UNICODE_STRING usBuffer;
2219 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2220 PWSTR pwstrPrinterNameW;
2223 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2226 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2227 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2228 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2229 pDefaultW = &DefaultW;
2231 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2233 RtlFreeUnicodeString(&usBuffer);
2234 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2236 RtlFreeUnicodeString(&lpPrinterNameW);
2240 /******************************************************************
2241 * OpenPrinterW [WINSPOOL.@]
2243 * Open a Printer / Printserver or a Printer-Object
2246 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2247 * phPrinter [O] The resulting Handle is stored here
2248 * pDefault [I] PTR to Default Printer Settings or NULL
2255 * lpPrinterName is one of:
2256 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2257 *| Printer: "PrinterName"
2258 *| Printer-Object: "PrinterName,Job xxx"
2259 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2260 *| XcvPort: "Servername,XcvPort PortName"
2263 *| Printer-Object not supported
2264 *| pDefaults is ignored
2267 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2270 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2273 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2274 SetLastError(ERROR_INVALID_PARAMETER);
2278 /* Get the unique handle of the printer or Printserver */
2279 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2280 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2281 return (*phPrinter != 0);
2284 /******************************************************************
2285 * AddMonitorA [WINSPOOL.@]
2290 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2292 LPWSTR nameW = NULL;
2295 LPMONITOR_INFO_2A mi2a;
2296 MONITOR_INFO_2W mi2w;
2298 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2299 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2300 debugstr_a(mi2a ? mi2a->pName : NULL),
2301 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2302 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2305 SetLastError(ERROR_INVALID_LEVEL);
2309 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2315 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2316 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2317 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2320 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2322 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2323 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2324 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2326 if (mi2a->pEnvironment) {
2327 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2328 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2329 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2331 if (mi2a->pDLLName) {
2332 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2333 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2334 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2337 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2339 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2340 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2341 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2343 HeapFree(GetProcessHeap(), 0, nameW);
2347 /******************************************************************************
2348 * AddMonitorW [WINSPOOL.@]
2350 * Install a Printmonitor
2353 * pName [I] Servername or NULL (local Computer)
2354 * Level [I] Structure-Level (Must be 2)
2355 * pMonitors [I] PTR to MONITOR_INFO_2
2362 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2365 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2367 LPMONITOR_INFO_2W mi2w;
2369 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2370 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2371 debugstr_w(mi2w ? mi2w->pName : NULL),
2372 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2373 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2375 if ((backend == NULL) && !load_backend()) return FALSE;
2378 SetLastError(ERROR_INVALID_LEVEL);
2382 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2387 return backend->fpAddMonitor(pName, Level, pMonitors);
2390 /******************************************************************
2391 * DeletePrinterDriverA [WINSPOOL.@]
2394 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2396 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2399 /******************************************************************
2400 * DeletePrinterDriverW [WINSPOOL.@]
2403 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2405 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2408 /******************************************************************
2409 * DeleteMonitorA [WINSPOOL.@]
2411 * See DeleteMonitorW.
2414 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2416 LPWSTR nameW = NULL;
2417 LPWSTR EnvironmentW = NULL;
2418 LPWSTR MonitorNameW = NULL;
2423 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2424 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2425 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2429 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2430 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2431 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2434 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2435 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2436 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2439 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2441 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2442 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2443 HeapFree(GetProcessHeap(), 0, nameW);
2447 /******************************************************************
2448 * DeleteMonitorW [WINSPOOL.@]
2450 * Delete a specific Printmonitor from a Printing-Environment
2453 * pName [I] Servername or NULL (local Computer)
2454 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2455 * pMonitorName [I] Name of the Monitor, that should be deleted
2462 * pEnvironment is ignored in Windows for the local Computer.
2465 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2468 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2469 debugstr_w(pMonitorName));
2471 if ((backend == NULL) && !load_backend()) return FALSE;
2473 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2477 /******************************************************************
2478 * DeletePortA [WINSPOOL.@]
2483 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2485 LPWSTR nameW = NULL;
2486 LPWSTR portW = NULL;
2490 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2492 /* convert servername to unicode */
2494 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2495 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2496 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2499 /* convert portname to unicode */
2501 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2502 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2503 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2506 res = DeletePortW(nameW, hWnd, portW);
2507 HeapFree(GetProcessHeap(), 0, nameW);
2508 HeapFree(GetProcessHeap(), 0, portW);
2512 /******************************************************************
2513 * DeletePortW [WINSPOOL.@]
2515 * Delete a specific Port
2518 * pName [I] Servername or NULL (local Computer)
2519 * hWnd [I] Handle to parent Window for the Dialog-Box
2520 * pPortName [I] Name of the Port, that should be deleted
2527 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2529 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2531 if ((backend == NULL) && !load_backend()) return FALSE;
2534 SetLastError(RPC_X_NULL_REF_POINTER);
2538 return backend->fpDeletePort(pName, hWnd, pPortName);
2541 /******************************************************************************
2542 * WritePrinter [WINSPOOL.@]
2544 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2546 opened_printer_t *printer;
2549 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2551 EnterCriticalSection(&printer_handles_cs);
2552 printer = get_opened_printer(hPrinter);
2555 SetLastError(ERROR_INVALID_HANDLE);
2561 SetLastError(ERROR_SPL_NO_STARTDOC);
2565 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2567 LeaveCriticalSection(&printer_handles_cs);
2571 /*****************************************************************************
2572 * AddFormA [WINSPOOL.@]
2574 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2576 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2580 /*****************************************************************************
2581 * AddFormW [WINSPOOL.@]
2583 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2585 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2589 /*****************************************************************************
2590 * AddJobA [WINSPOOL.@]
2592 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2595 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2599 SetLastError(ERROR_INVALID_LEVEL);
2603 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2606 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2607 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2608 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2609 if(*pcbNeeded > cbBuf) {
2610 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2613 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2614 addjobA->JobId = addjobW->JobId;
2615 addjobA->Path = (char *)(addjobA + 1);
2616 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2622 /*****************************************************************************
2623 * AddJobW [WINSPOOL.@]
2625 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2627 opened_printer_t *printer;
2630 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2631 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2632 WCHAR path[MAX_PATH], filename[MAX_PATH];
2634 ADDJOB_INFO_1W *addjob;
2636 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2638 EnterCriticalSection(&printer_handles_cs);
2640 printer = get_opened_printer(hPrinter);
2643 SetLastError(ERROR_INVALID_HANDLE);
2648 SetLastError(ERROR_INVALID_LEVEL);
2652 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2656 job->job_id = InterlockedIncrement(&next_job_id);
2658 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2659 if(path[len - 1] != '\\')
2661 memcpy(path + len, spool_path, sizeof(spool_path));
2662 sprintfW(filename, fmtW, path, job->job_id);
2664 len = strlenW(filename);
2665 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2666 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2667 job->portname = NULL;
2668 job->document_title = strdupW(default_doc_title);
2669 job->printer_name = strdupW(printer->name);
2670 job->devmode = dup_devmode( printer->devmode );
2671 list_add_tail(&printer->queue->jobs, &job->entry);
2673 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2674 if(*pcbNeeded <= cbBuf) {
2675 addjob = (ADDJOB_INFO_1W*)pData;
2676 addjob->JobId = job->job_id;
2677 addjob->Path = (WCHAR *)(addjob + 1);
2678 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2681 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2684 LeaveCriticalSection(&printer_handles_cs);
2688 /*****************************************************************************
2689 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2691 * Return the PATH for the Print-Processors
2693 * See GetPrintProcessorDirectoryW.
2697 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2698 DWORD level, LPBYTE Info,
2699 DWORD cbBuf, LPDWORD pcbNeeded)
2701 LPWSTR serverW = NULL;
2706 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2707 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2711 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2712 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2713 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2717 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2718 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2719 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2722 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2723 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2725 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2728 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2729 cbBuf, NULL, NULL) > 0;
2732 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2733 HeapFree(GetProcessHeap(), 0, envW);
2734 HeapFree(GetProcessHeap(), 0, serverW);
2738 /*****************************************************************************
2739 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2741 * Return the PATH for the Print-Processors
2744 * server [I] Servername (NT only) or NULL (local Computer)
2745 * env [I] Printing-Environment (see below) or NULL (Default)
2746 * level [I] Structure-Level (must be 1)
2747 * Info [O] PTR to Buffer that receives the Result
2748 * cbBuf [I] Size of Buffer at "Info"
2749 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2750 * required for the Buffer at "Info"
2753 * Success: TRUE and in pcbNeeded the Bytes used in Info
2754 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2755 * if cbBuf is too small
2757 * Native Values returned in Info on Success:
2758 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2759 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2760 *| win9x(Windows 4.0): "%winsysdir%"
2762 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2765 * Only NULL or "" is supported for server
2768 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2769 DWORD level, LPBYTE Info,
2770 DWORD cbBuf, LPDWORD pcbNeeded)
2773 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2774 Info, cbBuf, pcbNeeded);
2776 if ((backend == NULL) && !load_backend()) return FALSE;
2779 /* (Level != 1) is ignored in win9x */
2780 SetLastError(ERROR_INVALID_LEVEL);
2784 if (pcbNeeded == NULL) {
2785 /* (pcbNeeded == NULL) is ignored in win9x */
2786 SetLastError(RPC_X_NULL_REF_POINTER);
2790 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2793 /*****************************************************************************
2794 * WINSPOOL_OpenDriverReg [internal]
2796 * opens the registry for the printer drivers depending on the given input
2797 * variable pEnvironment
2800 * the opened hkey on success
2803 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2807 const printenv_t * env;
2809 TRACE("(%s)\n", debugstr_w(pEnvironment));
2811 env = validate_envW(pEnvironment);
2812 if (!env) return NULL;
2814 buffer = HeapAlloc( GetProcessHeap(), 0,
2815 (strlenW(DriversW) + strlenW(env->envname) +
2816 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2818 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2819 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2820 HeapFree(GetProcessHeap(), 0, buffer);
2825 /*****************************************************************************
2826 * set_devices_and_printerports [internal]
2828 * set the [Devices] and [PrinterPorts] entries for a printer.
2831 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2833 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2837 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2839 /* FIXME: the driver must change to "winspool" */
2840 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2842 lstrcpyW(devline, driver_nt);
2843 lstrcatW(devline, commaW);
2844 lstrcatW(devline, pi->pPortName);
2846 TRACE("using %s\n", debugstr_w(devline));
2847 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2848 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2849 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2850 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2854 lstrcatW(devline, timeout_15_45);
2855 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2856 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2857 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2858 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2861 HeapFree(GetProcessHeap(), 0, devline);
2865 /*****************************************************************************
2866 * AddPrinterW [WINSPOOL.@]
2868 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2870 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2873 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2876 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2879 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2880 SetLastError(ERROR_INVALID_PARAMETER);
2884 ERR("Level = %d, unsupported!\n", Level);
2885 SetLastError(ERROR_INVALID_LEVEL);
2889 SetLastError(ERROR_INVALID_PARAMETER);
2892 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2894 ERR("Can't create Printers key\n");
2897 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2898 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
2899 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2900 RegCloseKey(hkeyPrinter);
2901 RegCloseKey(hkeyPrinters);
2904 RegCloseKey(hkeyPrinter);
2906 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2908 ERR("Can't create Drivers key\n");
2909 RegCloseKey(hkeyPrinters);
2912 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2914 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2915 RegCloseKey(hkeyPrinters);
2916 RegCloseKey(hkeyDrivers);
2917 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2920 RegCloseKey(hkeyDriver);
2921 RegCloseKey(hkeyDrivers);
2923 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2924 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2925 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2926 RegCloseKey(hkeyPrinters);
2930 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2932 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2933 SetLastError(ERROR_INVALID_PRINTER_NAME);
2934 RegCloseKey(hkeyPrinters);
2938 set_devices_and_printerports(pi);
2939 RegSetValueExW(hkeyPrinter, AttributesW, 0, REG_DWORD,
2940 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2941 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2943 /* See if we can load the driver. We may need the devmode structure anyway
2946 * Note that DocumentPropertiesW will briefly try to open the printer we
2947 * just create to find a DEVMODE struct (it will use the WINEPS default
2948 * one in case it is not there, so we are ok).
2950 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2953 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2954 size = sizeof(DEVMODEW);
2960 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
2962 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
2964 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2965 HeapFree( GetProcessHeap(), 0, dm );
2970 /* set devmode to printer name */
2971 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
2975 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
2976 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
2978 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2979 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2980 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2981 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2983 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2984 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2985 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2986 RegSetValueExW(hkeyPrinter, PriorityW, 0, REG_DWORD,
2987 (LPBYTE)&pi->Priority, sizeof(DWORD));
2988 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2989 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2990 RegSetValueExW(hkeyPrinter, StartTimeW, 0, REG_DWORD,
2991 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2992 RegSetValueExW(hkeyPrinter, StatusW, 0, REG_DWORD,
2993 (LPBYTE)&pi->Status, sizeof(DWORD));
2994 RegSetValueExW(hkeyPrinter, UntilTimeW, 0, REG_DWORD,
2995 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2997 RegCloseKey(hkeyPrinter);
2998 RegCloseKey(hkeyPrinters);
2999 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3000 ERR("OpenPrinter failing\n");
3006 /*****************************************************************************
3007 * AddPrinterA [WINSPOOL.@]
3009 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3011 UNICODE_STRING pNameW;
3013 PRINTER_INFO_2W *piW;
3014 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3017 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3019 ERR("Level = %d, unsupported!\n", Level);
3020 SetLastError(ERROR_INVALID_LEVEL);
3023 pwstrNameW = asciitounicode(&pNameW,pName);
3024 piW = printer_info_AtoW( piA, Level );
3026 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3028 free_printer_info( piW, Level );
3029 RtlFreeUnicodeString(&pNameW);
3034 /*****************************************************************************
3035 * ClosePrinter [WINSPOOL.@]
3037 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3039 UINT_PTR i = (UINT_PTR)hPrinter;
3040 opened_printer_t *printer = NULL;
3043 TRACE("(%p)\n", hPrinter);
3045 EnterCriticalSection(&printer_handles_cs);
3047 if ((i > 0) && (i <= nb_printer_handles))
3048 printer = printer_handles[i - 1];
3053 struct list *cursor, *cursor2;
3055 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3057 if (printer->backend_printer) {
3058 backend->fpClosePrinter(printer->backend_printer);
3062 EndDocPrinter(hPrinter);
3064 if(InterlockedDecrement(&printer->queue->ref) == 0)
3066 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3068 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3069 ScheduleJob(hPrinter, job->job_id);
3071 HeapFree(GetProcessHeap(), 0, printer->queue);
3074 free_printer_entry( printer );
3075 printer_handles[i - 1] = NULL;
3078 LeaveCriticalSection(&printer_handles_cs);
3082 /*****************************************************************************
3083 * DeleteFormA [WINSPOOL.@]
3085 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3087 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3091 /*****************************************************************************
3092 * DeleteFormW [WINSPOOL.@]
3094 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3096 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3100 /*****************************************************************************
3101 * DeletePrinter [WINSPOOL.@]
3103 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3105 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3106 HKEY hkeyPrinters, hkey;
3107 WCHAR def[MAX_PATH];
3108 DWORD size = sizeof( def ) / sizeof( def[0] );
3111 SetLastError(ERROR_INVALID_HANDLE);
3114 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3115 RegDeleteTreeW(hkeyPrinters, lpNameW);
3116 RegCloseKey(hkeyPrinters);
3118 WriteProfileStringW(devicesW, lpNameW, NULL);
3119 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3121 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3122 RegDeleteValueW(hkey, lpNameW);
3126 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3127 RegDeleteValueW(hkey, lpNameW);
3131 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3133 WriteProfileStringW( windowsW, deviceW, NULL );
3134 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3136 RegDeleteValueW( hkey, deviceW );
3137 RegCloseKey( hkey );
3139 SetDefaultPrinterW( NULL );
3145 /*****************************************************************************
3146 * SetPrinterA [WINSPOOL.@]
3148 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3155 dataW = printer_info_AtoW( data, level );
3156 if (!dataW) return FALSE;
3159 ret = SetPrinterW( printer, level, dataW, command );
3161 if (dataW != data) free_printer_info( dataW, level );
3166 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3168 set_reg_szW( key, NameW, pi->pPrinterName );
3169 set_reg_szW( key, Share_NameW, pi->pShareName );
3170 set_reg_szW( key, PortW, pi->pPortName );
3171 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3172 set_reg_szW( key, DescriptionW, pi->pComment );
3173 set_reg_szW( key, LocationW, pi->pLocation );
3176 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3178 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3179 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3180 set_reg_szW( key, DatatypeW, pi->pDatatype );
3181 set_reg_szW( key, ParametersW, pi->pParameters );
3183 set_reg_DWORD( key, AttributesW, pi->Attributes );
3184 set_reg_DWORD( key, PriorityW, pi->Priority );
3185 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3186 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3187 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3190 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3192 if (!pi->pDevMode) return FALSE;
3194 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3198 /******************************************************************************
3199 * SetPrinterW [WINSPOOL.@]
3201 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3206 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3208 if (command != 0) FIXME( "Ignoring command %d\n", command );
3210 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3217 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3218 set_printer_2( key, pi2 );
3225 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3226 ret = set_printer_9( key, pi );
3231 FIXME( "Unimplemented level %d\n", level );
3232 SetLastError( ERROR_INVALID_LEVEL );
3239 /*****************************************************************************
3240 * SetJobA [WINSPOOL.@]
3242 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3243 LPBYTE pJob, DWORD Command)
3247 UNICODE_STRING usBuffer;
3249 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3251 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3252 are all ignored by SetJob, so we don't bother copying them */
3260 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3261 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3263 JobW = (LPBYTE)info1W;
3264 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3265 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3266 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3267 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3268 info1W->Status = info1A->Status;
3269 info1W->Priority = info1A->Priority;
3270 info1W->Position = info1A->Position;
3271 info1W->PagesPrinted = info1A->PagesPrinted;
3276 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3277 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3279 JobW = (LPBYTE)info2W;
3280 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3281 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3282 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3283 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3284 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3285 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3286 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3287 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3288 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3289 info2W->Status = info2A->Status;
3290 info2W->Priority = info2A->Priority;
3291 info2W->Position = info2A->Position;
3292 info2W->StartTime = info2A->StartTime;
3293 info2W->UntilTime = info2A->UntilTime;
3294 info2W->PagesPrinted = info2A->PagesPrinted;
3298 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3299 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3302 SetLastError(ERROR_INVALID_LEVEL);
3306 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3312 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3313 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3314 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3315 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3316 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3321 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3322 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3323 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3324 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3325 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3326 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3327 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3328 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3329 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3333 HeapFree(GetProcessHeap(), 0, JobW);
3338 /*****************************************************************************
3339 * SetJobW [WINSPOOL.@]
3341 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3342 LPBYTE pJob, DWORD Command)
3347 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3348 FIXME("Ignoring everything other than document title\n");
3350 EnterCriticalSection(&printer_handles_cs);
3351 job = get_job(hPrinter, JobId);
3361 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3362 HeapFree(GetProcessHeap(), 0, job->document_title);
3363 job->document_title = strdupW(info1->pDocument);
3368 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3369 HeapFree(GetProcessHeap(), 0, job->document_title);
3370 job->document_title = strdupW(info2->pDocument);
3371 HeapFree(GetProcessHeap(), 0, job->devmode);
3372 job->devmode = dup_devmode( info2->pDevMode );
3378 SetLastError(ERROR_INVALID_LEVEL);
3383 LeaveCriticalSection(&printer_handles_cs);
3387 /*****************************************************************************
3388 * EndDocPrinter [WINSPOOL.@]
3390 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3392 opened_printer_t *printer;
3394 TRACE("(%p)\n", hPrinter);
3396 EnterCriticalSection(&printer_handles_cs);
3398 printer = get_opened_printer(hPrinter);
3401 SetLastError(ERROR_INVALID_HANDLE);
3407 SetLastError(ERROR_SPL_NO_STARTDOC);
3411 CloseHandle(printer->doc->hf);
3412 ScheduleJob(hPrinter, printer->doc->job_id);
3413 HeapFree(GetProcessHeap(), 0, printer->doc);
3414 printer->doc = NULL;
3417 LeaveCriticalSection(&printer_handles_cs);
3421 /*****************************************************************************
3422 * EndPagePrinter [WINSPOOL.@]
3424 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3426 FIXME("(%p): stub\n", hPrinter);
3430 /*****************************************************************************
3431 * StartDocPrinterA [WINSPOOL.@]
3433 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3435 UNICODE_STRING usBuffer;
3437 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3440 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3441 or one (DOC_INFO_3) extra DWORDs */
3445 doc2W.JobId = doc2->JobId;
3448 doc2W.dwMode = doc2->dwMode;
3451 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3452 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3453 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3457 SetLastError(ERROR_INVALID_LEVEL);
3461 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3463 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3464 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3465 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3470 /*****************************************************************************
3471 * StartDocPrinterW [WINSPOOL.@]
3473 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3475 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3476 opened_printer_t *printer;
3477 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3478 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3479 JOB_INFO_1W job_info;
3480 DWORD needed, ret = 0;
3485 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3486 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3487 debugstr_w(doc->pDatatype));
3489 if(Level < 1 || Level > 3)
3491 SetLastError(ERROR_INVALID_LEVEL);
3495 EnterCriticalSection(&printer_handles_cs);
3496 printer = get_opened_printer(hPrinter);
3499 SetLastError(ERROR_INVALID_HANDLE);
3505 SetLastError(ERROR_INVALID_PRINTER_STATE);
3509 /* Even if we're printing to a file we still add a print job, we'll
3510 just ignore the spool file name */
3512 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3514 ERR("AddJob failed gle %u\n", GetLastError());
3518 /* use pOutputFile only, when it is a real filename */
3519 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3520 filename = doc->pOutputFile;
3522 filename = addjob->Path;
3524 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3525 if(hf == INVALID_HANDLE_VALUE)
3528 memset(&job_info, 0, sizeof(job_info));
3529 job_info.pDocument = doc->pDocName;
3530 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3532 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3533 printer->doc->hf = hf;
3534 ret = printer->doc->job_id = addjob->JobId;
3535 job = get_job(hPrinter, ret);
3536 job->portname = strdupW(doc->pOutputFile);
3539 LeaveCriticalSection(&printer_handles_cs);
3544 /*****************************************************************************
3545 * StartPagePrinter [WINSPOOL.@]
3547 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3549 FIXME("(%p): stub\n", hPrinter);
3553 /*****************************************************************************
3554 * GetFormA [WINSPOOL.@]
3556 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3557 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3559 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3560 Level,pForm,cbBuf,pcbNeeded);
3564 /*****************************************************************************
3565 * GetFormW [WINSPOOL.@]
3567 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3568 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3570 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3571 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3575 /*****************************************************************************
3576 * SetFormA [WINSPOOL.@]
3578 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3581 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3585 /*****************************************************************************
3586 * SetFormW [WINSPOOL.@]
3588 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3591 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3595 /*****************************************************************************
3596 * ReadPrinter [WINSPOOL.@]
3598 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3599 LPDWORD pNoBytesRead)
3601 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3605 /*****************************************************************************
3606 * ResetPrinterA [WINSPOOL.@]
3608 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3610 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3614 /*****************************************************************************
3615 * ResetPrinterW [WINSPOOL.@]
3617 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3619 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3623 /*****************************************************************************
3624 * get_filename_from_reg [internal]
3626 * Get ValueName from hkey storing result in out
3627 * when the Value in the registry has only a filename, use driverdir as prefix
3628 * outlen is space left in out
3629 * String is stored either as unicode or ascii
3633 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3634 LPBYTE out, DWORD outlen, LPDWORD needed)
3636 WCHAR filename[MAX_PATH];
3640 LPWSTR buffer = filename;
3644 size = sizeof(filename);
3646 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3647 if (ret == ERROR_MORE_DATA) {
3648 TRACE("need dynamic buffer: %u\n", size);
3649 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3651 /* No Memory is bad */
3655 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3658 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3659 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3665 /* do we have a full path ? */
3666 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3667 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3670 /* we must build the full Path */
3672 if ((out) && (outlen > dirlen)) {
3673 lstrcpyW((LPWSTR)out, driverdir);
3681 /* write the filename */
3682 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3683 if ((out) && (outlen >= size)) {
3684 lstrcpyW((LPWSTR)out, ptr);
3691 ptr += lstrlenW(ptr)+1;
3692 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3695 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3697 /* write the multisz-termination */
3698 if (type == REG_MULTI_SZ) {
3699 size = sizeof(WCHAR);
3702 if (out && (outlen >= size)) {
3703 memset (out, 0, size);
3709 /*****************************************************************************
3710 * WINSPOOL_GetStringFromReg
3712 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3713 * String is stored as unicode.
3715 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3716 DWORD buflen, DWORD *needed)
3718 DWORD sz = buflen, type;
3721 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3722 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3723 WARN("Got ret = %d\n", ret);
3727 /* add space for terminating '\0' */
3728 sz += sizeof(WCHAR);
3732 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3737 /*****************************************************************************
3738 * WINSPOOL_GetDefaultDevMode
3740 * Get a default DevMode values for wineps.
3744 static void WINSPOOL_GetDefaultDevMode(
3746 DWORD buflen, DWORD *needed)
3749 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3751 /* fill default DEVMODE - should be read from ppd... */
3752 ZeroMemory( &dm, sizeof(dm) );
3753 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3754 dm.dmSpecVersion = DM_SPECVERSION;
3755 dm.dmDriverVersion = 1;
3756 dm.dmSize = sizeof(DEVMODEW);
3757 dm.dmDriverExtra = 0;
3759 DM_ORIENTATION | DM_PAPERSIZE |
3760 DM_PAPERLENGTH | DM_PAPERWIDTH |
3763 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3764 DM_YRESOLUTION | DM_TTOPTION;
3766 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3767 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3768 dm.u1.s1.dmPaperLength = 2970;
3769 dm.u1.s1.dmPaperWidth = 2100;
3771 dm.u1.s1.dmScale = 100;
3772 dm.u1.s1.dmCopies = 1;
3773 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3774 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3777 dm.dmYResolution = 300; /* 300dpi */
3778 dm.dmTTOption = DMTT_BITMAP;
3781 /* dm.dmLogPixels */
3782 /* dm.dmBitsPerPel */
3783 /* dm.dmPelsWidth */
3784 /* dm.dmPelsHeight */
3785 /* dm.u2.dmDisplayFlags */
3786 /* dm.dmDisplayFrequency */
3787 /* dm.dmICMMethod */
3788 /* dm.dmICMIntent */
3789 /* dm.dmMediaType */
3790 /* dm.dmDitherType */
3791 /* dm.dmReserved1 */
3792 /* dm.dmReserved2 */
3793 /* dm.dmPanningWidth */
3794 /* dm.dmPanningHeight */
3796 if(buflen >= sizeof(DEVMODEW))
3797 memcpy(ptr, &dm, sizeof(DEVMODEW));
3798 *needed = sizeof(DEVMODEW);
3801 /*****************************************************************************
3802 * WINSPOOL_GetDevModeFromReg
3804 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3805 * DevMode is stored either as unicode or ascii.
3807 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3809 DWORD buflen, DWORD *needed)
3811 DWORD sz = buflen, type;
3814 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3815 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3816 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3817 if (sz < sizeof(DEVMODEA))
3819 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3822 /* ensures that dmSize is not erratically bogus if registry is invalid */
3823 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3824 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3825 sz += (CCHDEVICENAME + CCHFORMNAME);
3826 if (ptr && (buflen >= sz)) {
3827 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3828 memcpy(ptr, dmW, sz);
3829 HeapFree(GetProcessHeap(),0,dmW);
3835 /*********************************************************************
3836 * WINSPOOL_GetPrinter_1
3838 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3840 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3841 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3843 DWORD size, left = cbBuf;
3844 BOOL space = (cbBuf > 0);
3849 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3850 if(space && size <= left) {
3851 pi1->pName = (LPWSTR)ptr;
3859 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3860 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3861 if(space && size <= left) {
3862 pi1->pDescription = (LPWSTR)ptr;
3870 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3871 if(space && size <= left) {
3872 pi1->pComment = (LPWSTR)ptr;
3880 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3882 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3883 memset(pi1, 0, sizeof(*pi1));
3887 /*********************************************************************
3888 * WINSPOOL_GetPrinter_2
3890 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3892 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3893 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3895 DWORD size, left = cbBuf;
3896 BOOL space = (cbBuf > 0);
3901 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3902 if(space && size <= left) {
3903 pi2->pPrinterName = (LPWSTR)ptr;
3910 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3911 if(space && size <= left) {
3912 pi2->pShareName = (LPWSTR)ptr;
3919 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3920 if(space && size <= left) {
3921 pi2->pPortName = (LPWSTR)ptr;
3928 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3929 if(space && size <= left) {
3930 pi2->pDriverName = (LPWSTR)ptr;
3937 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3938 if(space && size <= left) {
3939 pi2->pComment = (LPWSTR)ptr;
3946 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3947 if(space && size <= left) {
3948 pi2->pLocation = (LPWSTR)ptr;
3955 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3956 if(space && size <= left) {
3957 pi2->pDevMode = (LPDEVMODEW)ptr;
3966 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3967 if(space && size <= left) {
3968 pi2->pDevMode = (LPDEVMODEW)ptr;
3975 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3976 if(space && size <= left) {
3977 pi2->pSepFile = (LPWSTR)ptr;
3984 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3985 if(space && size <= left) {
3986 pi2->pPrintProcessor = (LPWSTR)ptr;
3993 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3994 if(space && size <= left) {
3995 pi2->pDatatype = (LPWSTR)ptr;
4002 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4003 if(space && size <= left) {
4004 pi2->pParameters = (LPWSTR)ptr;
4012 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4013 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4014 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4015 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4016 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4019 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4020 memset(pi2, 0, sizeof(*pi2));
4025 /*********************************************************************
4026 * WINSPOOL_GetPrinter_4
4028 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4030 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4031 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4033 DWORD size, left = cbBuf;
4034 BOOL space = (cbBuf > 0);
4039 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4040 if(space && size <= left) {
4041 pi4->pPrinterName = (LPWSTR)ptr;
4049 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4052 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4053 memset(pi4, 0, sizeof(*pi4));
4058 /*********************************************************************
4059 * WINSPOOL_GetPrinter_5
4061 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4063 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4064 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4066 DWORD size, left = cbBuf;
4067 BOOL space = (cbBuf > 0);
4072 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4073 if(space && size <= left) {
4074 pi5->pPrinterName = (LPWSTR)ptr;
4081 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4082 if(space && size <= left) {
4083 pi5->pPortName = (LPWSTR)ptr;
4091 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4092 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4093 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4096 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4097 memset(pi5, 0, sizeof(*pi5));
4102 /*********************************************************************
4103 * WINSPOOL_GetPrinter_7
4105 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4107 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4108 DWORD cbBuf, LPDWORD pcbNeeded)
4110 DWORD size, left = cbBuf;
4111 BOOL space = (cbBuf > 0);
4116 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4119 size = sizeof(pi7->pszObjectGUID);
4121 if (space && size <= left) {
4122 pi7->pszObjectGUID = (LPWSTR)ptr;
4129 /* We do not have a Directory Service */
4130 pi7->dwAction = DSPRINT_UNPUBLISH;
4133 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4134 memset(pi7, 0, sizeof(*pi7));
4139 /*********************************************************************
4140 * WINSPOOL_GetPrinter_9
4142 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4144 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4145 DWORD cbBuf, LPDWORD pcbNeeded)
4148 BOOL space = (cbBuf > 0);
4152 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4153 if(space && size <= cbBuf) {
4154 pi9->pDevMode = (LPDEVMODEW)buf;
4161 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4162 if(space && size <= cbBuf) {
4163 pi9->pDevMode = (LPDEVMODEW)buf;
4169 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4170 memset(pi9, 0, sizeof(*pi9));
4175 /*****************************************************************************
4176 * GetPrinterW [WINSPOOL.@]
4178 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4179 DWORD cbBuf, LPDWORD pcbNeeded)
4181 DWORD size, needed = 0, err;
4186 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4188 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4191 SetLastError( err );
4198 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4200 size = sizeof(PRINTER_INFO_2W);
4202 ptr = pPrinter + size;
4204 memset(pPrinter, 0, size);
4209 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4216 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4218 size = sizeof(PRINTER_INFO_4W);
4220 ptr = pPrinter + size;
4222 memset(pPrinter, 0, size);
4227 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4235 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4237 size = sizeof(PRINTER_INFO_5W);
4239 ptr = pPrinter + size;
4241 memset(pPrinter, 0, size);
4247 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4255 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4257 size = sizeof(PRINTER_INFO_6);
4258 if (size <= cbBuf) {
4259 /* FIXME: We do not update the status yet */
4260 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4272 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4274 size = sizeof(PRINTER_INFO_7W);
4275 if (size <= cbBuf) {
4276 ptr = pPrinter + size;
4278 memset(pPrinter, 0, size);
4284 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4291 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4292 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4296 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4298 size = sizeof(PRINTER_INFO_9W);
4300 ptr = pPrinter + size;
4302 memset(pPrinter, 0, size);
4308 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4315 FIXME("Unimplemented level %d\n", Level);
4316 SetLastError(ERROR_INVALID_LEVEL);
4317 RegCloseKey(hkeyPrinter);
4321 RegCloseKey(hkeyPrinter);
4323 TRACE("returning %d needed = %d\n", ret, needed);
4324 if(pcbNeeded) *pcbNeeded = needed;
4326 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4330 /*****************************************************************************
4331 * GetPrinterA [WINSPOOL.@]
4333 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4334 DWORD cbBuf, LPDWORD pcbNeeded)
4340 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4342 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4344 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4345 HeapFree(GetProcessHeap(), 0, buf);
4350 /*****************************************************************************
4351 * WINSPOOL_EnumPrintersW
4353 * Implementation of EnumPrintersW
4355 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4356 DWORD dwLevel, LPBYTE lpbPrinters,
4357 DWORD cbBuf, LPDWORD lpdwNeeded,
4358 LPDWORD lpdwReturned)
4361 HKEY hkeyPrinters, hkeyPrinter;
4362 WCHAR PrinterName[255];
4363 DWORD needed = 0, number = 0;
4364 DWORD used, i, left;
4368 memset(lpbPrinters, 0, cbBuf);
4374 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4375 if(dwType == PRINTER_ENUM_DEFAULT)
4378 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4379 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4380 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4382 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4388 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4389 FIXME("dwType = %08x\n", dwType);
4390 SetLastError(ERROR_INVALID_FLAGS);
4394 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4396 ERR("Can't create Printers key\n");
4400 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4401 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4402 RegCloseKey(hkeyPrinters);
4403 ERR("Can't query Printers key\n");
4406 TRACE("Found %d printers\n", number);
4410 used = number * sizeof(PRINTER_INFO_1W);
4413 used = number * sizeof(PRINTER_INFO_2W);
4416 used = number * sizeof(PRINTER_INFO_4W);
4419 used = number * sizeof(PRINTER_INFO_5W);
4423 SetLastError(ERROR_INVALID_LEVEL);
4424 RegCloseKey(hkeyPrinters);
4427 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4429 for(i = 0; i < number; i++) {
4430 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4432 ERR("Can't enum key number %d\n", i);
4433 RegCloseKey(hkeyPrinters);
4436 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4437 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4439 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4440 RegCloseKey(hkeyPrinters);
4445 buf = lpbPrinters + used;
4446 left = cbBuf - used;
4454 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4457 if(pi) pi += sizeof(PRINTER_INFO_1W);
4460 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4463 if(pi) pi += sizeof(PRINTER_INFO_2W);
4466 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4469 if(pi) pi += sizeof(PRINTER_INFO_4W);
4472 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4475 if(pi) pi += sizeof(PRINTER_INFO_5W);
4478 ERR("Shouldn't be here!\n");
4479 RegCloseKey(hkeyPrinter);
4480 RegCloseKey(hkeyPrinters);
4483 RegCloseKey(hkeyPrinter);
4485 RegCloseKey(hkeyPrinters);
4492 memset(lpbPrinters, 0, cbBuf);
4493 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4497 *lpdwReturned = number;
4498 SetLastError(ERROR_SUCCESS);
4503 /******************************************************************
4504 * EnumPrintersW [WINSPOOL.@]
4506 * Enumerates the available printers, print servers and print
4507 * providers, depending on the specified flags, name and level.
4511 * If level is set to 1:
4512 * Returns an array of PRINTER_INFO_1 data structures in the
4513 * lpbPrinters buffer.
4515 * If level is set to 2:
4516 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4517 * Returns an array of PRINTER_INFO_2 data structures in the
4518 * lpbPrinters buffer. Note that according to MSDN also an
4519 * OpenPrinter should be performed on every remote printer.
4521 * If level is set to 4 (officially WinNT only):
4522 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4523 * Fast: Only the registry is queried to retrieve printer names,
4524 * no connection to the driver is made.
4525 * Returns an array of PRINTER_INFO_4 data structures in the
4526 * lpbPrinters buffer.
4528 * If level is set to 5 (officially WinNT4/Win9x only):
4529 * Fast: Only the registry is queried to retrieve printer names,
4530 * no connection to the driver is made.
4531 * Returns an array of PRINTER_INFO_5 data structures in the
4532 * lpbPrinters buffer.
4534 * If level set to 3 or 6+:
4535 * returns zero (failure!)
4537 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4541 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4542 * - Only levels 2, 4 and 5 are implemented at the moment.
4543 * - 16-bit printer drivers are not enumerated.
4544 * - Returned amount of bytes used/needed does not match the real Windoze
4545 * implementation (as in this implementation, all strings are part
4546 * of the buffer, whereas Win32 keeps them somewhere else)
4547 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4550 * - In a regular Wine installation, no registry settings for printers
4551 * exist, which makes this function return an empty list.
4553 BOOL WINAPI EnumPrintersW(
4554 DWORD dwType, /* [in] Types of print objects to enumerate */
4555 LPWSTR lpszName, /* [in] name of objects to enumerate */
4556 DWORD dwLevel, /* [in] type of printer info structure */
4557 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4558 DWORD cbBuf, /* [in] max size of buffer in bytes */
4559 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4560 LPDWORD lpdwReturned /* [out] number of entries returned */
4563 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4564 lpdwNeeded, lpdwReturned);
4567 /******************************************************************
4568 * EnumPrintersA [WINSPOOL.@]
4573 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4574 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4577 UNICODE_STRING pNameU;
4581 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4582 pPrinters, cbBuf, pcbNeeded, pcReturned);
4584 pNameW = asciitounicode(&pNameU, pName);
4586 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4587 MS Office need this */
4588 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4590 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4592 RtlFreeUnicodeString(&pNameU);
4594 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4596 HeapFree(GetProcessHeap(), 0, pPrintersW);
4600 /*****************************************************************************
4601 * WINSPOOL_GetDriverInfoFromReg [internal]
4603 * Enters the information from the registry into the DRIVER_INFO struct
4606 * zero if the printer driver does not exist in the registry
4607 * (only if Level > 1) otherwise nonzero
4609 static BOOL WINSPOOL_GetDriverInfoFromReg(
4612 const printenv_t * env,
4614 LPBYTE ptr, /* DRIVER_INFO */
4615 LPBYTE pDriverStrings, /* strings buffer */
4616 DWORD cbBuf, /* size of string buffer */
4617 LPDWORD pcbNeeded) /* space needed for str. */
4621 WCHAR driverdir[MAX_PATH];
4623 LPBYTE strPtr = pDriverStrings;
4624 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4626 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4627 debugstr_w(DriverName), env,
4628 Level, di, pDriverStrings, cbBuf);
4630 if (di) ZeroMemory(di, di_sizeof[Level]);
4632 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4633 if (*pcbNeeded <= cbBuf)
4634 strcpyW((LPWSTR)strPtr, DriverName);
4636 /* pName for level 1 has a different offset! */
4638 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4642 /* .cVersion and .pName for level > 1 */
4644 di->cVersion = env->driverversion;
4645 di->pName = (LPWSTR) strPtr;
4646 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4649 /* Reserve Space for the largest subdir and a Backslash*/
4650 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4651 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4652 /* Should never Fail */
4655 lstrcatW(driverdir, env->versionsubdir);
4656 lstrcatW(driverdir, backslashW);
4658 /* dirlen must not include the terminating zero */
4659 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4661 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4662 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4663 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4668 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4671 if (*pcbNeeded <= cbBuf) {
4672 lstrcpyW((LPWSTR)strPtr, env->envname);
4673 if (di) di->pEnvironment = (LPWSTR)strPtr;
4674 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4677 /* .pDriverPath is the Graphics rendering engine.
4678 The full Path is required to avoid a crash in some apps */
4679 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4681 if (*pcbNeeded <= cbBuf)
4682 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4684 if (di) di->pDriverPath = (LPWSTR)strPtr;
4685 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4688 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4689 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4691 if (*pcbNeeded <= cbBuf)
4692 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4694 if (di) di->pDataFile = (LPWSTR)strPtr;
4695 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4698 /* .pConfigFile is the Driver user Interface */
4699 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4701 if (*pcbNeeded <= cbBuf)
4702 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4704 if (di) di->pConfigFile = (LPWSTR)strPtr;
4705 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4709 RegCloseKey(hkeyDriver);
4710 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4715 RegCloseKey(hkeyDriver);
4716 FIXME("level 5: incomplete\n");
4721 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4723 if (*pcbNeeded <= cbBuf)
4724 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4726 if (di) di->pHelpFile = (LPWSTR)strPtr;
4727 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4730 /* .pDependentFiles */
4731 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4733 if (*pcbNeeded <= cbBuf)
4734 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4736 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4737 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4739 else if (GetVersion() & 0x80000000) {
4740 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4741 size = 2 * sizeof(WCHAR);
4743 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4745 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4746 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4749 /* .pMonitorName is the optional Language Monitor */
4750 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4752 if (*pcbNeeded <= cbBuf)
4753 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4755 if (di) di->pMonitorName = (LPWSTR)strPtr;
4756 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4759 /* .pDefaultDataType */
4760 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4762 if(*pcbNeeded <= cbBuf)
4763 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4765 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4766 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4770 RegCloseKey(hkeyDriver);
4771 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4775 /* .pszzPreviousNames */
4776 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4778 if(*pcbNeeded <= cbBuf)
4779 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4781 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4782 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4786 RegCloseKey(hkeyDriver);
4787 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4791 /* support is missing, but not important enough for a FIXME */
4792 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4795 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4797 if(*pcbNeeded <= cbBuf)
4798 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4800 if (di) di->pszMfgName = (LPWSTR)strPtr;
4801 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4805 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4807 if(*pcbNeeded <= cbBuf)
4808 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4810 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4811 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4814 /* .pszHardwareID */
4815 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4817 if(*pcbNeeded <= cbBuf)
4818 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4820 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4821 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4825 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4827 if(*pcbNeeded <= cbBuf)
4828 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4830 if (di) di->pszProvider = (LPWSTR)strPtr;
4831 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4835 RegCloseKey(hkeyDriver);
4839 /* support is missing, but not important enough for a FIXME */
4840 TRACE("level 8: incomplete\n");
4842 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4843 RegCloseKey(hkeyDriver);
4847 /*****************************************************************************
4848 * GetPrinterDriverW [WINSPOOL.@]
4850 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4851 DWORD Level, LPBYTE pDriverInfo,
4852 DWORD cbBuf, LPDWORD pcbNeeded)
4855 WCHAR DriverName[100];
4856 DWORD ret, type, size, needed = 0;
4858 HKEY hkeyPrinter, hkeyDrivers;
4859 const printenv_t * env;
4861 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4862 Level,pDriverInfo,cbBuf, pcbNeeded);
4865 ZeroMemory(pDriverInfo, cbBuf);
4867 if (!(name = get_opened_printer_name(hPrinter))) {
4868 SetLastError(ERROR_INVALID_HANDLE);
4872 if (Level < 1 || Level == 7 || Level > 8) {
4873 SetLastError(ERROR_INVALID_LEVEL);
4877 env = validate_envW(pEnvironment);
4878 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4880 ret = open_printer_reg_key( name, &hkeyPrinter );
4883 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
4884 SetLastError( ret );
4888 size = sizeof(DriverName);
4890 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4891 (LPBYTE)DriverName, &size);
4892 RegCloseKey(hkeyPrinter);
4893 if(ret != ERROR_SUCCESS) {
4894 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4898 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4900 ERR("Can't create Drivers key\n");
4904 size = di_sizeof[Level];
4905 if ((size <= cbBuf) && pDriverInfo)
4906 ptr = pDriverInfo + size;
4908 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4909 env, Level, pDriverInfo, ptr,
4910 (cbBuf < size) ? 0 : cbBuf - size,
4912 RegCloseKey(hkeyDrivers);
4916 RegCloseKey(hkeyDrivers);
4918 if(pcbNeeded) *pcbNeeded = size + needed;
4919 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4920 if(cbBuf >= size + needed) return TRUE;
4921 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4925 /*****************************************************************************
4926 * GetPrinterDriverA [WINSPOOL.@]
4928 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4929 DWORD Level, LPBYTE pDriverInfo,
4930 DWORD cbBuf, LPDWORD pcbNeeded)
4933 UNICODE_STRING pEnvW;
4939 ZeroMemory(pDriverInfo, cbBuf);
4940 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4943 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4944 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4947 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4949 HeapFree(GetProcessHeap(), 0, buf);
4951 RtlFreeUnicodeString(&pEnvW);
4955 /*****************************************************************************
4956 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4958 * Return the PATH for the Printer-Drivers (UNICODE)
4961 * pName [I] Servername (NT only) or NULL (local Computer)
4962 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4963 * Level [I] Structure-Level (must be 1)
4964 * pDriverDirectory [O] PTR to Buffer that receives the Result
4965 * cbBuf [I] Size of Buffer at pDriverDirectory
4966 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4967 * required for pDriverDirectory
4970 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4971 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4972 * if cbBuf is too small
4974 * Native Values returned in pDriverDirectory on Success:
4975 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4976 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4977 *| win9x(Windows 4.0): "%winsysdir%"
4979 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4982 *- Only NULL or "" is supported for pName
4985 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4986 DWORD Level, LPBYTE pDriverDirectory,
4987 DWORD cbBuf, LPDWORD pcbNeeded)
4989 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4990 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4992 if ((backend == NULL) && !load_backend()) return FALSE;
4995 /* (Level != 1) is ignored in win9x */
4996 SetLastError(ERROR_INVALID_LEVEL);
4999 if (pcbNeeded == NULL) {
5000 /* (pcbNeeded == NULL) is ignored in win9x */
5001 SetLastError(RPC_X_NULL_REF_POINTER);
5005 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5006 pDriverDirectory, cbBuf, pcbNeeded);
5011 /*****************************************************************************
5012 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5014 * Return the PATH for the Printer-Drivers (ANSI)
5016 * See GetPrinterDriverDirectoryW.
5019 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5022 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5023 DWORD Level, LPBYTE pDriverDirectory,
5024 DWORD cbBuf, LPDWORD pcbNeeded)
5026 UNICODE_STRING nameW, environmentW;
5029 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5030 WCHAR *driverDirectoryW = NULL;
5032 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5033 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5035 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5037 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5038 else nameW.Buffer = NULL;
5039 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5040 else environmentW.Buffer = NULL;
5042 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5043 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5046 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5047 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5049 *pcbNeeded = needed;
5050 ret = (needed <= cbBuf) ? TRUE : FALSE;
5052 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5054 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5056 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5057 RtlFreeUnicodeString(&environmentW);
5058 RtlFreeUnicodeString(&nameW);
5063 /*****************************************************************************
5064 * AddPrinterDriverA [WINSPOOL.@]
5066 * See AddPrinterDriverW.
5069 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5071 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5072 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5075 /******************************************************************************
5076 * AddPrinterDriverW (WINSPOOL.@)
5078 * Install a Printer Driver
5081 * pName [I] Servername or NULL (local Computer)
5082 * level [I] Level for the supplied DRIVER_INFO_*W struct
5083 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5090 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5092 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5093 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5096 /*****************************************************************************
5097 * AddPrintProcessorA [WINSPOOL.@]
5099 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5100 LPSTR pPrintProcessorName)
5102 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5103 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5107 /*****************************************************************************
5108 * AddPrintProcessorW [WINSPOOL.@]
5110 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5111 LPWSTR pPrintProcessorName)
5113 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5114 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5118 /*****************************************************************************
5119 * AddPrintProvidorA [WINSPOOL.@]
5121 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5123 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5127 /*****************************************************************************
5128 * AddPrintProvidorW [WINSPOOL.@]
5130 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5132 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5136 /*****************************************************************************
5137 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5139 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5140 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5142 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5143 pDevModeOutput, pDevModeInput);
5147 /*****************************************************************************
5148 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5150 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5151 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5153 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5154 pDevModeOutput, pDevModeInput);
5158 /*****************************************************************************
5159 * PrinterProperties [WINSPOOL.@]
5161 * Displays a dialog to set the properties of the printer.
5164 * nonzero on success or zero on failure
5167 * implemented as stub only
5169 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5170 HANDLE hPrinter /* [in] handle to printer object */
5172 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5173 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5177 /*****************************************************************************
5178 * EnumJobsA [WINSPOOL.@]
5181 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5182 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5185 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5186 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5188 if(pcbNeeded) *pcbNeeded = 0;
5189 if(pcReturned) *pcReturned = 0;
5194 /*****************************************************************************
5195 * EnumJobsW [WINSPOOL.@]
5198 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5199 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5202 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5203 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5205 if(pcbNeeded) *pcbNeeded = 0;
5206 if(pcReturned) *pcReturned = 0;
5210 /*****************************************************************************
5211 * WINSPOOL_EnumPrinterDrivers [internal]
5213 * Delivers information about all printer drivers installed on the
5214 * localhost or a given server
5217 * nonzero on success or zero on failure. If the buffer for the returned
5218 * information is too small the function will return an error
5221 * - only implemented for localhost, foreign hosts will return an error
5223 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5224 DWORD Level, LPBYTE pDriverInfo,
5226 DWORD cbBuf, LPDWORD pcbNeeded,
5227 LPDWORD pcFound, DWORD data_offset)
5231 const printenv_t * env;
5233 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5234 debugstr_w(pName), debugstr_w(pEnvironment),
5235 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5237 env = validate_envW(pEnvironment);
5238 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5242 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5244 ERR("Can't open Drivers key\n");
5248 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5249 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5250 RegCloseKey(hkeyDrivers);
5251 ERR("Can't query Drivers key\n");
5254 TRACE("Found %d Drivers\n", *pcFound);
5256 /* get size of single struct
5257 * unicode and ascii structure have the same size
5259 size = di_sizeof[Level];
5261 if (data_offset == 0)
5262 data_offset = size * (*pcFound);
5263 *pcbNeeded = data_offset;
5265 for( i = 0; i < *pcFound; i++) {
5266 WCHAR DriverNameW[255];
5267 PBYTE table_ptr = NULL;
5268 PBYTE data_ptr = NULL;
5271 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5273 ERR("Can't enum key number %d\n", i);
5274 RegCloseKey(hkeyDrivers);
5278 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5279 table_ptr = pDriverInfo + (driver_index + i) * size;
5280 if (pDriverInfo && *pcbNeeded <= cbBuf)
5281 data_ptr = pDriverInfo + *pcbNeeded;
5283 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5284 env, Level, table_ptr, data_ptr,
5285 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5287 RegCloseKey(hkeyDrivers);
5291 *pcbNeeded += needed;
5294 RegCloseKey(hkeyDrivers);
5296 if(cbBuf < *pcbNeeded){
5297 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5304 /*****************************************************************************
5305 * EnumPrinterDriversW [WINSPOOL.@]
5307 * see function EnumPrinterDrivers for RETURNS, BUGS
5309 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5310 LPBYTE pDriverInfo, DWORD cbBuf,
5311 LPDWORD pcbNeeded, LPDWORD pcReturned)
5313 static const WCHAR allW[] = {'a','l','l',0};
5317 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5319 SetLastError(RPC_X_NULL_REF_POINTER);
5323 /* check for local drivers */
5324 if((pName) && (pName[0])) {
5325 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5326 SetLastError(ERROR_ACCESS_DENIED);
5330 /* check input parameter */
5331 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5332 SetLastError(ERROR_INVALID_LEVEL);
5336 if(pDriverInfo && cbBuf > 0)
5337 memset( pDriverInfo, 0, cbBuf);
5339 /* Exception: pull all printers */
5340 if (pEnvironment && !strcmpW(pEnvironment, allW))
5342 DWORD i, needed, bufsize = cbBuf;
5343 DWORD total_needed = 0;
5344 DWORD total_found = 0;
5347 /* Precompute the overall total; we need this to know
5348 where pointers end and data begins (i.e. data_offset) */
5349 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5352 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5353 NULL, 0, 0, &needed, &found, 0);
5354 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5355 total_needed += needed;
5356 total_found += found;
5359 data_offset = di_sizeof[Level] * total_found;
5364 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5367 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5368 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5369 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5371 *pcReturned += found;
5372 *pcbNeeded = needed;
5373 data_offset = needed;
5374 total_found += found;
5379 /* Normal behavior */
5380 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5381 0, cbBuf, pcbNeeded, &found, 0);
5383 *pcReturned = found;
5388 /*****************************************************************************
5389 * EnumPrinterDriversA [WINSPOOL.@]
5391 * see function EnumPrinterDrivers for RETURNS, BUGS
5393 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5394 LPBYTE pDriverInfo, DWORD cbBuf,
5395 LPDWORD pcbNeeded, LPDWORD pcReturned)
5398 UNICODE_STRING pNameW, pEnvironmentW;
5399 PWSTR pwstrNameW, pwstrEnvironmentW;
5403 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5405 pwstrNameW = asciitounicode(&pNameW, pName);
5406 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5408 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5409 buf, cbBuf, pcbNeeded, pcReturned);
5411 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5413 HeapFree(GetProcessHeap(), 0, buf);
5415 RtlFreeUnicodeString(&pNameW);
5416 RtlFreeUnicodeString(&pEnvironmentW);
5421 /******************************************************************************
5422 * EnumPortsA (WINSPOOL.@)
5427 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5428 LPDWORD pcbNeeded, LPDWORD pcReturned)
5431 LPBYTE bufferW = NULL;
5432 LPWSTR nameW = NULL;
5434 DWORD numentries = 0;
5437 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5438 cbBuf, pcbNeeded, pcReturned);
5440 /* convert servername to unicode */
5442 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5443 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5444 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5446 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5447 needed = cbBuf * sizeof(WCHAR);
5448 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5449 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5451 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5452 if (pcbNeeded) needed = *pcbNeeded;
5453 /* HeapReAlloc return NULL, when bufferW was NULL */
5454 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5455 HeapAlloc(GetProcessHeap(), 0, needed);
5457 /* Try again with the large Buffer */
5458 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5460 needed = pcbNeeded ? *pcbNeeded : 0;
5461 numentries = pcReturned ? *pcReturned : 0;
5464 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5465 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5468 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5469 DWORD entrysize = 0;
5472 LPPORT_INFO_2W pi2w;
5473 LPPORT_INFO_2A pi2a;
5476 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5478 /* First pass: calculate the size for all Entries */
5479 pi2w = (LPPORT_INFO_2W) bufferW;
5480 pi2a = (LPPORT_INFO_2A) pPorts;
5482 while (index < numentries) {
5484 needed += entrysize; /* PORT_INFO_?A */
5485 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5487 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5488 NULL, 0, NULL, NULL);
5490 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5491 NULL, 0, NULL, NULL);
5492 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5493 NULL, 0, NULL, NULL);
5495 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5496 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5497 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5500 /* check for errors and quit on failure */
5501 if (cbBuf < needed) {
5502 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5506 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5507 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5508 cbBuf -= len ; /* free Bytes in the user-Buffer */
5509 pi2w = (LPPORT_INFO_2W) bufferW;
5510 pi2a = (LPPORT_INFO_2A) pPorts;
5512 /* Second Pass: Fill the User Buffer (if we have one) */
5513 while ((index < numentries) && pPorts) {
5515 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5516 pi2a->pPortName = ptr;
5517 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5518 ptr, cbBuf , NULL, NULL);
5522 pi2a->pMonitorName = ptr;
5523 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5524 ptr, cbBuf, NULL, NULL);
5528 pi2a->pDescription = ptr;
5529 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5530 ptr, cbBuf, NULL, NULL);
5534 pi2a->fPortType = pi2w->fPortType;
5535 pi2a->Reserved = 0; /* documented: "must be zero" */
5538 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5539 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5540 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5545 if (pcbNeeded) *pcbNeeded = needed;
5546 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5548 HeapFree(GetProcessHeap(), 0, nameW);
5549 HeapFree(GetProcessHeap(), 0, bufferW);
5551 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5552 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5558 /******************************************************************************
5559 * EnumPortsW (WINSPOOL.@)
5561 * Enumerate available Ports
5564 * pName [I] Servername or NULL (local Computer)
5565 * Level [I] Structure-Level (1 or 2)
5566 * pPorts [O] PTR to Buffer that receives the Result
5567 * cbBuf [I] Size of Buffer at pPorts
5568 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5569 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5573 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5576 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5579 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5580 cbBuf, pcbNeeded, pcReturned);
5582 if ((backend == NULL) && !load_backend()) return FALSE;
5584 /* Level is not checked in win9x */
5585 if (!Level || (Level > 2)) {
5586 WARN("level (%d) is ignored in win9x\n", Level);
5587 SetLastError(ERROR_INVALID_LEVEL);
5590 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5591 SetLastError(RPC_X_NULL_REF_POINTER);
5595 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5598 /******************************************************************************
5599 * GetDefaultPrinterW (WINSPOOL.@)
5602 * This function must read the value from data 'device' of key
5603 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5605 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5609 WCHAR *buffer, *ptr;
5613 SetLastError(ERROR_INVALID_PARAMETER);
5617 /* make the buffer big enough for the stuff from the profile/registry,
5618 * the content must fit into the local buffer to compute the correct
5619 * size even if the extern buffer is too small or not given.
5620 * (20 for ,driver,port) */
5622 len = max(100, (insize + 20));
5623 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5625 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5627 SetLastError (ERROR_FILE_NOT_FOUND);
5631 TRACE("%s\n", debugstr_w(buffer));
5633 if ((ptr = strchrW(buffer, ',')) == NULL)
5635 SetLastError(ERROR_INVALID_NAME);
5641 *namesize = strlenW(buffer) + 1;
5642 if(!name || (*namesize > insize))
5644 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5648 strcpyW(name, buffer);
5651 HeapFree( GetProcessHeap(), 0, buffer);
5656 /******************************************************************************
5657 * GetDefaultPrinterA (WINSPOOL.@)
5659 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5663 WCHAR *bufferW = NULL;
5667 SetLastError(ERROR_INVALID_PARAMETER);
5671 if(name && *namesize) {
5673 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5676 if(!GetDefaultPrinterW( bufferW, namesize)) {
5681 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5685 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5688 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5691 HeapFree( GetProcessHeap(), 0, bufferW);
5696 /******************************************************************************
5697 * SetDefaultPrinterW (WINSPOOL.204)
5699 * Set the Name of the Default Printer
5702 * pszPrinter [I] Name of the Printer or NULL
5709 * When the Parameter is NULL or points to an Empty String and
5710 * a Default Printer was already present, then this Function changes nothing.
5711 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5712 * the First enumerated local Printer is used.
5715 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5717 WCHAR default_printer[MAX_PATH];
5718 LPWSTR buffer = NULL;
5724 TRACE("(%s)\n", debugstr_w(pszPrinter));
5725 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5727 default_printer[0] = '\0';
5728 size = sizeof(default_printer)/sizeof(WCHAR);
5730 /* if we have a default Printer, do nothing. */
5731 if (GetDefaultPrinterW(default_printer, &size))
5735 /* we have no default Printer: search local Printers and use the first */
5736 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5738 default_printer[0] = '\0';
5739 size = sizeof(default_printer)/sizeof(WCHAR);
5740 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5742 pszPrinter = default_printer;
5743 TRACE("using %s\n", debugstr_w(pszPrinter));
5748 if (pszPrinter == NULL) {
5749 TRACE("no local printer found\n");
5750 SetLastError(ERROR_FILE_NOT_FOUND);
5755 /* "pszPrinter" is never empty or NULL here. */
5756 namelen = lstrlenW(pszPrinter);
5757 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5758 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5760 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5761 HeapFree(GetProcessHeap(), 0, buffer);
5762 SetLastError(ERROR_FILE_NOT_FOUND);
5766 /* read the devices entry for the printer (driver,port) to build the string for the
5767 default device entry (printer,driver,port) */
5768 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5769 buffer[namelen] = ',';
5770 namelen++; /* move index to the start of the driver */
5772 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5773 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5775 TRACE("set device to %s\n", debugstr_w(buffer));
5777 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5778 TRACE("failed to set the device entry: %d\n", GetLastError());
5779 lres = ERROR_INVALID_PRINTER_NAME;
5782 /* remove the next section, when INIFileMapping is implemented */
5785 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5786 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5793 if (lres != ERROR_FILE_NOT_FOUND)
5794 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5796 SetLastError(ERROR_INVALID_PRINTER_NAME);
5800 HeapFree(GetProcessHeap(), 0, buffer);
5801 return (lres == ERROR_SUCCESS);
5804 /******************************************************************************
5805 * SetDefaultPrinterA (WINSPOOL.202)
5807 * See SetDefaultPrinterW.
5810 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5812 LPWSTR bufferW = NULL;
5815 TRACE("(%s)\n", debugstr_a(pszPrinter));
5817 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5818 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5819 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5821 res = SetDefaultPrinterW(bufferW);
5822 HeapFree(GetProcessHeap(), 0, bufferW);
5826 /******************************************************************************
5827 * SetPrinterDataExA (WINSPOOL.@)
5829 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5830 LPCSTR pValueName, DWORD Type,
5831 LPBYTE pData, DWORD cbData)
5833 HKEY hkeyPrinter, hkeySubkey;
5836 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5837 debugstr_a(pValueName), Type, pData, cbData);
5839 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5843 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5845 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5846 RegCloseKey(hkeyPrinter);
5849 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5850 RegCloseKey(hkeySubkey);
5851 RegCloseKey(hkeyPrinter);
5855 /******************************************************************************
5856 * SetPrinterDataExW (WINSPOOL.@)
5858 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5859 LPCWSTR pValueName, DWORD Type,
5860 LPBYTE pData, DWORD cbData)
5862 HKEY hkeyPrinter, hkeySubkey;
5865 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5866 debugstr_w(pValueName), Type, pData, cbData);
5868 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5872 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5874 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5875 RegCloseKey(hkeyPrinter);
5878 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5879 RegCloseKey(hkeySubkey);
5880 RegCloseKey(hkeyPrinter);
5884 /******************************************************************************
5885 * SetPrinterDataA (WINSPOOL.@)
5887 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5888 LPBYTE pData, DWORD cbData)
5890 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5894 /******************************************************************************
5895 * SetPrinterDataW (WINSPOOL.@)
5897 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5898 LPBYTE pData, DWORD cbData)
5900 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5904 /******************************************************************************
5905 * GetPrinterDataExA (WINSPOOL.@)
5907 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5908 LPCSTR pValueName, LPDWORD pType,
5909 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5911 opened_printer_t *printer;
5912 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5915 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5916 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5918 printer = get_opened_printer(hPrinter);
5919 if(!printer) return ERROR_INVALID_HANDLE;
5921 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5922 if (ret) return ret;
5924 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5926 if (printer->name) {
5928 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5930 RegCloseKey(hkeyPrinters);
5933 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5934 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5935 RegCloseKey(hkeyPrinter);
5936 RegCloseKey(hkeyPrinters);
5941 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5942 0, pType, pData, pcbNeeded);
5944 if (!ret && !pData) ret = ERROR_MORE_DATA;
5946 RegCloseKey(hkeySubkey);
5947 RegCloseKey(hkeyPrinter);
5948 RegCloseKey(hkeyPrinters);
5950 TRACE("--> %d\n", ret);
5954 /******************************************************************************
5955 * GetPrinterDataExW (WINSPOOL.@)
5957 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5958 LPCWSTR pValueName, LPDWORD pType,
5959 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5961 opened_printer_t *printer;
5962 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5965 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5966 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5968 printer = get_opened_printer(hPrinter);
5969 if(!printer) return ERROR_INVALID_HANDLE;
5971 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5972 if (ret) return ret;
5974 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5976 if (printer->name) {
5978 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5980 RegCloseKey(hkeyPrinters);
5983 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5984 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5985 RegCloseKey(hkeyPrinter);
5986 RegCloseKey(hkeyPrinters);
5991 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5992 0, pType, pData, pcbNeeded);
5994 if (!ret && !pData) ret = ERROR_MORE_DATA;
5996 RegCloseKey(hkeySubkey);
5997 RegCloseKey(hkeyPrinter);
5998 RegCloseKey(hkeyPrinters);
6000 TRACE("--> %d\n", ret);
6004 /******************************************************************************
6005 * GetPrinterDataA (WINSPOOL.@)
6007 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6008 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6010 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6011 pData, nSize, pcbNeeded);
6014 /******************************************************************************
6015 * GetPrinterDataW (WINSPOOL.@)
6017 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6018 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6020 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6021 pData, nSize, pcbNeeded);
6024 /*******************************************************************************
6025 * EnumPrinterDataExW [WINSPOOL.@]
6027 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6028 LPBYTE pEnumValues, DWORD cbEnumValues,
6029 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6031 HKEY hkPrinter, hkSubKey;
6032 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6033 cbValueNameLen, cbMaxValueLen, cbValueLen,
6038 PPRINTER_ENUM_VALUESW ppev;
6040 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6042 if (pKeyName == NULL || *pKeyName == 0)
6043 return ERROR_INVALID_PARAMETER;
6045 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6046 if (ret != ERROR_SUCCESS)
6048 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6053 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6054 if (ret != ERROR_SUCCESS)
6056 r = RegCloseKey (hkPrinter);
6057 if (r != ERROR_SUCCESS)
6058 WARN ("RegCloseKey returned %i\n", r);
6059 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6060 debugstr_w (pKeyName), ret);
6064 ret = RegCloseKey (hkPrinter);
6065 if (ret != ERROR_SUCCESS)
6067 ERR ("RegCloseKey returned %i\n", ret);
6068 r = RegCloseKey (hkSubKey);
6069 if (r != ERROR_SUCCESS)
6070 WARN ("RegCloseKey returned %i\n", r);
6074 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6075 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6076 if (ret != ERROR_SUCCESS)
6078 r = RegCloseKey (hkSubKey);
6079 if (r != ERROR_SUCCESS)
6080 WARN ("RegCloseKey returned %i\n", r);
6081 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6085 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6086 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6088 if (cValues == 0) /* empty key */
6090 r = RegCloseKey (hkSubKey);
6091 if (r != ERROR_SUCCESS)
6092 WARN ("RegCloseKey returned %i\n", r);
6093 *pcbEnumValues = *pnEnumValues = 0;
6094 return ERROR_SUCCESS;
6097 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6099 hHeap = GetProcessHeap ();
6102 ERR ("GetProcessHeap failed\n");
6103 r = RegCloseKey (hkSubKey);
6104 if (r != ERROR_SUCCESS)
6105 WARN ("RegCloseKey returned %i\n", r);
6106 return ERROR_OUTOFMEMORY;
6109 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6110 if (lpValueName == NULL)
6112 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6113 r = RegCloseKey (hkSubKey);
6114 if (r != ERROR_SUCCESS)
6115 WARN ("RegCloseKey returned %i\n", r);
6116 return ERROR_OUTOFMEMORY;
6119 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6120 if (lpValue == NULL)
6122 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6123 if (HeapFree (hHeap, 0, lpValueName) == 0)
6124 WARN ("HeapFree failed with code %i\n", GetLastError ());
6125 r = RegCloseKey (hkSubKey);
6126 if (r != ERROR_SUCCESS)
6127 WARN ("RegCloseKey returned %i\n", r);
6128 return ERROR_OUTOFMEMORY;
6131 TRACE ("pass 1: calculating buffer required for all names and values\n");
6133 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6135 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6137 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6139 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6140 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6141 NULL, NULL, lpValue, &cbValueLen);
6142 if (ret != ERROR_SUCCESS)
6144 if (HeapFree (hHeap, 0, lpValue) == 0)
6145 WARN ("HeapFree failed with code %i\n", GetLastError ());
6146 if (HeapFree (hHeap, 0, lpValueName) == 0)
6147 WARN ("HeapFree failed with code %i\n", GetLastError ());
6148 r = RegCloseKey (hkSubKey);
6149 if (r != ERROR_SUCCESS)
6150 WARN ("RegCloseKey returned %i\n", r);
6151 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6155 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6156 debugstr_w (lpValueName), dwIndex,
6157 cbValueNameLen + 1, cbValueLen);
6159 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6160 cbBufSize += cbValueLen;
6163 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6165 *pcbEnumValues = cbBufSize;
6166 *pnEnumValues = cValues;
6168 if (cbEnumValues < cbBufSize) /* buffer too small */
6170 if (HeapFree (hHeap, 0, lpValue) == 0)
6171 WARN ("HeapFree failed with code %i\n", GetLastError ());
6172 if (HeapFree (hHeap, 0, lpValueName) == 0)
6173 WARN ("HeapFree failed with code %i\n", GetLastError ());
6174 r = RegCloseKey (hkSubKey);
6175 if (r != ERROR_SUCCESS)
6176 WARN ("RegCloseKey returned %i\n", r);
6177 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6178 return ERROR_MORE_DATA;
6181 TRACE ("pass 2: copying all names and values to buffer\n");
6183 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6184 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6186 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6188 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6189 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6190 NULL, &dwType, lpValue, &cbValueLen);
6191 if (ret != ERROR_SUCCESS)
6193 if (HeapFree (hHeap, 0, lpValue) == 0)
6194 WARN ("HeapFree failed with code %i\n", GetLastError ());
6195 if (HeapFree (hHeap, 0, lpValueName) == 0)
6196 WARN ("HeapFree failed with code %i\n", GetLastError ());
6197 r = RegCloseKey (hkSubKey);
6198 if (r != ERROR_SUCCESS)
6199 WARN ("RegCloseKey returned %i\n", r);
6200 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6204 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6205 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6206 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6207 pEnumValues += cbValueNameLen;
6209 /* return # of *bytes* (including trailing \0), not # of chars */
6210 ppev[dwIndex].cbValueName = cbValueNameLen;
6212 ppev[dwIndex].dwType = dwType;
6214 memcpy (pEnumValues, lpValue, cbValueLen);
6215 ppev[dwIndex].pData = pEnumValues;
6216 pEnumValues += cbValueLen;
6218 ppev[dwIndex].cbData = cbValueLen;
6220 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6221 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6224 if (HeapFree (hHeap, 0, lpValue) == 0)
6226 ret = GetLastError ();
6227 ERR ("HeapFree failed with code %i\n", ret);
6228 if (HeapFree (hHeap, 0, lpValueName) == 0)
6229 WARN ("HeapFree failed with code %i\n", GetLastError ());
6230 r = RegCloseKey (hkSubKey);
6231 if (r != ERROR_SUCCESS)
6232 WARN ("RegCloseKey returned %i\n", r);
6236 if (HeapFree (hHeap, 0, lpValueName) == 0)
6238 ret = GetLastError ();
6239 ERR ("HeapFree failed with code %i\n", ret);
6240 r = RegCloseKey (hkSubKey);
6241 if (r != ERROR_SUCCESS)
6242 WARN ("RegCloseKey returned %i\n", r);
6246 ret = RegCloseKey (hkSubKey);
6247 if (ret != ERROR_SUCCESS)
6249 ERR ("RegCloseKey returned %i\n", ret);
6253 return ERROR_SUCCESS;
6256 /*******************************************************************************
6257 * EnumPrinterDataExA [WINSPOOL.@]
6259 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6260 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6261 * what Windows 2000 SP1 does.
6264 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6265 LPBYTE pEnumValues, DWORD cbEnumValues,
6266 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6270 DWORD ret, dwIndex, dwBufSize;
6274 TRACE ("%p %s\n", hPrinter, pKeyName);
6276 if (pKeyName == NULL || *pKeyName == 0)
6277 return ERROR_INVALID_PARAMETER;
6279 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6282 ret = GetLastError ();
6283 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6287 hHeap = GetProcessHeap ();
6290 ERR ("GetProcessHeap failed\n");
6291 return ERROR_OUTOFMEMORY;
6294 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6295 if (pKeyNameW == NULL)
6297 ERR ("Failed to allocate %i bytes from process heap\n",
6298 (LONG)(len * sizeof (WCHAR)));
6299 return ERROR_OUTOFMEMORY;
6302 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6304 ret = GetLastError ();
6305 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6306 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6307 WARN ("HeapFree failed with code %i\n", GetLastError ());
6311 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6312 pcbEnumValues, pnEnumValues);
6313 if (ret != ERROR_SUCCESS)
6315 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6316 WARN ("HeapFree failed with code %i\n", GetLastError ());
6317 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6321 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6323 ret = GetLastError ();
6324 ERR ("HeapFree failed with code %i\n", ret);
6328 if (*pnEnumValues == 0) /* empty key */
6329 return ERROR_SUCCESS;
6332 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6334 PPRINTER_ENUM_VALUESW ppev =
6335 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6337 if (dwBufSize < ppev->cbValueName)
6338 dwBufSize = ppev->cbValueName;
6340 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6341 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6342 dwBufSize = ppev->cbData;
6345 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6347 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6348 if (pBuffer == NULL)
6350 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6351 return ERROR_OUTOFMEMORY;
6354 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6356 PPRINTER_ENUM_VALUESW ppev =
6357 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6359 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6360 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6364 ret = GetLastError ();
6365 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6366 if (HeapFree (hHeap, 0, pBuffer) == 0)
6367 WARN ("HeapFree failed with code %i\n", GetLastError ());
6371 memcpy (ppev->pValueName, pBuffer, len);
6373 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6375 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6376 ppev->dwType != REG_MULTI_SZ)
6379 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6380 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6383 ret = GetLastError ();
6384 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6385 if (HeapFree (hHeap, 0, pBuffer) == 0)
6386 WARN ("HeapFree failed with code %i\n", GetLastError ());
6390 memcpy (ppev->pData, pBuffer, len);
6392 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6393 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6396 if (HeapFree (hHeap, 0, pBuffer) == 0)
6398 ret = GetLastError ();
6399 ERR ("HeapFree failed with code %i\n", ret);
6403 return ERROR_SUCCESS;
6406 /******************************************************************************
6407 * AbortPrinter (WINSPOOL.@)
6409 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6411 FIXME("(%p), stub!\n", hPrinter);
6415 /******************************************************************************
6416 * AddPortA (WINSPOOL.@)
6421 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6423 LPWSTR nameW = NULL;
6424 LPWSTR monitorW = NULL;
6428 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6431 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6432 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6433 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6437 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6438 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6439 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6441 res = AddPortW(nameW, hWnd, monitorW);
6442 HeapFree(GetProcessHeap(), 0, nameW);
6443 HeapFree(GetProcessHeap(), 0, monitorW);
6447 /******************************************************************************
6448 * AddPortW (WINSPOOL.@)
6450 * Add a Port for a specific Monitor
6453 * pName [I] Servername or NULL (local Computer)
6454 * hWnd [I] Handle to parent Window for the Dialog-Box
6455 * pMonitorName [I] Name of the Monitor that manage the Port
6462 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6464 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6466 if ((backend == NULL) && !load_backend()) return FALSE;
6468 if (!pMonitorName) {
6469 SetLastError(RPC_X_NULL_REF_POINTER);
6473 return backend->fpAddPort(pName, hWnd, pMonitorName);
6476 /******************************************************************************
6477 * AddPortExA (WINSPOOL.@)
6482 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6485 PORT_INFO_2A * pi2A;
6486 LPWSTR nameW = NULL;
6487 LPWSTR monitorW = NULL;
6491 pi2A = (PORT_INFO_2A *) pBuffer;
6493 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6494 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6496 if ((level < 1) || (level > 2)) {
6497 SetLastError(ERROR_INVALID_LEVEL);
6502 SetLastError(ERROR_INVALID_PARAMETER);
6507 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6508 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6509 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6513 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6514 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6515 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6518 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6520 if (pi2A->pPortName) {
6521 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6522 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6523 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6527 if (pi2A->pMonitorName) {
6528 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6529 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6530 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6533 if (pi2A->pDescription) {
6534 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6535 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6536 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6538 pi2W.fPortType = pi2A->fPortType;
6539 pi2W.Reserved = pi2A->Reserved;
6542 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6544 HeapFree(GetProcessHeap(), 0, nameW);
6545 HeapFree(GetProcessHeap(), 0, monitorW);
6546 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6547 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6548 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6553 /******************************************************************************
6554 * AddPortExW (WINSPOOL.@)
6556 * Add a Port for a specific Monitor, without presenting a user interface
6559 * pName [I] Servername or NULL (local Computer)
6560 * level [I] Structure-Level (1 or 2) for pBuffer
6561 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6562 * pMonitorName [I] Name of the Monitor that manage the Port
6569 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6573 pi2 = (PORT_INFO_2W *) pBuffer;
6575 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6576 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6577 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6578 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6580 if ((backend == NULL) && !load_backend()) return FALSE;
6582 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6583 SetLastError(ERROR_INVALID_PARAMETER);
6587 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6590 /******************************************************************************
6591 * AddPrinterConnectionA (WINSPOOL.@)
6593 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6595 FIXME("%s\n", debugstr_a(pName));
6599 /******************************************************************************
6600 * AddPrinterConnectionW (WINSPOOL.@)
6602 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6604 FIXME("%s\n", debugstr_w(pName));
6608 /******************************************************************************
6609 * AddPrinterDriverExW (WINSPOOL.@)
6611 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6614 * pName [I] Servername or NULL (local Computer)
6615 * level [I] Level for the supplied DRIVER_INFO_*W struct
6616 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6617 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6624 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6626 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6628 if ((backend == NULL) && !load_backend()) return FALSE;
6630 if (level < 2 || level == 5 || level == 7 || level > 8) {
6631 SetLastError(ERROR_INVALID_LEVEL);
6636 SetLastError(ERROR_INVALID_PARAMETER);
6640 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6643 /******************************************************************************
6644 * AddPrinterDriverExA (WINSPOOL.@)
6646 * See AddPrinterDriverExW.
6649 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6651 DRIVER_INFO_8A *diA;
6653 LPWSTR nameW = NULL;
6658 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6660 diA = (DRIVER_INFO_8A *) pDriverInfo;
6661 ZeroMemory(&diW, sizeof(diW));
6663 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6664 SetLastError(ERROR_INVALID_LEVEL);
6669 SetLastError(ERROR_INVALID_PARAMETER);
6673 /* convert servername to unicode */
6675 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6676 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6677 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6681 diW.cVersion = diA->cVersion;
6684 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6685 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6686 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6689 if (diA->pEnvironment) {
6690 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6691 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6692 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6695 if (diA->pDriverPath) {
6696 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6697 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6698 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6701 if (diA->pDataFile) {
6702 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6703 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6704 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6707 if (diA->pConfigFile) {
6708 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6709 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6710 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6713 if ((Level > 2) && diA->pDependentFiles) {
6714 lenA = multi_sz_lenA(diA->pDependentFiles);
6715 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6716 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6717 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6720 if ((Level > 2) && diA->pMonitorName) {
6721 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6722 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6723 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6726 if ((Level > 3) && diA->pDefaultDataType) {
6727 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6728 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6729 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6732 if ((Level > 3) && diA->pszzPreviousNames) {
6733 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6734 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6735 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6736 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6739 if ((Level > 5) && diA->pszMfgName) {
6740 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6741 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6742 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6745 if ((Level > 5) && diA->pszOEMUrl) {
6746 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6747 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6748 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6751 if ((Level > 5) && diA->pszHardwareID) {
6752 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6753 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6754 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6757 if ((Level > 5) && diA->pszProvider) {
6758 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6759 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6760 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6764 FIXME("level %u is incomplete\n", Level);
6767 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6768 TRACE("got %u with %u\n", res, GetLastError());
6769 HeapFree(GetProcessHeap(), 0, nameW);
6770 HeapFree(GetProcessHeap(), 0, diW.pName);
6771 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6772 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6773 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6774 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6775 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6776 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6777 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6778 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6779 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6780 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6781 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6782 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6784 TRACE("=> %u with %u\n", res, GetLastError());
6788 /******************************************************************************
6789 * ConfigurePortA (WINSPOOL.@)
6791 * See ConfigurePortW.
6794 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6796 LPWSTR nameW = NULL;
6797 LPWSTR portW = NULL;
6801 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6803 /* convert servername to unicode */
6805 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6806 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6807 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6810 /* convert portname to unicode */
6812 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6813 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6814 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6817 res = ConfigurePortW(nameW, hWnd, portW);
6818 HeapFree(GetProcessHeap(), 0, nameW);
6819 HeapFree(GetProcessHeap(), 0, portW);
6823 /******************************************************************************
6824 * ConfigurePortW (WINSPOOL.@)
6826 * Display the Configuration-Dialog for a specific Port
6829 * pName [I] Servername or NULL (local Computer)
6830 * hWnd [I] Handle to parent Window for the Dialog-Box
6831 * pPortName [I] Name of the Port, that should be configured
6838 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6841 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6843 if ((backend == NULL) && !load_backend()) return FALSE;
6846 SetLastError(RPC_X_NULL_REF_POINTER);
6850 return backend->fpConfigurePort(pName, hWnd, pPortName);
6853 /******************************************************************************
6854 * ConnectToPrinterDlg (WINSPOOL.@)
6856 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6858 FIXME("%p %x\n", hWnd, Flags);
6862 /******************************************************************************
6863 * DeletePrinterConnectionA (WINSPOOL.@)
6865 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6867 FIXME("%s\n", debugstr_a(pName));
6871 /******************************************************************************
6872 * DeletePrinterConnectionW (WINSPOOL.@)
6874 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6876 FIXME("%s\n", debugstr_w(pName));
6880 /******************************************************************************
6881 * DeletePrinterDriverExW (WINSPOOL.@)
6883 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6884 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6889 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6890 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6892 if(pName && pName[0])
6894 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6895 SetLastError(ERROR_INVALID_PARAMETER);
6901 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6902 SetLastError(ERROR_INVALID_PARAMETER);
6906 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6910 ERR("Can't open drivers key\n");
6914 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6917 RegCloseKey(hkey_drivers);
6922 /******************************************************************************
6923 * DeletePrinterDriverExA (WINSPOOL.@)
6925 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6926 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6928 UNICODE_STRING NameW, EnvW, DriverW;
6931 asciitounicode(&NameW, pName);
6932 asciitounicode(&EnvW, pEnvironment);
6933 asciitounicode(&DriverW, pDriverName);
6935 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6937 RtlFreeUnicodeString(&DriverW);
6938 RtlFreeUnicodeString(&EnvW);
6939 RtlFreeUnicodeString(&NameW);
6944 /******************************************************************************
6945 * DeletePrinterDataExW (WINSPOOL.@)
6947 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6950 FIXME("%p %s %s\n", hPrinter,
6951 debugstr_w(pKeyName), debugstr_w(pValueName));
6952 return ERROR_INVALID_PARAMETER;
6955 /******************************************************************************
6956 * DeletePrinterDataExA (WINSPOOL.@)
6958 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6961 FIXME("%p %s %s\n", hPrinter,
6962 debugstr_a(pKeyName), debugstr_a(pValueName));
6963 return ERROR_INVALID_PARAMETER;
6966 /******************************************************************************
6967 * DeletePrintProcessorA (WINSPOOL.@)
6969 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6971 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6972 debugstr_a(pPrintProcessorName));
6976 /******************************************************************************
6977 * DeletePrintProcessorW (WINSPOOL.@)
6979 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6981 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6982 debugstr_w(pPrintProcessorName));
6986 /******************************************************************************
6987 * DeletePrintProvidorA (WINSPOOL.@)
6989 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6991 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6992 debugstr_a(pPrintProviderName));
6996 /******************************************************************************
6997 * DeletePrintProvidorW (WINSPOOL.@)
6999 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7001 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7002 debugstr_w(pPrintProviderName));
7006 /******************************************************************************
7007 * EnumFormsA (WINSPOOL.@)
7009 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7010 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7012 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7013 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7017 /******************************************************************************
7018 * EnumFormsW (WINSPOOL.@)
7020 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7021 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7023 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7024 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7028 /*****************************************************************************
7029 * EnumMonitorsA [WINSPOOL.@]
7031 * See EnumMonitorsW.
7034 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7035 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7038 LPBYTE bufferW = NULL;
7039 LPWSTR nameW = NULL;
7041 DWORD numentries = 0;
7044 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7045 cbBuf, pcbNeeded, pcReturned);
7047 /* convert servername to unicode */
7049 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7050 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7051 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7053 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7054 needed = cbBuf * sizeof(WCHAR);
7055 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7056 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7058 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7059 if (pcbNeeded) needed = *pcbNeeded;
7060 /* HeapReAlloc return NULL, when bufferW was NULL */
7061 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7062 HeapAlloc(GetProcessHeap(), 0, needed);
7064 /* Try again with the large Buffer */
7065 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7067 numentries = pcReturned ? *pcReturned : 0;
7070 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7071 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7074 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7075 DWORD entrysize = 0;
7078 LPMONITOR_INFO_2W mi2w;
7079 LPMONITOR_INFO_2A mi2a;
7081 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7082 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7084 /* First pass: calculate the size for all Entries */
7085 mi2w = (LPMONITOR_INFO_2W) bufferW;
7086 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7088 while (index < numentries) {
7090 needed += entrysize; /* MONITOR_INFO_?A */
7091 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7093 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7094 NULL, 0, NULL, NULL);
7096 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7097 NULL, 0, NULL, NULL);
7098 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7099 NULL, 0, NULL, NULL);
7101 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7102 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7103 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7106 /* check for errors and quit on failure */
7107 if (cbBuf < needed) {
7108 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7112 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7113 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7114 cbBuf -= len ; /* free Bytes in the user-Buffer */
7115 mi2w = (LPMONITOR_INFO_2W) bufferW;
7116 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7118 /* Second Pass: Fill the User Buffer (if we have one) */
7119 while ((index < numentries) && pMonitors) {
7121 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7123 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7124 ptr, cbBuf , NULL, NULL);
7128 mi2a->pEnvironment = ptr;
7129 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7130 ptr, cbBuf, NULL, NULL);
7134 mi2a->pDLLName = ptr;
7135 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7136 ptr, cbBuf, NULL, NULL);
7140 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7141 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7142 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7146 if (pcbNeeded) *pcbNeeded = needed;
7147 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7149 HeapFree(GetProcessHeap(), 0, nameW);
7150 HeapFree(GetProcessHeap(), 0, bufferW);
7152 TRACE("returning %d with %d (%d byte for %d entries)\n",
7153 (res), GetLastError(), needed, numentries);
7159 /*****************************************************************************
7160 * EnumMonitorsW [WINSPOOL.@]
7162 * Enumerate available Port-Monitors
7165 * pName [I] Servername or NULL (local Computer)
7166 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7167 * pMonitors [O] PTR to Buffer that receives the Result
7168 * cbBuf [I] Size of Buffer at pMonitors
7169 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7170 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7174 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7177 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7178 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7181 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7182 cbBuf, pcbNeeded, pcReturned);
7184 if ((backend == NULL) && !load_backend()) return FALSE;
7186 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7187 SetLastError(RPC_X_NULL_REF_POINTER);
7191 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7194 /******************************************************************************
7195 * SpoolerInit (WINSPOOL.@)
7197 * Initialize the Spooler
7204 * The function fails on windows, when the spooler service is not running
7207 BOOL WINAPI SpoolerInit(void)
7210 if ((backend == NULL) && !load_backend()) return FALSE;
7214 /******************************************************************************
7215 * XcvDataW (WINSPOOL.@)
7217 * Execute commands in the Printmonitor DLL
7220 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7221 * pszDataName [i] Name of the command to execute
7222 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7223 * cbInputData [i] Size in Bytes of Buffer at pInputData
7224 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7225 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7226 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7227 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7234 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7235 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7237 * Minimal List of commands, that a Printmonitor DLL should support:
7239 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7240 *| "AddPort" : Add a Port
7241 *| "DeletePort": Delete a Port
7243 * Many Printmonitors support additional commands. Examples for localspl.dll:
7244 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7245 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7248 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7249 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7250 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7252 opened_printer_t *printer;
7254 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7255 pInputData, cbInputData, pOutputData,
7256 cbOutputData, pcbOutputNeeded, pdwStatus);
7258 if ((backend == NULL) && !load_backend()) return FALSE;
7260 printer = get_opened_printer(hXcv);
7261 if (!printer || (!printer->backend_printer)) {
7262 SetLastError(ERROR_INVALID_HANDLE);
7266 if (!pcbOutputNeeded) {
7267 SetLastError(ERROR_INVALID_PARAMETER);
7271 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7272 SetLastError(RPC_X_NULL_REF_POINTER);
7276 *pcbOutputNeeded = 0;
7278 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7279 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7283 /*****************************************************************************
7284 * EnumPrinterDataA [WINSPOOL.@]
7287 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7288 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7289 DWORD cbData, LPDWORD pcbData )
7291 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7292 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7293 return ERROR_NO_MORE_ITEMS;
7296 /*****************************************************************************
7297 * EnumPrinterDataW [WINSPOOL.@]
7300 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7301 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7302 DWORD cbData, LPDWORD pcbData )
7304 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7305 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7306 return ERROR_NO_MORE_ITEMS;
7309 /*****************************************************************************
7310 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7313 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7314 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7315 LPDWORD pcbNeeded, LPDWORD pcReturned)
7317 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7318 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7319 pcbNeeded, pcReturned);
7323 /*****************************************************************************
7324 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7327 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7328 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7329 LPDWORD pcbNeeded, LPDWORD pcReturned)
7331 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7332 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7333 pcbNeeded, pcReturned);
7337 /*****************************************************************************
7338 * EnumPrintProcessorsA [WINSPOOL.@]
7340 * See EnumPrintProcessorsW.
7343 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7344 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7347 LPBYTE bufferW = NULL;
7348 LPWSTR nameW = NULL;
7351 DWORD numentries = 0;
7354 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7355 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7357 /* convert names to unicode */
7359 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7360 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7361 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7364 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7365 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7366 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7369 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7370 needed = cbBuf * sizeof(WCHAR);
7371 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7372 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7374 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7375 if (pcbNeeded) needed = *pcbNeeded;
7376 /* HeapReAlloc return NULL, when bufferW was NULL */
7377 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7378 HeapAlloc(GetProcessHeap(), 0, needed);
7380 /* Try again with the large Buffer */
7381 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7383 numentries = pcReturned ? *pcReturned : 0;
7387 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7390 PPRINTPROCESSOR_INFO_1W ppiw;
7391 PPRINTPROCESSOR_INFO_1A ppia;
7393 /* First pass: calculate the size for all Entries */
7394 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7395 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7397 while (index < numentries) {
7399 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7400 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7402 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7403 NULL, 0, NULL, NULL);
7405 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7406 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7409 /* check for errors and quit on failure */
7410 if (cbBuf < needed) {
7411 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7416 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7417 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7418 cbBuf -= len ; /* free Bytes in the user-Buffer */
7419 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7420 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7422 /* Second Pass: Fill the User Buffer (if we have one) */
7423 while ((index < numentries) && pPPInfo) {
7425 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7427 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7428 ptr, cbBuf , NULL, NULL);
7432 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7433 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7438 if (pcbNeeded) *pcbNeeded = needed;
7439 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7441 HeapFree(GetProcessHeap(), 0, nameW);
7442 HeapFree(GetProcessHeap(), 0, envW);
7443 HeapFree(GetProcessHeap(), 0, bufferW);
7445 TRACE("returning %d with %d (%d byte for %d entries)\n",
7446 (res), GetLastError(), needed, numentries);
7451 /*****************************************************************************
7452 * EnumPrintProcessorsW [WINSPOOL.@]
7454 * Enumerate available Print Processors
7457 * pName [I] Servername or NULL (local Computer)
7458 * pEnvironment [I] Printing-Environment or NULL (Default)
7459 * Level [I] Structure-Level (Only 1 is allowed)
7460 * pPPInfo [O] PTR to Buffer that receives the Result
7461 * cbBuf [I] Size of Buffer at pPPInfo
7462 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7463 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7467 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7470 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7471 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7474 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7475 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7477 if ((backend == NULL) && !load_backend()) return FALSE;
7479 if (!pcbNeeded || !pcReturned) {
7480 SetLastError(RPC_X_NULL_REF_POINTER);
7484 if (!pPPInfo && (cbBuf > 0)) {
7485 SetLastError(ERROR_INVALID_USER_BUFFER);
7489 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7490 cbBuf, pcbNeeded, pcReturned);
7493 /*****************************************************************************
7494 * ExtDeviceMode [WINSPOOL.@]
7497 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7498 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7501 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7502 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7503 debugstr_a(pProfile), fMode);
7507 /*****************************************************************************
7508 * FindClosePrinterChangeNotification [WINSPOOL.@]
7511 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7513 FIXME("Stub: %p\n", hChange);
7517 /*****************************************************************************
7518 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7521 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7522 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7524 FIXME("Stub: %p %x %x %p\n",
7525 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7526 return INVALID_HANDLE_VALUE;
7529 /*****************************************************************************
7530 * FindNextPrinterChangeNotification [WINSPOOL.@]
7533 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7534 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7536 FIXME("Stub: %p %p %p %p\n",
7537 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7541 /*****************************************************************************
7542 * FreePrinterNotifyInfo [WINSPOOL.@]
7545 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7547 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7551 /*****************************************************************************
7554 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7555 * ansi depending on the unicode parameter.
7557 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7567 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7570 memcpy(ptr, str, *size);
7577 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7580 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7587 /*****************************************************************************
7590 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7591 LPDWORD pcbNeeded, BOOL unicode)
7593 DWORD size, left = cbBuf;
7594 BOOL space = (cbBuf > 0);
7601 ji1->JobId = job->job_id;
7604 string_to_buf(job->document_title, ptr, left, &size, unicode);
7605 if(space && size <= left)
7607 ji1->pDocument = (LPWSTR)ptr;
7615 if (job->printer_name)
7617 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7618 if(space && size <= left)
7620 ji1->pPrinterName = (LPWSTR)ptr;
7632 /*****************************************************************************
7635 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7636 LPDWORD pcbNeeded, BOOL unicode)
7638 DWORD size, left = cbBuf;
7640 BOOL space = (cbBuf > 0);
7642 LPDEVMODEA dmA = NULL;
7649 ji2->JobId = job->job_id;
7652 string_to_buf(job->document_title, ptr, left, &size, unicode);
7653 if(space && size <= left)
7655 ji2->pDocument = (LPWSTR)ptr;
7663 if (job->printer_name)
7665 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7666 if(space && size <= left)
7668 ji2->pPrinterName = (LPWSTR)ptr;
7681 dmA = DEVMODEdupWtoA(job->devmode);
7682 devmode = (LPDEVMODEW) dmA;
7683 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7687 devmode = job->devmode;
7688 size = devmode->dmSize + devmode->dmDriverExtra;
7692 FIXME("Can't convert DEVMODE W to A\n");
7695 /* align DEVMODE to a DWORD boundary */
7696 shift = (4 - (*pcbNeeded & 3)) & 3;
7702 memcpy(ptr, devmode, size-shift);
7703 ji2->pDevMode = (LPDEVMODEW)ptr;
7704 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7717 /*****************************************************************************
7720 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7721 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7724 DWORD needed = 0, size;
7728 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7730 EnterCriticalSection(&printer_handles_cs);
7731 job = get_job(hPrinter, JobId);
7738 size = sizeof(JOB_INFO_1W);
7743 memset(pJob, 0, size);
7747 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7752 size = sizeof(JOB_INFO_2W);
7757 memset(pJob, 0, size);
7761 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7766 size = sizeof(JOB_INFO_3);
7770 memset(pJob, 0, size);
7779 SetLastError(ERROR_INVALID_LEVEL);
7783 *pcbNeeded = needed;
7785 LeaveCriticalSection(&printer_handles_cs);
7789 /*****************************************************************************
7790 * GetJobA [WINSPOOL.@]
7793 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7794 DWORD cbBuf, LPDWORD pcbNeeded)
7796 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7799 /*****************************************************************************
7800 * GetJobW [WINSPOOL.@]
7803 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7804 DWORD cbBuf, LPDWORD pcbNeeded)
7806 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7809 /*****************************************************************************
7812 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7815 char *unixname, *cmdA;
7817 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7823 if(!(unixname = wine_get_unix_file_name(filename)))
7826 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7827 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7828 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7830 TRACE("printing with: %s\n", cmdA);
7832 if((file_fd = open(unixname, O_RDONLY)) == -1)
7837 ERR("pipe() failed!\n");
7841 if ((pid = fork()) == 0)
7847 /* reset signals that we previously set to SIG_IGN */
7848 signal(SIGPIPE, SIG_DFL);
7850 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7855 ERR("fork() failed!\n");
7859 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7860 write(fds[1], buf, no_read);
7867 wret = waitpid(pid, &status, 0);
7868 } while (wret < 0 && errno == EINTR);
7871 ERR("waitpid() failed!\n");
7874 if (!WIFEXITED(status) || WEXITSTATUS(status))
7876 ERR("child process failed! %d\n", status);
7883 if(file_fd != -1) close(file_fd);
7884 if(fds[0] != -1) close(fds[0]);
7885 if(fds[1] != -1) close(fds[1]);
7887 HeapFree(GetProcessHeap(), 0, cmdA);
7888 HeapFree(GetProcessHeap(), 0, unixname);
7895 /*****************************************************************************
7898 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7901 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7904 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7905 sprintfW(cmd, fmtW, printer_name);
7907 r = schedule_pipe(cmd, filename);
7909 HeapFree(GetProcessHeap(), 0, cmd);
7913 #ifdef SONAME_LIBCUPS
7914 /*****************************************************************************
7915 * get_cups_jobs_ticket_options
7917 * Explicitly set CUPS options based on any %cupsJobTicket lines.
7918 * The CUPS scheduler only looks for these in Print-File requests, and since
7919 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
7922 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
7924 FILE *fp = fopen( file, "r" );
7925 char buf[257]; /* DSC max of 256 + '\0' */
7926 const char *ps_adobe = "%!PS-Adobe-";
7927 const char *cups_job = "%cupsJobTicket:";
7929 if (!fp) return num_options;
7930 if (!fgets( buf, sizeof(buf), fp )) goto end;
7931 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
7932 while (fgets( buf, sizeof(buf), fp ))
7934 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
7935 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
7944 /*****************************************************************************
7947 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7949 #ifdef SONAME_LIBCUPS
7952 char *unixname, *queue, *unix_doc_title;
7955 int num_options = 0, i;
7956 cups_option_t *options = NULL;
7958 if(!(unixname = wine_get_unix_file_name(filename)))
7961 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7962 queue = HeapAlloc(GetProcessHeap(), 0, len);
7963 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7965 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7966 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7967 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7969 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
7971 TRACE( "printing via cups with options:\n" );
7972 for (i = 0; i < num_options; i++)
7973 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
7975 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
7977 pcupsFreeOptions( num_options, options );
7979 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7980 HeapFree(GetProcessHeap(), 0, queue);
7981 HeapFree(GetProcessHeap(), 0, unixname);
7987 return schedule_lpr(printer_name, filename);
7991 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7998 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8002 if(HIWORD(wparam) == BN_CLICKED)
8004 if(LOWORD(wparam) == IDOK)
8007 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8010 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8011 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8013 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8015 WCHAR caption[200], message[200];
8018 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8019 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8020 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8021 if(mb_ret == IDCANCEL)
8023 HeapFree(GetProcessHeap(), 0, filename);
8027 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8028 if(hf == INVALID_HANDLE_VALUE)
8030 WCHAR caption[200], message[200];
8032 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8033 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8034 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8035 HeapFree(GetProcessHeap(), 0, filename);
8039 DeleteFileW(filename);
8040 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8042 EndDialog(hwnd, IDOK);
8045 if(LOWORD(wparam) == IDCANCEL)
8047 EndDialog(hwnd, IDCANCEL);
8056 /*****************************************************************************
8059 static BOOL get_filename(LPWSTR *filename)
8061 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8062 file_dlg_proc, (LPARAM)filename) == IDOK;
8065 /*****************************************************************************
8068 static BOOL schedule_file(LPCWSTR filename)
8070 LPWSTR output = NULL;
8072 if(get_filename(&output))
8075 TRACE("copy to %s\n", debugstr_w(output));
8076 r = CopyFileW(filename, output, FALSE);
8077 HeapFree(GetProcessHeap(), 0, output);
8083 /*****************************************************************************
8086 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8088 int in_fd, out_fd, no_read;
8091 char *unixname, *outputA;
8094 if(!(unixname = wine_get_unix_file_name(filename)))
8097 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8098 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8099 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8101 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8102 in_fd = open(unixname, O_RDONLY);
8103 if(out_fd == -1 || in_fd == -1)
8106 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8107 write(out_fd, buf, no_read);
8111 if(in_fd != -1) close(in_fd);
8112 if(out_fd != -1) close(out_fd);
8113 HeapFree(GetProcessHeap(), 0, outputA);
8114 HeapFree(GetProcessHeap(), 0, unixname);
8118 /*****************************************************************************
8119 * ScheduleJob [WINSPOOL.@]
8122 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8124 opened_printer_t *printer;
8126 struct list *cursor, *cursor2;
8128 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8129 EnterCriticalSection(&printer_handles_cs);
8130 printer = get_opened_printer(hPrinter);
8134 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8136 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8139 if(job->job_id != dwJobID) continue;
8141 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8142 if(hf != INVALID_HANDLE_VALUE)
8144 PRINTER_INFO_5W *pi5 = NULL;
8145 LPWSTR portname = job->portname;
8149 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8150 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8154 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8155 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8156 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8157 portname = pi5->pPortName;
8159 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8160 debugstr_w(portname));
8164 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8165 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8167 DWORD type, count = sizeof(output);
8168 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8171 if(output[0] == '|')
8173 ret = schedule_pipe(output + 1, job->filename);
8177 ret = schedule_unixfile(output, job->filename);
8179 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8181 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8183 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8185 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8187 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8189 ret = schedule_file(job->filename);
8193 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8195 HeapFree(GetProcessHeap(), 0, pi5);
8197 DeleteFileW(job->filename);
8199 list_remove(cursor);
8200 HeapFree(GetProcessHeap(), 0, job->document_title);
8201 HeapFree(GetProcessHeap(), 0, job->printer_name);
8202 HeapFree(GetProcessHeap(), 0, job->portname);
8203 HeapFree(GetProcessHeap(), 0, job->filename);
8204 HeapFree(GetProcessHeap(), 0, job->devmode);
8205 HeapFree(GetProcessHeap(), 0, job);
8209 LeaveCriticalSection(&printer_handles_cs);
8213 /*****************************************************************************
8214 * StartDocDlgA [WINSPOOL.@]
8216 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8218 UNICODE_STRING usBuffer;
8221 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8224 docW.cbSize = sizeof(docW);
8225 if (doc->lpszDocName)
8227 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8228 if (!(docW.lpszDocName = docnameW)) return NULL;
8230 if (doc->lpszOutput)
8232 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8233 if (!(docW.lpszOutput = outputW)) return NULL;
8235 if (doc->lpszDatatype)
8237 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8238 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8240 docW.fwType = doc->fwType;
8242 retW = StartDocDlgW(hPrinter, &docW);
8246 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8247 ret = HeapAlloc(GetProcessHeap(), 0, len);
8248 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8249 HeapFree(GetProcessHeap(), 0, retW);
8252 HeapFree(GetProcessHeap(), 0, datatypeW);
8253 HeapFree(GetProcessHeap(), 0, outputW);
8254 HeapFree(GetProcessHeap(), 0, docnameW);
8259 /*****************************************************************************
8260 * StartDocDlgW [WINSPOOL.@]
8262 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8263 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8264 * port is "FILE:". Also returns the full path if passed a relative path.
8266 * The caller should free the returned string from the process heap.
8268 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8273 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8275 PRINTER_INFO_5W *pi5;
8276 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8277 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8279 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8280 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8281 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8283 HeapFree(GetProcessHeap(), 0, pi5);
8286 HeapFree(GetProcessHeap(), 0, pi5);
8289 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8293 if (get_filename(&name))
8295 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8297 HeapFree(GetProcessHeap(), 0, name);
8300 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8301 GetFullPathNameW(name, len, ret, NULL);
8302 HeapFree(GetProcessHeap(), 0, name);
8307 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8310 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8311 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8313 attr = GetFileAttributesW(ret);
8314 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8316 HeapFree(GetProcessHeap(), 0, ret);