winspool.drv: Remove unused strings (Clang).
[wine.git] / dlls / winspool.drv / info.c
blob073a8fbd37a88974b384c6376d00eaaf1ae37109
1 /*
2 * WINSPOOL functions
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
27 #include "config.h"
28 #include "wine/port.h"
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <stddef.h>
36 #include <errno.h>
37 #ifdef HAVE_SYS_WAIT_H
38 #include <sys/wait.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif
43 #include <signal.h>
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
46 #endif
48 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
49 #define GetCurrentProcess GetCurrentProcess_Mac
50 #define GetCurrentThread GetCurrentThread_Mac
51 #define LoadResource LoadResource_Mac
52 #define AnimatePalette AnimatePalette_Mac
53 #define EqualRgn EqualRgn_Mac
54 #define FillRgn FillRgn_Mac
55 #define FrameRgn FrameRgn_Mac
56 #define GetPixel GetPixel_Mac
57 #define InvertRgn InvertRgn_Mac
58 #define LineTo LineTo_Mac
59 #define OffsetRgn OffsetRgn_Mac
60 #define PaintRgn PaintRgn_Mac
61 #define Polygon Polygon_Mac
62 #define ResizePalette ResizePalette_Mac
63 #define SetRectRgn SetRectRgn_Mac
64 #define EqualRect EqualRect_Mac
65 #define FillRect FillRect_Mac
66 #define FrameRect FrameRect_Mac
67 #define GetCursor GetCursor_Mac
68 #define InvertRect InvertRect_Mac
69 #define OffsetRect OffsetRect_Mac
70 #define PtInRect PtInRect_Mac
71 #define SetCursor SetCursor_Mac
72 #define SetRect SetRect_Mac
73 #define ShowCursor ShowCursor_Mac
74 #define UnionRect UnionRect_Mac
75 #include <ApplicationServices/ApplicationServices.h>
76 #undef GetCurrentProcess
77 #undef GetCurrentThread
78 #undef LoadResource
79 #undef AnimatePalette
80 #undef EqualRgn
81 #undef FillRgn
82 #undef FrameRgn
83 #undef GetPixel
84 #undef InvertRgn
85 #undef LineTo
86 #undef OffsetRgn
87 #undef PaintRgn
88 #undef Polygon
89 #undef ResizePalette
90 #undef SetRectRgn
91 #undef EqualRect
92 #undef FillRect
93 #undef FrameRect
94 #undef GetCursor
95 #undef InvertRect
96 #undef OffsetRect
97 #undef PtInRect
98 #undef SetCursor
99 #undef SetRect
100 #undef ShowCursor
101 #undef UnionRect
102 #undef DPRINTF
103 #endif
105 #define NONAMELESSUNION
106 #define NONAMELESSSTRUCT
107 #include "wine/library.h"
108 #include "windef.h"
109 #include "winbase.h"
110 #include "winuser.h"
111 #include "winerror.h"
112 #include "winreg.h"
113 #include "wingdi.h"
114 #include "winspool.h"
115 #include "winternl.h"
116 #include "wine/windef16.h"
117 #include "wine/unicode.h"
118 #include "wine/debug.h"
119 #include "wine/list.h"
120 #include "winnls.h"
122 #include "ddk/winsplp.h"
123 #include "wspool.h"
125 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
127 /* ############################### */
129 static CRITICAL_SECTION printer_handles_cs;
130 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
132 0, 0, &printer_handles_cs,
133 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
134 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
136 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
138 /* ############################### */
140 typedef struct {
141 DWORD job_id;
142 HANDLE hf;
143 } started_doc_t;
145 typedef struct {
146 struct list jobs;
147 LONG ref;
148 } jobqueue_t;
150 typedef struct {
151 LPWSTR name;
152 LPWSTR printername;
153 HANDLE backend_printer;
154 jobqueue_t *queue;
155 started_doc_t *doc;
156 DEVMODEW *devmode;
157 } opened_printer_t;
159 typedef struct {
160 struct list entry;
161 DWORD job_id;
162 WCHAR *filename;
163 WCHAR *portname;
164 WCHAR *document_title;
165 WCHAR *printer_name;
166 LPDEVMODEW devmode;
167 } job_t;
170 typedef struct {
171 LPCWSTR envname;
172 LPCWSTR subdir;
173 DWORD driverversion;
174 LPCWSTR versionregpath;
175 LPCWSTR versionsubdir;
176 } printenv_t;
178 /* ############################### */
180 static opened_printer_t **printer_handles;
181 static UINT nb_printer_handles;
182 static LONG next_job_id = 1;
184 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
185 WORD fwCapability, LPSTR lpszOutput,
186 LPDEVMODEA lpdm );
187 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
188 LPSTR lpszDevice, LPSTR lpszPort,
189 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
190 DWORD fwMode );
192 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
193 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
194 'c','o','n','t','r','o','l','\\',
195 'P','r','i','n','t','\\',
196 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
197 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
199 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
200 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
201 'C','o','n','t','r','o','l','\\',
202 'P','r','i','n','t','\\',
203 'P','r','i','n','t','e','r','s',0};
205 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
206 'M','i','c','r','o','s','o','f','t','\\',
207 'W','i','n','d','o','w','s',' ','N','T','\\',
208 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
209 'W','i','n','d','o','w','s',0};
211 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
212 'M','i','c','r','o','s','o','f','t','\\',
213 'W','i','n','d','o','w','s',' ','N','T','\\',
214 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
215 'D','e','v','i','c','e','s',0};
217 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
218 'M','i','c','r','o','s','o','f','t','\\',
219 'W','i','n','d','o','w','s',' ','N','T','\\',
220 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
221 'P','r','i','n','t','e','r','P','o','r','t','s',0};
223 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
224 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
225 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
226 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
227 static const WCHAR subdir_x64W[] = {'x','6','4',0};
228 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
229 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
230 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
231 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
232 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
234 static const WCHAR AttributesW[] = {'A','t','t','r','i','b','u','t','e','s',0};
235 static const WCHAR backslashW[] = {'\\',0};
236 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
237 'i','o','n',' ','F','i','l','e',0};
238 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
239 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
240 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
241 static const WCHAR Default_PriorityW[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
242 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
243 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
244 static const WCHAR dnsTimeoutW[] = {'d','n','s','T','i','m','e','o','u','t',0};
245 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
246 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
247 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
248 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
249 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
250 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
251 static const WCHAR NameW[] = {'N','a','m','e',0};
252 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
253 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
254 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
255 static const WCHAR PortW[] = {'P','o','r','t',0};
256 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
257 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
258 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
259 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
260 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
261 static const WCHAR PriorityW[] = {'P','r','i','o','r','i','t','y',0};
262 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
263 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
264 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
265 static const WCHAR StartTimeW[] = {'S','t','a','r','t','T','i','m','e',0};
266 static const WCHAR StatusW[] = {'S','t','a','t','u','s',0};
267 static const WCHAR txTimeoutW[] = {'t','x','T','i','m','e','o','u','t',0};
268 static const WCHAR UntilTimeW[] = {'U','n','t','i','l','T','i','m','e',0};
269 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
270 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
271 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
272 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
273 static WCHAR rawW[] = {'R','A','W',0};
274 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
275 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
276 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
277 static const WCHAR commaW[] = {',',0};
278 static WCHAR emptyStringW[] = {0};
280 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
282 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
283 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
284 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
286 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
287 'D','o','c','u','m','e','n','t',0};
289 static const WCHAR PPD_Overrides[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
290 static const WCHAR DefaultPageSize[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
292 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
293 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
294 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
295 0, sizeof(DRIVER_INFO_8W)};
298 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
299 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
300 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
301 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
302 sizeof(PRINTER_INFO_9W)};
304 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
305 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
306 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
308 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
310 /******************************************************************
311 * validate the user-supplied printing-environment [internal]
313 * PARAMS
314 * env [I] PTR to Environment-String or NULL
316 * RETURNS
317 * Failure: NULL
318 * Success: PTR to printenv_t
320 * NOTES
321 * An empty string is handled the same way as NULL.
322 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
326 static const printenv_t * validate_envW(LPCWSTR env)
328 const printenv_t *result = NULL;
329 unsigned int i;
331 TRACE("testing %s\n", debugstr_w(env));
332 if (env && env[0])
334 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
336 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
338 result = all_printenv[i];
339 break;
343 if (result == NULL) {
344 FIXME("unsupported Environment: %s\n", debugstr_w(env));
345 SetLastError(ERROR_INVALID_ENVIRONMENT);
347 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
349 else
351 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
353 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
355 return result;
359 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
360 if passed a NULL string. This returns NULLs to the result.
362 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
364 if ( (src) )
366 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
367 return usBufferPtr->Buffer;
369 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
370 return NULL;
373 static LPWSTR strdupW(LPCWSTR p)
375 LPWSTR ret;
376 DWORD len;
378 if(!p) return NULL;
379 len = (strlenW(p) + 1) * sizeof(WCHAR);
380 ret = HeapAlloc(GetProcessHeap(), 0, len);
381 memcpy(ret, p, len);
382 return ret;
385 static LPSTR strdupWtoA( LPCWSTR str )
387 LPSTR ret;
388 INT len;
390 if (!str) return NULL;
391 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
392 ret = HeapAlloc( GetProcessHeap(), 0, len );
393 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
394 return ret;
397 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
399 DEVMODEW *ret;
401 if (!dm) return NULL;
402 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
403 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
404 return ret;
407 /***********************************************************
408 * DEVMODEdupWtoA
409 * Creates an ansi copy of supplied devmode
411 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
413 LPDEVMODEA dmA;
414 DWORD size;
416 if (!dmW) return NULL;
417 size = dmW->dmSize - CCHDEVICENAME -
418 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
420 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
421 if (!dmA) return NULL;
423 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
424 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
426 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
428 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
429 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
431 else
433 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
434 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
435 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
436 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
438 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
441 dmA->dmSize = size;
442 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
443 return dmA;
447 /******************************************************************
448 * verify, that the filename is a local file
451 static inline BOOL is_local_file(LPWSTR name)
453 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
456 /* ################################ */
458 static int multi_sz_lenA(const char *str)
460 const char *ptr = str;
461 if(!str) return 0;
464 ptr += lstrlenA(ptr) + 1;
465 } while(*ptr);
467 return ptr - str + 1;
470 /*****************************************************************************
471 * get_dword_from_reg
473 * Return DWORD associated with name from hkey.
475 static DWORD get_dword_from_reg( HKEY hkey, const WCHAR *name )
477 DWORD sz = sizeof(DWORD), type, value = 0;
478 LONG ret;
480 ret = RegQueryValueExW( hkey, name, 0, &type, (LPBYTE)&value, &sz );
482 if (ret != ERROR_SUCCESS)
484 WARN( "Got ret = %d on name %s\n", ret, debugstr_w(name) );
485 return 0;
487 if (type != REG_DWORD)
489 ERR( "Got type %d\n", type );
490 return 0;
492 return value;
495 static inline DWORD set_reg_DWORD( HKEY hkey, const WCHAR *keyname, const DWORD value )
497 return RegSetValueExW( hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value) );
500 /******************************************************************
501 * get_opened_printer
502 * Get the pointer to the opened printer referred by the handle
504 static opened_printer_t *get_opened_printer(HANDLE hprn)
506 UINT_PTR idx = (UINT_PTR)hprn;
507 opened_printer_t *ret = NULL;
509 EnterCriticalSection(&printer_handles_cs);
511 if ((idx > 0) && (idx <= nb_printer_handles)) {
512 ret = printer_handles[idx - 1];
514 LeaveCriticalSection(&printer_handles_cs);
515 return ret;
518 /******************************************************************
519 * get_opened_printer_name
520 * Get the pointer to the opened printer name referred by the handle
522 static LPCWSTR get_opened_printer_name(HANDLE hprn)
524 opened_printer_t *printer = get_opened_printer(hprn);
525 if(!printer) return NULL;
526 return printer->name;
529 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
531 HKEY printers;
532 DWORD err;
534 *key = NULL;
535 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
536 if (err) return err;
538 err = RegOpenKeyW( printers, name, key );
539 if (err) err = ERROR_INVALID_PRINTER_NAME;
540 RegCloseKey( printers );
541 return err;
544 /******************************************************************
545 * WINSPOOL_GetOpenedPrinterRegKey
548 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
550 LPCWSTR name = get_opened_printer_name(hPrinter);
552 if(!name) return ERROR_INVALID_HANDLE;
553 return open_printer_reg_key( name, phkey );
556 static void
557 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
558 char qbuf[200];
560 /* If forcing, or no profile string entry for device yet, set the entry
562 * The always change entry if not WINEPS yet is discussable.
564 if (force ||
565 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
566 !strcmp(qbuf,"*") ||
567 !strstr(qbuf,"WINEPS.DRV")
569 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
570 HKEY hkey;
572 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
573 WriteProfileStringA("windows","device",buf);
574 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
575 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
576 RegCloseKey(hkey);
578 HeapFree(GetProcessHeap(),0,buf);
582 static BOOL add_printer_driver(const WCHAR *name, WCHAR *ppd)
584 DRIVER_INFO_3W di3;
586 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
587 di3.cVersion = 3;
588 di3.pName = (WCHAR*)name;
589 di3.pEnvironment = envname_x86W;
590 di3.pDriverPath = driver_nt;
591 di3.pDataFile = ppd;
592 di3.pConfigFile = driver_nt;
593 di3.pDefaultDataType = rawW;
595 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
596 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
598 di3.cVersion = 0;
599 di3.pEnvironment = envname_win40W;
600 di3.pDriverPath = driver_9x;
601 di3.pConfigFile = driver_9x;
602 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
603 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
605 return TRUE;
608 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
609 return FALSE;
612 static inline char *expand_env_string( char *str, DWORD type )
614 if (type == REG_EXPAND_SZ)
616 char *tmp;
617 DWORD needed = ExpandEnvironmentStringsA( str, NULL, 0 );
618 tmp = HeapAlloc( GetProcessHeap(), 0, needed );
619 if (tmp)
621 ExpandEnvironmentStringsA( str, tmp, needed );
622 HeapFree( GetProcessHeap(), 0, str );
623 return tmp;
626 return str;
629 static char *get_fallback_ppd_name( const char *printer_name )
631 static const WCHAR ppds_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
632 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
633 HKEY hkey;
634 DWORD needed, type;
635 char *ret = NULL;
637 if (RegOpenKeyW( HKEY_CURRENT_USER, ppds_key, &hkey ) == ERROR_SUCCESS )
639 const char *value_name = NULL;
641 if (RegQueryValueExA( hkey, printer_name, 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
642 value_name = printer_name;
643 else if (RegQueryValueExA( hkey, "generic", 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
644 value_name = "generic";
646 if (value_name)
648 ret = HeapAlloc( GetProcessHeap(), 0, needed );
649 if (!ret) return NULL;
650 RegQueryValueExA( hkey, value_name, 0, &type, (BYTE *)ret, &needed );
652 RegCloseKey( hkey );
653 if (ret) return expand_env_string( ret, type );
655 return NULL;
658 static BOOL copy_file( const char *src, const char *dst )
660 int fds[2] = {-1, -1}, num;
661 char buf[1024];
662 BOOL ret = FALSE;
664 fds[0] = open( src, O_RDONLY );
665 fds[1] = open( dst, O_CREAT | O_TRUNC | O_WRONLY, 0666 );
666 if (fds[0] == -1 || fds[1] == -1) goto fail;
668 while ((num = read( fds[0], buf, sizeof(buf) )) != 0)
670 if (num == -1) goto fail;
671 if (write( fds[1], buf, num ) != num) goto fail;
673 ret = TRUE;
675 fail:
676 if (fds[1] != -1) close( fds[1] );
677 if (fds[0] != -1) close( fds[0] );
678 return ret;
681 static BOOL get_internal_fallback_ppd( const WCHAR *ppd )
683 static const WCHAR typeW[] = {'P','P','D','F','I','L','E',0};
685 char *ptr, *end;
686 DWORD size, written;
687 HANDLE file;
688 BOOL ret;
689 HRSRC res = FindResourceW( WINSPOOL_hInstance, MAKEINTRESOURCEW(1), typeW );
691 if (!res || !(ptr = LoadResource( WINSPOOL_hInstance, res ))) return FALSE;
692 size = SizeofResource( WINSPOOL_hInstance, res );
693 end = memchr( ptr, 0, size ); /* resource file may contain additional nulls */
694 if (end) size = end - ptr;
695 file = CreateFileW( ppd, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0 );
696 if (file == INVALID_HANDLE_VALUE) return FALSE;
697 ret = WriteFile( file, ptr, size, &written, NULL ) && written == size;
698 CloseHandle( file );
699 if (ret) TRACE( "using internal fallback for %s\n", debugstr_w( ppd ));
700 else DeleteFileW( ppd );
701 return ret;
704 static BOOL get_fallback_ppd( const char *printer_name, const WCHAR *ppd )
706 char *dst, *src = get_fallback_ppd_name( printer_name );
707 BOOL ret = FALSE;
709 if (!src) return get_internal_fallback_ppd( ppd );
711 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name), debugstr_w(ppd), debugstr_a(src) );
713 if (!(dst = wine_get_unix_file_name( ppd ))) goto fail;
715 if (symlink( src, dst ) == -1)
716 if (errno != ENOSYS || !copy_file( src, dst ))
717 goto fail;
719 ret = TRUE;
720 fail:
721 HeapFree( GetProcessHeap(), 0, dst );
722 HeapFree( GetProcessHeap(), 0, src );
723 return ret;
726 static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
728 static const WCHAR dot_ppd[] = {'.','p','p','d',0};
729 int len = (strlenW( dir ) + strlenW( file_name )) * sizeof(WCHAR) + sizeof(dot_ppd);
730 WCHAR *ppd = HeapAlloc( GetProcessHeap(), 0, len );
732 if (!ppd) return NULL;
733 strcpyW( ppd, dir );
734 strcatW( ppd, file_name );
735 strcatW( ppd, dot_ppd );
737 return ppd;
740 static WCHAR *get_ppd_dir( void )
742 static const WCHAR wine_ppds[] = {'w','i','n','e','_','p','p','d','s','\\',0};
743 DWORD len;
744 WCHAR *dir, tmp_path[MAX_PATH];
745 BOOL res;
747 len = GetTempPathW( sizeof(tmp_path) / sizeof(tmp_path[0]), tmp_path );
748 if (!len) return NULL;
749 dir = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
750 if (!dir) return NULL;
752 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
753 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
754 res = CreateDirectoryW( dir, NULL );
755 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
757 HeapFree( GetProcessHeap(), 0, dir );
758 dir = NULL;
760 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
761 return dir;
764 static void unlink_ppd( const WCHAR *ppd )
766 char *unix_name = wine_get_unix_file_name( ppd );
767 unlink( unix_name );
768 HeapFree( GetProcessHeap(), 0, unix_name );
771 #ifdef SONAME_LIBCUPS
773 static void *cupshandle;
775 #define CUPS_FUNCS \
776 DO_FUNC(cupsAddOption); \
777 DO_FUNC(cupsFreeDests); \
778 DO_FUNC(cupsFreeOptions); \
779 DO_FUNC(cupsGetDests); \
780 DO_FUNC(cupsGetOption); \
781 DO_FUNC(cupsGetPPD); \
782 DO_FUNC(cupsParseOptions); \
783 DO_FUNC(cupsPrintFile)
784 #define CUPS_OPT_FUNCS \
785 DO_FUNC(cupsGetNamedDest); \
786 DO_FUNC(cupsGetPPD3)
788 #define DO_FUNC(f) static typeof(f) *p##f
789 CUPS_FUNCS;
790 #undef DO_FUNC
791 static cups_dest_t * (*pcupsGetNamedDest)(http_t *, const char *, const char *);
792 static http_status_t (*pcupsGetPPD3)(http_t *, const char *, time_t *, char *, size_t);
794 static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name,
795 time_t *modtime, char *buffer,
796 size_t bufsize )
798 const char *ppd;
800 if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
802 if (!pcupsGetPPD) return HTTP_NOT_FOUND;
804 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
806 *modtime = 0;
807 ppd = pcupsGetPPD( name );
809 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
811 if (!ppd) return HTTP_NOT_FOUND;
813 if (rename( ppd, buffer ) == -1)
815 BOOL res = copy_file( ppd, buffer );
816 unlink( ppd );
817 if (!res) return HTTP_NOT_FOUND;
819 return HTTP_OK;
822 static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
824 time_t modtime = 0;
825 http_status_t http_status;
826 char *unix_name = wine_get_unix_file_name( ppd );
828 TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
830 if (!unix_name) return FALSE;
832 http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
833 unix_name, strlen( unix_name ) + 1 );
835 if (http_status != HTTP_OK) unlink( unix_name );
836 HeapFree( GetProcessHeap(), 0, unix_name );
838 if (http_status == HTTP_OK) return TRUE;
840 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
841 debugstr_a(printer_name), http_status );
842 return get_fallback_ppd( printer_name, ppd );
845 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
847 const char *value;
848 WCHAR *ret;
849 int len;
851 value = pcupsGetOption( name, num_options, options );
852 if (!value) return NULL;
854 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
855 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
856 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
858 return ret;
861 static cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
863 WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
864 cups_ptype_t ret = 0;
866 if (type && *type)
868 ret = (cups_ptype_t)strtoulW( type, &end, 10 );
869 if (*end) ret = 0;
871 HeapFree( GetProcessHeap(), 0, type );
872 return ret;
875 static void load_cups(void)
877 cupshandle = wine_dlopen( SONAME_LIBCUPS, RTLD_NOW, NULL, 0 );
878 if (!cupshandle) return;
880 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
882 #define DO_FUNC(x) \
883 p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); \
884 if (!p##x) \
886 ERR("failed to load symbol %s\n", #x); \
887 cupshandle = NULL; \
888 return; \
890 CUPS_FUNCS;
891 #undef DO_FUNC
892 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 )
893 CUPS_OPT_FUNCS;
894 #undef DO_FUNC
897 static BOOL CUPS_LoadPrinters(void)
899 int i, nrofdests;
900 BOOL hadprinter = FALSE, haddefault = FALSE;
901 cups_dest_t *dests;
902 PRINTER_INFO_2W pi2;
903 WCHAR *port, *ppd_dir = NULL, *ppd;
904 HKEY hkeyPrinter, hkeyPrinters;
905 WCHAR nameW[MAX_PATH];
906 HANDLE added_printer;
907 cups_ptype_t printer_type;
909 if (!cupshandle) return FALSE;
911 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
912 ERROR_SUCCESS) {
913 ERR("Can't create Printers key\n");
914 return FALSE;
917 nrofdests = pcupsGetDests(&dests);
918 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
919 for (i=0;i<nrofdests;i++) {
920 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
921 printer_type = get_cups_printer_type( dests + i );
923 TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
925 if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
927 TRACE( "skipping scanner-only device\n" );
928 continue;
931 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
932 lstrcpyW(port, CUPS_Port);
933 lstrcatW(port, nameW);
935 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
936 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
937 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
938 and continue */
939 TRACE("Printer already exists\n");
940 /* overwrite old LPR:* port */
941 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
942 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
943 /* flag that the PPD file should be checked for an update */
944 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
945 RegCloseKey(hkeyPrinter);
946 } else {
947 BOOL added_driver = FALSE;
949 if (!ppd_dir) ppd_dir = get_ppd_dir();
950 ppd = get_ppd_filename( ppd_dir, nameW );
951 if (get_cups_ppd( dests[i].name, ppd ))
953 added_driver = add_printer_driver( nameW, ppd );
954 unlink_ppd( ppd );
956 HeapFree( GetProcessHeap(), 0, ppd );
957 if (!added_driver)
959 HeapFree( GetProcessHeap(), 0, port );
960 continue;
963 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
964 pi2.pPrinterName = nameW;
965 pi2.pDatatype = rawW;
966 pi2.pPrintProcessor = WinPrintW;
967 pi2.pDriverName = nameW;
968 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
969 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
970 pi2.pPortName = port;
971 pi2.pParameters = emptyStringW;
972 pi2.pShareName = emptyStringW;
973 pi2.pSepFile = emptyStringW;
975 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
976 if (added_printer) ClosePrinter( added_printer );
977 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
978 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
980 HeapFree( GetProcessHeap(), 0, pi2.pComment );
981 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
983 HeapFree( GetProcessHeap(), 0, port );
985 hadprinter = TRUE;
986 if (dests[i].is_default) {
987 SetDefaultPrinterW(nameW);
988 haddefault = TRUE;
992 if (ppd_dir)
994 RemoveDirectoryW( ppd_dir );
995 HeapFree( GetProcessHeap(), 0, ppd_dir );
998 if (hadprinter && !haddefault) {
999 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
1000 SetDefaultPrinterW(nameW);
1002 pcupsFreeDests(nrofdests, dests);
1003 RegCloseKey(hkeyPrinters);
1004 return TRUE;
1007 #endif
1009 static char *get_queue_name( HANDLE printer, BOOL *cups )
1011 WCHAR *port, *name = NULL;
1012 DWORD err, needed, type;
1013 char *ret = NULL;
1014 HKEY key;
1016 *cups = FALSE;
1018 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1019 if (err) return NULL;
1020 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1021 if (err) goto end;
1022 port = HeapAlloc( GetProcessHeap(), 0, needed );
1023 if (!port) goto end;
1024 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1026 if (!strncmpW( port, CUPS_Port, sizeof(CUPS_Port) / sizeof(WCHAR) -1 ))
1028 name = port + sizeof(CUPS_Port) / sizeof(WCHAR) - 1;
1029 *cups = TRUE;
1031 else if (!strncmpW( port, LPR_Port, sizeof(LPR_Port) / sizeof(WCHAR) -1 ))
1032 name = port + sizeof(LPR_Port) / sizeof(WCHAR) - 1;
1033 if (name)
1035 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1036 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1037 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1039 HeapFree( GetProcessHeap(), 0, port );
1040 end:
1041 RegCloseKey( key );
1042 return ret;
1046 static void set_ppd_overrides( HANDLE printer )
1048 WCHAR *wstr = NULL;
1049 int size = 0;
1050 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1051 OSStatus status;
1052 PMPrintSession session = NULL;
1053 PMPageFormat format = NULL;
1054 PMPaper paper;
1055 CFStringRef paper_name;
1056 CFRange range;
1058 status = PMCreateSession( &session );
1059 if (status) goto end;
1061 status = PMCreatePageFormat( &format );
1062 if (status) goto end;
1064 status = PMSessionDefaultPageFormat( session, format );
1065 if (status) goto end;
1067 status = PMGetPageFormatPaper( format, &paper );
1068 if (status) goto end;
1070 status = PMPaperGetPPDPaperName( paper, &paper_name );
1071 if (status) goto end;
1073 range.location = 0;
1074 range.length = CFStringGetLength( paper_name );
1075 size = (range.length + 1) * sizeof(WCHAR);
1077 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1078 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1079 wstr[range.length] = 0;
1081 end:
1082 if (format) PMRelease( format );
1083 if (session) PMRelease( session );
1084 #endif
1086 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1087 HeapFree( GetProcessHeap(), 0, wstr );
1090 static BOOL update_driver( HANDLE printer )
1092 BOOL ret, is_cups;
1093 const WCHAR *name = get_opened_printer_name( printer );
1094 WCHAR *ppd_dir, *ppd;
1095 char *queue_name;
1097 if (!name) return FALSE;
1098 queue_name = get_queue_name( printer, &is_cups );
1099 if (!queue_name) return FALSE;
1101 ppd_dir = get_ppd_dir();
1102 ppd = get_ppd_filename( ppd_dir, name );
1104 #ifdef SONAME_LIBCUPS
1105 if (is_cups)
1106 ret = get_cups_ppd( queue_name, ppd );
1107 else
1108 #endif
1109 ret = get_fallback_ppd( queue_name, ppd );
1111 if (ret)
1113 TRACE( "updating driver %s\n", debugstr_w( name ) );
1114 ret = add_printer_driver( name, ppd );
1115 unlink_ppd( ppd );
1117 HeapFree( GetProcessHeap(), 0, ppd_dir );
1118 HeapFree( GetProcessHeap(), 0, ppd );
1119 HeapFree( GetProcessHeap(), 0, queue_name );
1121 set_ppd_overrides( printer );
1123 /* call into the driver to update the devmode */
1124 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1126 return ret;
1129 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1131 PRINTER_INFO_2A pinfo2a;
1132 const char *r;
1133 size_t name_len;
1134 char *e,*s,*name,*prettyname,*devname;
1135 BOOL ret = FALSE, set_default = FALSE;
1136 char *port = NULL, *env_default;
1137 HKEY hkeyPrinter, hkeyPrinters = NULL;
1138 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1139 HANDLE added_printer;
1141 while (isspace(*pent)) pent++;
1142 r = strchr(pent,':');
1143 if (r)
1144 name_len = r - pent;
1145 else
1146 name_len = strlen(pent);
1147 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1148 memcpy(name, pent, name_len);
1149 name[name_len] = '\0';
1150 if (r)
1151 pent = r;
1152 else
1153 pent = "";
1155 TRACE("name=%s entry=%s\n",name, pent);
1157 if(ispunct(*name)) { /* a tc entry, not a real printer */
1158 TRACE("skipping tc entry\n");
1159 goto end;
1162 if(strstr(pent,":server")) { /* server only version so skip */
1163 TRACE("skipping server entry\n");
1164 goto end;
1167 /* Determine whether this is a postscript printer. */
1169 ret = TRUE;
1170 env_default = getenv("PRINTER");
1171 prettyname = name;
1172 /* Get longest name, usually the one at the right for later display. */
1173 while((s=strchr(prettyname,'|'))) {
1174 *s = '\0';
1175 e = s;
1176 while(isspace(*--e)) *e = '\0';
1177 TRACE("\t%s\n", debugstr_a(prettyname));
1178 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1179 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1182 e = prettyname + strlen(prettyname);
1183 while(isspace(*--e)) *e = '\0';
1184 TRACE("\t%s\n", debugstr_a(prettyname));
1185 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1187 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1188 * if it is too long, we use it as comment below. */
1189 devname = prettyname;
1190 if (strlen(devname)>=CCHDEVICENAME-1)
1191 devname = name;
1192 if (strlen(devname)>=CCHDEVICENAME-1) {
1193 ret = FALSE;
1194 goto end;
1197 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1198 sprintf(port,"LPR:%s",name);
1200 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1201 ERROR_SUCCESS) {
1202 ERR("Can't create Printers key\n");
1203 ret = FALSE;
1204 goto end;
1207 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
1209 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1210 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1211 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1212 and continue */
1213 TRACE("Printer already exists\n");
1214 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1215 /* flag that the PPD file should be checked for an update */
1216 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1217 RegCloseKey(hkeyPrinter);
1218 } else {
1219 static CHAR data_type[] = "RAW",
1220 print_proc[] = "WinPrint",
1221 comment[] = "WINEPS Printer using LPR",
1222 params[] = "<parameters?>",
1223 share_name[] = "<share name?>",
1224 sep_file[] = "<sep file?>";
1225 BOOL added_driver = FALSE;
1227 if (!ppd_dir) ppd_dir = get_ppd_dir();
1228 ppd = get_ppd_filename( ppd_dir, devnameW );
1229 if (get_fallback_ppd( devname, ppd ))
1231 added_driver = add_printer_driver( devnameW, ppd );
1232 unlink_ppd( ppd );
1234 HeapFree( GetProcessHeap(), 0, ppd );
1235 if (!added_driver) goto end;
1237 memset(&pinfo2a,0,sizeof(pinfo2a));
1238 pinfo2a.pPrinterName = devname;
1239 pinfo2a.pDatatype = data_type;
1240 pinfo2a.pPrintProcessor = print_proc;
1241 pinfo2a.pDriverName = devname;
1242 pinfo2a.pComment = comment;
1243 pinfo2a.pLocation = prettyname;
1244 pinfo2a.pPortName = port;
1245 pinfo2a.pParameters = params;
1246 pinfo2a.pShareName = share_name;
1247 pinfo2a.pSepFile = sep_file;
1249 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1250 if (added_printer) ClosePrinter( added_printer );
1251 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1252 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1255 if (isfirst || set_default)
1256 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1258 end:
1259 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1260 if (ppd_dir)
1262 RemoveDirectoryW( ppd_dir );
1263 HeapFree( GetProcessHeap(), 0, ppd_dir );
1265 HeapFree(GetProcessHeap(), 0, port);
1266 HeapFree(GetProcessHeap(), 0, name);
1267 return ret;
1270 static BOOL
1271 PRINTCAP_LoadPrinters(void) {
1272 BOOL hadprinter = FALSE;
1273 char buf[200];
1274 FILE *f;
1275 char *pent = NULL;
1276 BOOL had_bash = FALSE;
1278 f = fopen("/etc/printcap","r");
1279 if (!f)
1280 return FALSE;
1282 while(fgets(buf,sizeof(buf),f)) {
1283 char *start, *end;
1285 end=strchr(buf,'\n');
1286 if (end) *end='\0';
1288 start = buf;
1289 while(isspace(*start)) start++;
1290 if(*start == '#' || *start == '\0')
1291 continue;
1293 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1294 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1295 HeapFree(GetProcessHeap(),0,pent);
1296 pent = NULL;
1299 if (end && *--end == '\\') {
1300 *end = '\0';
1301 had_bash = TRUE;
1302 } else
1303 had_bash = FALSE;
1305 if (pent) {
1306 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1307 strcat(pent,start);
1308 } else {
1309 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1310 strcpy(pent,start);
1314 if(pent) {
1315 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1316 HeapFree(GetProcessHeap(),0,pent);
1318 fclose(f);
1319 return hadprinter;
1322 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1324 if (value)
1325 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1326 (lstrlenW(value) + 1) * sizeof(WCHAR));
1327 else
1328 return ERROR_FILE_NOT_FOUND;
1331 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1333 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1334 DWORD ret = ERROR_FILE_NOT_FOUND;
1336 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1337 and we support these drivers. NT writes DEVMODEW so somehow
1338 we'll need to distinguish between these when we support NT
1339 drivers */
1341 if (dmA)
1343 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1344 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1345 HeapFree( GetProcessHeap(), 0, dmA );
1348 return ret;
1351 /******************************************************************
1352 * get_servername_from_name (internal)
1354 * for an external server, a copy of the serverpart from the full name is returned
1357 static LPWSTR get_servername_from_name(LPCWSTR name)
1359 LPWSTR server;
1360 LPWSTR ptr;
1361 WCHAR buffer[MAX_PATH];
1362 DWORD len;
1364 if (name == NULL) return NULL;
1365 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1367 server = strdupW(&name[2]); /* skip over both backslash */
1368 if (server == NULL) return NULL;
1370 /* strip '\' and the printername */
1371 ptr = strchrW(server, '\\');
1372 if (ptr) ptr[0] = '\0';
1374 TRACE("found %s\n", debugstr_w(server));
1376 len = sizeof(buffer)/sizeof(buffer[0]);
1377 if (GetComputerNameW(buffer, &len)) {
1378 if (lstrcmpW(buffer, server) == 0) {
1379 /* The requested Servername is our computername */
1380 HeapFree(GetProcessHeap(), 0, server);
1381 return NULL;
1384 return server;
1387 /******************************************************************
1388 * get_basename_from_name (internal)
1390 * skip over the serverpart from the full name
1393 static LPCWSTR get_basename_from_name(LPCWSTR name)
1395 if (name == NULL) return NULL;
1396 if ((name[0] == '\\') && (name[1] == '\\')) {
1397 /* skip over the servername and search for the following '\' */
1398 name = strchrW(&name[2], '\\');
1399 if ((name) && (name[1])) {
1400 /* found a separator ('\') followed by a name:
1401 skip over the separator and return the rest */
1402 name++;
1404 else
1406 /* no basename present (we found only a servername) */
1407 return NULL;
1410 return name;
1413 static void free_printer_entry( opened_printer_t *printer )
1415 /* the queue is shared, so don't free that here */
1416 HeapFree( GetProcessHeap(), 0, printer->printername );
1417 HeapFree( GetProcessHeap(), 0, printer->name );
1418 HeapFree( GetProcessHeap(), 0, printer->devmode );
1419 HeapFree( GetProcessHeap(), 0, printer );
1422 /******************************************************************
1423 * get_opened_printer_entry
1424 * Get the first place empty in the opened printer table
1426 * ToDo:
1427 * - pDefault is ignored
1429 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1431 UINT_PTR handle = nb_printer_handles, i;
1432 jobqueue_t *queue = NULL;
1433 opened_printer_t *printer = NULL;
1434 LPWSTR servername;
1435 LPCWSTR printername;
1437 if ((backend == NULL) && !load_backend()) return NULL;
1439 servername = get_servername_from_name(name);
1440 if (servername) {
1441 FIXME("server %s not supported\n", debugstr_w(servername));
1442 HeapFree(GetProcessHeap(), 0, servername);
1443 SetLastError(ERROR_INVALID_PRINTER_NAME);
1444 return NULL;
1447 printername = get_basename_from_name(name);
1448 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1450 /* an empty printername is invalid */
1451 if (printername && (!printername[0])) {
1452 SetLastError(ERROR_INVALID_PARAMETER);
1453 return NULL;
1456 EnterCriticalSection(&printer_handles_cs);
1458 for (i = 0; i < nb_printer_handles; i++)
1460 if (!printer_handles[i])
1462 if(handle == nb_printer_handles)
1463 handle = i;
1465 else
1467 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1468 queue = printer_handles[i]->queue;
1472 if (handle >= nb_printer_handles)
1474 opened_printer_t **new_array;
1475 if (printer_handles)
1476 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1477 (nb_printer_handles + 16) * sizeof(*new_array) );
1478 else
1479 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1480 (nb_printer_handles + 16) * sizeof(*new_array) );
1482 if (!new_array)
1484 handle = 0;
1485 goto end;
1487 printer_handles = new_array;
1488 nb_printer_handles += 16;
1491 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1493 handle = 0;
1494 goto end;
1497 /* get a printer handle from the backend */
1498 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1499 handle = 0;
1500 goto end;
1503 /* clone the base name. This is NULL for the printserver */
1504 printer->printername = strdupW(printername);
1506 /* clone the full name */
1507 printer->name = strdupW(name);
1508 if (name && (!printer->name)) {
1509 handle = 0;
1510 goto end;
1513 if (pDefault && pDefault->pDevMode)
1514 printer->devmode = dup_devmode( pDefault->pDevMode );
1516 if(queue)
1517 printer->queue = queue;
1518 else
1520 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1521 if (!printer->queue) {
1522 handle = 0;
1523 goto end;
1525 list_init(&printer->queue->jobs);
1526 printer->queue->ref = 0;
1528 InterlockedIncrement(&printer->queue->ref);
1530 printer_handles[handle] = printer;
1531 handle++;
1532 end:
1533 LeaveCriticalSection(&printer_handles_cs);
1534 if (!handle && printer) {
1535 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1536 free_printer_entry( printer );
1539 return (HANDLE)handle;
1542 static void old_printer_check( BOOL delete_phase )
1544 PRINTER_INFO_5W* pi;
1545 DWORD needed, type, num, delete, i, size;
1546 const DWORD one = 1;
1547 HKEY key;
1548 HANDLE hprn;
1550 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1551 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1553 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1554 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1555 for (i = 0; i < num; i++)
1557 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1558 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1559 continue;
1561 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1563 if (!delete_phase)
1565 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1566 RegCloseKey( key );
1568 else
1570 delete = 0;
1571 size = sizeof( delete );
1572 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1573 RegCloseKey( key );
1574 if (delete)
1576 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1577 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1579 DeletePrinter( hprn );
1580 ClosePrinter( hprn );
1582 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1586 HeapFree(GetProcessHeap(), 0, pi);
1589 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1590 'M','U','T','E','X','_','_','\0'};
1591 static HANDLE init_mutex;
1593 void WINSPOOL_LoadSystemPrinters(void)
1595 HKEY hkey, hkeyPrinters;
1596 DWORD needed, num, i;
1597 WCHAR PrinterName[256];
1598 BOOL done = FALSE;
1600 #ifdef SONAME_LIBCUPS
1601 load_cups();
1602 #endif
1604 /* FIXME: The init code should be moved to spoolsv.exe */
1605 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1606 if (!init_mutex)
1608 ERR( "Failed to create mutex\n" );
1609 return;
1611 if (GetLastError() == ERROR_ALREADY_EXISTS)
1613 WaitForSingleObject( init_mutex, INFINITE );
1614 ReleaseMutex( init_mutex );
1615 TRACE( "Init already done\n" );
1616 return;
1619 /* This ensures that all printer entries have a valid Name value. If causes
1620 problems later if they don't. If one is found to be missed we create one
1621 and set it equal to the name of the key */
1622 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1623 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1624 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1625 for(i = 0; i < num; i++) {
1626 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1627 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1628 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1629 set_reg_szW(hkey, NameW, PrinterName);
1631 RegCloseKey(hkey);
1636 RegCloseKey(hkeyPrinters);
1639 old_printer_check( FALSE );
1641 #ifdef SONAME_LIBCUPS
1642 done = CUPS_LoadPrinters();
1643 #endif
1645 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1646 PRINTCAP_LoadPrinters();
1648 old_printer_check( TRUE );
1650 ReleaseMutex( init_mutex );
1651 return;
1654 /******************************************************************
1655 * get_job
1657 * Get the pointer to the specified job.
1658 * Should hold the printer_handles_cs before calling.
1660 static job_t *get_job(HANDLE hprn, DWORD JobId)
1662 opened_printer_t *printer = get_opened_printer(hprn);
1663 job_t *job;
1665 if(!printer) return NULL;
1666 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1668 if(job->job_id == JobId)
1669 return job;
1671 return NULL;
1674 /***********************************************************
1675 * DEVMODEcpyAtoW
1677 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1679 BOOL Formname;
1680 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1681 DWORD size;
1683 Formname = (dmA->dmSize > off_formname);
1684 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1685 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1686 dmW->dmDeviceName, CCHDEVICENAME);
1687 if(!Formname) {
1688 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1689 dmA->dmSize - CCHDEVICENAME);
1690 } else {
1691 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1692 off_formname - CCHDEVICENAME);
1693 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1694 dmW->dmFormName, CCHFORMNAME);
1695 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1696 (off_formname + CCHFORMNAME));
1698 dmW->dmSize = size;
1699 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1700 dmA->dmDriverExtra);
1701 return dmW;
1704 /******************************************************************
1705 * convert_printerinfo_W_to_A [internal]
1708 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1709 DWORD level, DWORD outlen, DWORD numentries)
1711 DWORD id = 0;
1712 LPSTR ptr;
1713 INT len;
1715 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1717 len = pi_sizeof[level] * numentries;
1718 ptr = (LPSTR) out + len;
1719 outlen -= len;
1721 /* copy the numbers of all PRINTER_INFO_* first */
1722 memcpy(out, pPrintersW, len);
1724 while (id < numentries) {
1725 switch (level) {
1726 case 1:
1728 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1729 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1731 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1732 if (piW->pDescription) {
1733 piA->pDescription = ptr;
1734 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1735 ptr, outlen, NULL, NULL);
1736 ptr += len;
1737 outlen -= len;
1739 if (piW->pName) {
1740 piA->pName = ptr;
1741 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1742 ptr, outlen, NULL, NULL);
1743 ptr += len;
1744 outlen -= len;
1746 if (piW->pComment) {
1747 piA->pComment = ptr;
1748 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1749 ptr, outlen, NULL, NULL);
1750 ptr += len;
1751 outlen -= len;
1753 break;
1756 case 2:
1758 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1759 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1760 LPDEVMODEA dmA;
1762 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1763 if (piW->pServerName) {
1764 piA->pServerName = ptr;
1765 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1766 ptr, outlen, NULL, NULL);
1767 ptr += len;
1768 outlen -= len;
1770 if (piW->pPrinterName) {
1771 piA->pPrinterName = ptr;
1772 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1773 ptr, outlen, NULL, NULL);
1774 ptr += len;
1775 outlen -= len;
1777 if (piW->pShareName) {
1778 piA->pShareName = ptr;
1779 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1780 ptr, outlen, NULL, NULL);
1781 ptr += len;
1782 outlen -= len;
1784 if (piW->pPortName) {
1785 piA->pPortName = ptr;
1786 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1787 ptr, outlen, NULL, NULL);
1788 ptr += len;
1789 outlen -= len;
1791 if (piW->pDriverName) {
1792 piA->pDriverName = ptr;
1793 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1794 ptr, outlen, NULL, NULL);
1795 ptr += len;
1796 outlen -= len;
1798 if (piW->pComment) {
1799 piA->pComment = ptr;
1800 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1801 ptr, outlen, NULL, NULL);
1802 ptr += len;
1803 outlen -= len;
1805 if (piW->pLocation) {
1806 piA->pLocation = ptr;
1807 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1808 ptr, outlen, NULL, NULL);
1809 ptr += len;
1810 outlen -= len;
1813 dmA = DEVMODEdupWtoA(piW->pDevMode);
1814 if (dmA) {
1815 /* align DEVMODEA to a DWORD boundary */
1816 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1817 ptr += len;
1818 outlen -= len;
1820 piA->pDevMode = (LPDEVMODEA) ptr;
1821 len = dmA->dmSize + dmA->dmDriverExtra;
1822 memcpy(ptr, dmA, len);
1823 HeapFree(GetProcessHeap(), 0, dmA);
1825 ptr += len;
1826 outlen -= len;
1829 if (piW->pSepFile) {
1830 piA->pSepFile = ptr;
1831 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1832 ptr, outlen, NULL, NULL);
1833 ptr += len;
1834 outlen -= len;
1836 if (piW->pPrintProcessor) {
1837 piA->pPrintProcessor = ptr;
1838 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1839 ptr, outlen, NULL, NULL);
1840 ptr += len;
1841 outlen -= len;
1843 if (piW->pDatatype) {
1844 piA->pDatatype = ptr;
1845 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1846 ptr, outlen, NULL, NULL);
1847 ptr += len;
1848 outlen -= len;
1850 if (piW->pParameters) {
1851 piA->pParameters = ptr;
1852 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1853 ptr, outlen, NULL, NULL);
1854 ptr += len;
1855 outlen -= len;
1857 if (piW->pSecurityDescriptor) {
1858 piA->pSecurityDescriptor = NULL;
1859 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1861 break;
1864 case 4:
1866 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1867 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1869 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1871 if (piW->pPrinterName) {
1872 piA->pPrinterName = ptr;
1873 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1874 ptr, outlen, NULL, NULL);
1875 ptr += len;
1876 outlen -= len;
1878 if (piW->pServerName) {
1879 piA->pServerName = ptr;
1880 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1881 ptr, outlen, NULL, NULL);
1882 ptr += len;
1883 outlen -= len;
1885 break;
1888 case 5:
1890 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1891 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1893 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1895 if (piW->pPrinterName) {
1896 piA->pPrinterName = ptr;
1897 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1898 ptr, outlen, NULL, NULL);
1899 ptr += len;
1900 outlen -= len;
1902 if (piW->pPortName) {
1903 piA->pPortName = ptr;
1904 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1905 ptr, outlen, NULL, NULL);
1906 ptr += len;
1907 outlen -= len;
1909 break;
1912 case 6: /* 6A and 6W are the same structure */
1913 break;
1915 case 7:
1917 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1918 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1920 TRACE("(%u) #%u\n", level, id);
1921 if (piW->pszObjectGUID) {
1922 piA->pszObjectGUID = ptr;
1923 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1924 ptr, outlen, NULL, NULL);
1925 ptr += len;
1926 outlen -= len;
1928 break;
1931 case 8:
1932 case 9:
1934 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1935 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1936 LPDEVMODEA dmA;
1938 TRACE("(%u) #%u\n", level, id);
1939 dmA = DEVMODEdupWtoA(piW->pDevMode);
1940 if (dmA) {
1941 /* align DEVMODEA to a DWORD boundary */
1942 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1943 ptr += len;
1944 outlen -= len;
1946 piA->pDevMode = (LPDEVMODEA) ptr;
1947 len = dmA->dmSize + dmA->dmDriverExtra;
1948 memcpy(ptr, dmA, len);
1949 HeapFree(GetProcessHeap(), 0, dmA);
1951 ptr += len;
1952 outlen -= len;
1955 break;
1958 default:
1959 FIXME("for level %u\n", level);
1961 pPrintersW += pi_sizeof[level];
1962 out += pi_sizeof[level];
1963 id++;
1967 /******************************************************************
1968 * convert_driverinfo_W_to_A [internal]
1971 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1972 DWORD level, DWORD outlen, DWORD numentries)
1974 DWORD id = 0;
1975 LPSTR ptr;
1976 INT len;
1978 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1980 len = di_sizeof[level] * numentries;
1981 ptr = (LPSTR) out + len;
1982 outlen -= len;
1984 /* copy the numbers of all PRINTER_INFO_* first */
1985 memcpy(out, pDriversW, len);
1987 #define COPY_STRING(fld) \
1988 { if (diW->fld){ \
1989 diA->fld = ptr; \
1990 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1991 ptr += len; outlen -= len;\
1993 #define COPY_MULTIZ_STRING(fld) \
1994 { LPWSTR p = diW->fld; if (p){ \
1995 diA->fld = ptr; \
1996 do {\
1997 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1998 ptr += len; outlen -= len; p += len;\
2000 while(len > 1 && outlen > 0); \
2003 while (id < numentries)
2005 switch (level)
2007 case 1:
2009 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
2010 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
2012 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2014 COPY_STRING(pName);
2015 break;
2017 case 2:
2019 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2020 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2022 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2024 COPY_STRING(pName);
2025 COPY_STRING(pEnvironment);
2026 COPY_STRING(pDriverPath);
2027 COPY_STRING(pDataFile);
2028 COPY_STRING(pConfigFile);
2029 break;
2031 case 3:
2033 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2034 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2036 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2038 COPY_STRING(pName);
2039 COPY_STRING(pEnvironment);
2040 COPY_STRING(pDriverPath);
2041 COPY_STRING(pDataFile);
2042 COPY_STRING(pConfigFile);
2043 COPY_STRING(pHelpFile);
2044 COPY_MULTIZ_STRING(pDependentFiles);
2045 COPY_STRING(pMonitorName);
2046 COPY_STRING(pDefaultDataType);
2047 break;
2049 case 4:
2051 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2052 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2054 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2056 COPY_STRING(pName);
2057 COPY_STRING(pEnvironment);
2058 COPY_STRING(pDriverPath);
2059 COPY_STRING(pDataFile);
2060 COPY_STRING(pConfigFile);
2061 COPY_STRING(pHelpFile);
2062 COPY_MULTIZ_STRING(pDependentFiles);
2063 COPY_STRING(pMonitorName);
2064 COPY_STRING(pDefaultDataType);
2065 COPY_MULTIZ_STRING(pszzPreviousNames);
2066 break;
2068 case 5:
2070 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2071 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2073 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2075 COPY_STRING(pName);
2076 COPY_STRING(pEnvironment);
2077 COPY_STRING(pDriverPath);
2078 COPY_STRING(pDataFile);
2079 COPY_STRING(pConfigFile);
2080 break;
2082 case 6:
2084 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2085 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2087 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2089 COPY_STRING(pName);
2090 COPY_STRING(pEnvironment);
2091 COPY_STRING(pDriverPath);
2092 COPY_STRING(pDataFile);
2093 COPY_STRING(pConfigFile);
2094 COPY_STRING(pHelpFile);
2095 COPY_MULTIZ_STRING(pDependentFiles);
2096 COPY_STRING(pMonitorName);
2097 COPY_STRING(pDefaultDataType);
2098 COPY_MULTIZ_STRING(pszzPreviousNames);
2099 COPY_STRING(pszMfgName);
2100 COPY_STRING(pszOEMUrl);
2101 COPY_STRING(pszHardwareID);
2102 COPY_STRING(pszProvider);
2103 break;
2105 case 8:
2107 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2108 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2110 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2112 COPY_STRING(pName);
2113 COPY_STRING(pEnvironment);
2114 COPY_STRING(pDriverPath);
2115 COPY_STRING(pDataFile);
2116 COPY_STRING(pConfigFile);
2117 COPY_STRING(pHelpFile);
2118 COPY_MULTIZ_STRING(pDependentFiles);
2119 COPY_STRING(pMonitorName);
2120 COPY_STRING(pDefaultDataType);
2121 COPY_MULTIZ_STRING(pszzPreviousNames);
2122 COPY_STRING(pszMfgName);
2123 COPY_STRING(pszOEMUrl);
2124 COPY_STRING(pszHardwareID);
2125 COPY_STRING(pszProvider);
2126 COPY_STRING(pszPrintProcessor);
2127 COPY_STRING(pszVendorSetup);
2128 COPY_MULTIZ_STRING(pszzColorProfiles);
2129 COPY_STRING(pszInfPath);
2130 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2131 break;
2135 default:
2136 FIXME("for level %u\n", level);
2139 pDriversW += di_sizeof[level];
2140 out += di_sizeof[level];
2141 id++;
2144 #undef COPY_STRING
2145 #undef COPY_MULTIZ_STRING
2149 /***********************************************************
2150 * printer_info_AtoW
2152 static void *printer_info_AtoW( const void *data, DWORD level )
2154 void *ret;
2155 UNICODE_STRING usBuffer;
2157 if (!data) return NULL;
2159 if (level < 1 || level > 9) return NULL;
2161 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2162 if (!ret) return NULL;
2164 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2166 switch (level)
2168 case 2:
2170 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2171 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2173 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2174 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2175 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2176 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2177 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2178 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2179 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2180 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2181 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2182 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2183 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2184 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2185 break;
2188 case 8:
2189 case 9:
2191 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2192 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2194 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2195 break;
2198 default:
2199 FIXME( "Unhandled level %d\n", level );
2200 HeapFree( GetProcessHeap(), 0, ret );
2201 return NULL;
2204 return ret;
2207 /***********************************************************
2208 * free_printer_info
2210 static void free_printer_info( void *data, DWORD level )
2212 if (!data) return;
2214 switch (level)
2216 case 2:
2218 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2220 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2221 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2222 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2223 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2224 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2225 HeapFree( GetProcessHeap(), 0, piW->pComment );
2226 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2227 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2228 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2229 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2230 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2231 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2232 break;
2235 case 8:
2236 case 9:
2238 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2240 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2241 break;
2244 default:
2245 FIXME( "Unhandled level %d\n", level );
2248 HeapFree( GetProcessHeap(), 0, data );
2249 return;
2252 /******************************************************************
2253 * DeviceCapabilities [WINSPOOL.@]
2254 * DeviceCapabilitiesA [WINSPOOL.@]
2257 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2258 LPSTR pOutput, LPDEVMODEA lpdm)
2260 INT ret;
2262 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice), debugstr_a(pPort), cap, pOutput, lpdm);
2264 if (!GDI_CallDeviceCapabilities16)
2266 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2267 (LPCSTR)104 );
2268 if (!GDI_CallDeviceCapabilities16) return -1;
2270 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2272 /* If DC_PAPERSIZE map POINT16s to POINTs */
2273 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2274 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2275 POINT *pt = (POINT *)pOutput;
2276 INT i;
2277 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2278 for(i = 0; i < ret; i++, pt++)
2280 pt->x = tmp[i].x;
2281 pt->y = tmp[i].y;
2283 HeapFree( GetProcessHeap(), 0, tmp );
2285 return ret;
2289 /*****************************************************************************
2290 * DeviceCapabilitiesW [WINSPOOL.@]
2292 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2295 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2296 WORD fwCapability, LPWSTR pOutput,
2297 const DEVMODEW *pDevMode)
2299 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2300 LPSTR pDeviceA = strdupWtoA(pDevice);
2301 LPSTR pPortA = strdupWtoA(pPort);
2302 INT ret;
2304 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability, pOutput, pDevMode);
2306 if(pOutput && (fwCapability == DC_BINNAMES ||
2307 fwCapability == DC_FILEDEPENDENCIES ||
2308 fwCapability == DC_PAPERNAMES)) {
2309 /* These need A -> W translation */
2310 INT size = 0, i;
2311 LPSTR pOutputA;
2312 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2313 dmA);
2314 if(ret == -1)
2315 return ret;
2316 switch(fwCapability) {
2317 case DC_BINNAMES:
2318 size = 24;
2319 break;
2320 case DC_PAPERNAMES:
2321 case DC_FILEDEPENDENCIES:
2322 size = 64;
2323 break;
2325 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2326 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2327 dmA);
2328 for(i = 0; i < ret; i++)
2329 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2330 pOutput + (i * size), size);
2331 HeapFree(GetProcessHeap(), 0, pOutputA);
2332 } else {
2333 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2334 (LPSTR)pOutput, dmA);
2336 HeapFree(GetProcessHeap(),0,pPortA);
2337 HeapFree(GetProcessHeap(),0,pDeviceA);
2338 HeapFree(GetProcessHeap(),0,dmA);
2339 return ret;
2342 /******************************************************************
2343 * DocumentPropertiesA [WINSPOOL.@]
2345 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2347 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2348 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2349 LPDEVMODEA pDevModeInput,DWORD fMode )
2351 LPSTR lpName = pDeviceName, dupname = NULL;
2352 static CHAR port[] = "LPT1:";
2353 LONG ret;
2355 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2356 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2359 if(!pDeviceName || !*pDeviceName) {
2360 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2361 if(!lpNameW) {
2362 ERR("no name from hPrinter?\n");
2363 SetLastError(ERROR_INVALID_HANDLE);
2364 return -1;
2366 lpName = dupname = strdupWtoA(lpNameW);
2369 if (!GDI_CallExtDeviceMode16)
2371 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2372 (LPCSTR)102 );
2373 if (!GDI_CallExtDeviceMode16) {
2374 ERR("No CallExtDeviceMode16?\n");
2375 ret = -1;
2376 goto end;
2379 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2380 pDevModeInput, NULL, fMode);
2382 end:
2383 HeapFree(GetProcessHeap(), 0, dupname);
2384 return ret;
2388 /*****************************************************************************
2389 * DocumentPropertiesW (WINSPOOL.@)
2391 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2393 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2394 LPWSTR pDeviceName,
2395 LPDEVMODEW pDevModeOutput,
2396 LPDEVMODEW pDevModeInput, DWORD fMode)
2399 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2400 LPDEVMODEA pDevModeInputA;
2401 LPDEVMODEA pDevModeOutputA = NULL;
2402 LONG ret;
2404 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2405 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2406 fMode);
2407 if(pDevModeOutput) {
2408 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2409 if(ret < 0) return ret;
2410 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2412 pDevModeInputA = (fMode & DM_IN_BUFFER) ? DEVMODEdupWtoA(pDevModeInput) : NULL;
2413 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2414 pDevModeInputA, fMode);
2415 if(pDevModeOutput) {
2416 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2417 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2419 if(fMode == 0 && ret > 0)
2420 ret += (CCHDEVICENAME + CCHFORMNAME);
2421 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2422 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2423 return ret;
2426 /*****************************************************************************
2427 * IsValidDevmodeA [WINSPOOL.@]
2429 * Validate a DEVMODE structure and fix errors if possible.
2432 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2434 FIXME("(%p,%ld): stub\n", pDevMode, size);
2436 if(!pDevMode)
2437 return FALSE;
2439 return TRUE;
2442 /*****************************************************************************
2443 * IsValidDevmodeW [WINSPOOL.@]
2445 * Validate a DEVMODE structure and fix errors if possible.
2448 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2450 FIXME("(%p,%ld): stub\n", pDevMode, size);
2452 if(!pDevMode)
2453 return FALSE;
2455 return TRUE;
2458 /******************************************************************
2459 * OpenPrinterA [WINSPOOL.@]
2461 * See OpenPrinterW.
2464 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2465 LPPRINTER_DEFAULTSA pDefault)
2467 UNICODE_STRING lpPrinterNameW;
2468 UNICODE_STRING usBuffer;
2469 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2470 PWSTR pwstrPrinterNameW;
2471 BOOL ret;
2473 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName), phPrinter, pDefault);
2475 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2477 if(pDefault) {
2478 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2479 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2480 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2481 pDefaultW = &DefaultW;
2483 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2484 if(pDefault) {
2485 RtlFreeUnicodeString(&usBuffer);
2486 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2488 RtlFreeUnicodeString(&lpPrinterNameW);
2489 return ret;
2492 /******************************************************************
2493 * OpenPrinterW [WINSPOOL.@]
2495 * Open a Printer / Printserver or a Printer-Object
2497 * PARAMS
2498 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2499 * phPrinter [O] The resulting Handle is stored here
2500 * pDefault [I] PTR to Default Printer Settings or NULL
2502 * RETURNS
2503 * Success: TRUE
2504 * Failure: FALSE
2506 * NOTES
2507 * lpPrinterName is one of:
2508 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2509 *| Printer: "PrinterName"
2510 *| Printer-Object: "PrinterName,Job xxx"
2511 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2512 *| XcvPort: "Servername,XcvPort PortName"
2514 * BUGS
2515 *| Printer-Object not supported
2516 *| pDefaults is ignored
2519 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2521 HKEY key;
2523 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2525 if(!phPrinter) {
2526 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2527 SetLastError(ERROR_INVALID_PARAMETER);
2528 return FALSE;
2531 /* Get the unique handle of the printer or Printserver */
2532 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2534 if (*phPrinter && WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key ) == ERROR_SUCCESS)
2536 DWORD deleting = 0, size = sizeof( deleting ), type;
2537 DWORD status;
2538 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2539 WaitForSingleObject( init_mutex, INFINITE );
2540 status = get_dword_from_reg( key, StatusW );
2541 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2542 ReleaseMutex( init_mutex );
2543 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2544 update_driver( *phPrinter );
2545 RegCloseKey( key );
2548 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2549 return (*phPrinter != 0);
2552 /******************************************************************
2553 * AddMonitorA [WINSPOOL.@]
2555 * See AddMonitorW.
2558 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2560 LPWSTR nameW = NULL;
2561 INT len;
2562 BOOL res;
2563 LPMONITOR_INFO_2A mi2a;
2564 MONITOR_INFO_2W mi2w;
2566 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2567 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2568 debugstr_a(mi2a ? mi2a->pName : NULL),
2569 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2570 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2572 if (Level != 2) {
2573 SetLastError(ERROR_INVALID_LEVEL);
2574 return FALSE;
2577 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2578 if (mi2a == NULL) {
2579 return FALSE;
2582 if (pName) {
2583 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2584 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2585 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2588 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2589 if (mi2a->pName) {
2590 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2591 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2592 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2594 if (mi2a->pEnvironment) {
2595 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2596 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2597 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2599 if (mi2a->pDLLName) {
2600 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2601 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2602 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2605 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2607 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2608 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2609 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2611 HeapFree(GetProcessHeap(), 0, nameW);
2612 return (res);
2615 /******************************************************************************
2616 * AddMonitorW [WINSPOOL.@]
2618 * Install a Printmonitor
2620 * PARAMS
2621 * pName [I] Servername or NULL (local Computer)
2622 * Level [I] Structure-Level (Must be 2)
2623 * pMonitors [I] PTR to MONITOR_INFO_2
2625 * RETURNS
2626 * Success: TRUE
2627 * Failure: FALSE
2629 * NOTES
2630 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2633 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2635 LPMONITOR_INFO_2W mi2w;
2637 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2638 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2639 debugstr_w(mi2w ? mi2w->pName : NULL),
2640 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2641 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2643 if ((backend == NULL) && !load_backend()) return FALSE;
2645 if (Level != 2) {
2646 SetLastError(ERROR_INVALID_LEVEL);
2647 return FALSE;
2650 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2651 if (mi2w == NULL) {
2652 return FALSE;
2655 return backend->fpAddMonitor(pName, Level, pMonitors);
2658 /******************************************************************
2659 * DeletePrinterDriverA [WINSPOOL.@]
2662 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2664 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2667 /******************************************************************
2668 * DeletePrinterDriverW [WINSPOOL.@]
2671 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2673 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2676 /******************************************************************
2677 * DeleteMonitorA [WINSPOOL.@]
2679 * See DeleteMonitorW.
2682 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2684 LPWSTR nameW = NULL;
2685 LPWSTR EnvironmentW = NULL;
2686 LPWSTR MonitorNameW = NULL;
2687 BOOL res;
2688 INT len;
2690 if (pName) {
2691 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2692 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2693 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2696 if (pEnvironment) {
2697 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2698 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2699 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2701 if (pMonitorName) {
2702 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2703 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2704 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2707 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2709 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2710 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2711 HeapFree(GetProcessHeap(), 0, nameW);
2712 return (res);
2715 /******************************************************************
2716 * DeleteMonitorW [WINSPOOL.@]
2718 * Delete a specific Printmonitor from a Printing-Environment
2720 * PARAMS
2721 * pName [I] Servername or NULL (local Computer)
2722 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2723 * pMonitorName [I] Name of the Monitor, that should be deleted
2725 * RETURNS
2726 * Success: TRUE
2727 * Failure: FALSE
2729 * NOTES
2730 * pEnvironment is ignored in Windows for the local Computer.
2733 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2736 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2737 debugstr_w(pMonitorName));
2739 if ((backend == NULL) && !load_backend()) return FALSE;
2741 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2745 /******************************************************************
2746 * DeletePortA [WINSPOOL.@]
2748 * See DeletePortW.
2751 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2753 LPWSTR nameW = NULL;
2754 LPWSTR portW = NULL;
2755 INT len;
2756 DWORD res;
2758 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2760 /* convert servername to unicode */
2761 if (pName) {
2762 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2763 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2764 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2767 /* convert portname to unicode */
2768 if (pPortName) {
2769 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2770 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2771 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2774 res = DeletePortW(nameW, hWnd, portW);
2775 HeapFree(GetProcessHeap(), 0, nameW);
2776 HeapFree(GetProcessHeap(), 0, portW);
2777 return res;
2780 /******************************************************************
2781 * DeletePortW [WINSPOOL.@]
2783 * Delete a specific Port
2785 * PARAMS
2786 * pName [I] Servername or NULL (local Computer)
2787 * hWnd [I] Handle to parent Window for the Dialog-Box
2788 * pPortName [I] Name of the Port, that should be deleted
2790 * RETURNS
2791 * Success: TRUE
2792 * Failure: FALSE
2795 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2797 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2799 if ((backend == NULL) && !load_backend()) return FALSE;
2801 if (!pPortName) {
2802 SetLastError(RPC_X_NULL_REF_POINTER);
2803 return FALSE;
2806 return backend->fpDeletePort(pName, hWnd, pPortName);
2809 /******************************************************************************
2810 * WritePrinter [WINSPOOL.@]
2812 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2814 opened_printer_t *printer;
2815 BOOL ret = FALSE;
2817 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2819 EnterCriticalSection(&printer_handles_cs);
2820 printer = get_opened_printer(hPrinter);
2821 if(!printer)
2823 SetLastError(ERROR_INVALID_HANDLE);
2824 goto end;
2827 if(!printer->doc)
2829 SetLastError(ERROR_SPL_NO_STARTDOC);
2830 goto end;
2833 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2834 end:
2835 LeaveCriticalSection(&printer_handles_cs);
2836 return ret;
2839 /*****************************************************************************
2840 * AddFormA [WINSPOOL.@]
2842 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2844 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2845 return TRUE;
2848 /*****************************************************************************
2849 * AddFormW [WINSPOOL.@]
2851 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2853 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2854 return TRUE;
2857 /*****************************************************************************
2858 * AddJobA [WINSPOOL.@]
2860 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2862 BOOL ret;
2863 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2864 DWORD needed;
2866 if(Level != 1) {
2867 SetLastError(ERROR_INVALID_LEVEL);
2868 return FALSE;
2871 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2873 if(ret) {
2874 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2875 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2876 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2877 if(*pcbNeeded > cbBuf) {
2878 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2879 ret = FALSE;
2880 } else {
2881 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2882 addjobA->JobId = addjobW->JobId;
2883 addjobA->Path = (char *)(addjobA + 1);
2884 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2887 return ret;
2890 /*****************************************************************************
2891 * AddJobW [WINSPOOL.@]
2893 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2895 opened_printer_t *printer;
2896 job_t *job;
2897 BOOL ret = FALSE;
2898 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2899 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2900 WCHAR path[MAX_PATH], filename[MAX_PATH];
2901 DWORD len;
2902 ADDJOB_INFO_1W *addjob;
2904 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2906 EnterCriticalSection(&printer_handles_cs);
2908 printer = get_opened_printer(hPrinter);
2910 if(!printer) {
2911 SetLastError(ERROR_INVALID_HANDLE);
2912 goto end;
2915 if(Level != 1) {
2916 SetLastError(ERROR_INVALID_LEVEL);
2917 goto end;
2920 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2921 if(!job)
2922 goto end;
2924 job->job_id = InterlockedIncrement(&next_job_id);
2926 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2927 if(path[len - 1] != '\\')
2928 path[len++] = '\\';
2929 memcpy(path + len, spool_path, sizeof(spool_path));
2930 sprintfW(filename, fmtW, path, job->job_id);
2932 len = strlenW(filename);
2933 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2934 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2935 job->portname = NULL;
2936 job->document_title = strdupW(default_doc_title);
2937 job->printer_name = strdupW(printer->name);
2938 job->devmode = dup_devmode( printer->devmode );
2939 list_add_tail(&printer->queue->jobs, &job->entry);
2941 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2942 if(*pcbNeeded <= cbBuf) {
2943 addjob = (ADDJOB_INFO_1W*)pData;
2944 addjob->JobId = job->job_id;
2945 addjob->Path = (WCHAR *)(addjob + 1);
2946 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2947 ret = TRUE;
2948 } else
2949 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2951 end:
2952 LeaveCriticalSection(&printer_handles_cs);
2953 return ret;
2956 /*****************************************************************************
2957 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2959 * Return the PATH for the Print-Processors
2961 * See GetPrintProcessorDirectoryW.
2965 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2966 DWORD level, LPBYTE Info,
2967 DWORD cbBuf, LPDWORD pcbNeeded)
2969 LPWSTR serverW = NULL;
2970 LPWSTR envW = NULL;
2971 BOOL ret;
2972 INT len;
2974 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2975 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2978 if (server) {
2979 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2980 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2981 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2984 if (env) {
2985 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2986 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2987 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2990 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2991 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2993 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2994 cbBuf, pcbNeeded);
2996 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2997 cbBuf, NULL, NULL) > 0;
3000 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3001 HeapFree(GetProcessHeap(), 0, envW);
3002 HeapFree(GetProcessHeap(), 0, serverW);
3003 return ret;
3006 /*****************************************************************************
3007 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3009 * Return the PATH for the Print-Processors
3011 * PARAMS
3012 * server [I] Servername (NT only) or NULL (local Computer)
3013 * env [I] Printing-Environment (see below) or NULL (Default)
3014 * level [I] Structure-Level (must be 1)
3015 * Info [O] PTR to Buffer that receives the Result
3016 * cbBuf [I] Size of Buffer at "Info"
3017 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3018 * required for the Buffer at "Info"
3020 * RETURNS
3021 * Success: TRUE and in pcbNeeded the Bytes used in Info
3022 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3023 * if cbBuf is too small
3025 * Native Values returned in Info on Success:
3026 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3027 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3028 *| win9x(Windows 4.0): "%winsysdir%"
3030 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3032 * BUGS
3033 * Only NULL or "" is supported for server
3036 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3037 DWORD level, LPBYTE Info,
3038 DWORD cbBuf, LPDWORD pcbNeeded)
3041 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3042 Info, cbBuf, pcbNeeded);
3044 if ((backend == NULL) && !load_backend()) return FALSE;
3046 if (level != 1) {
3047 /* (Level != 1) is ignored in win9x */
3048 SetLastError(ERROR_INVALID_LEVEL);
3049 return FALSE;
3052 if (pcbNeeded == NULL) {
3053 /* (pcbNeeded == NULL) is ignored in win9x */
3054 SetLastError(RPC_X_NULL_REF_POINTER);
3055 return FALSE;
3058 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3061 /*****************************************************************************
3062 * WINSPOOL_OpenDriverReg [internal]
3064 * opens the registry for the printer drivers depending on the given input
3065 * variable pEnvironment
3067 * RETURNS:
3068 * the opened hkey on success
3069 * NULL on error
3071 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3073 HKEY retval = NULL;
3074 LPWSTR buffer;
3075 const printenv_t * env;
3077 TRACE("(%s)\n", debugstr_w(pEnvironment));
3079 env = validate_envW(pEnvironment);
3080 if (!env) return NULL;
3082 buffer = HeapAlloc( GetProcessHeap(), 0,
3083 (strlenW(DriversW) + strlenW(env->envname) +
3084 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3085 if(buffer) {
3086 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3087 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3088 HeapFree(GetProcessHeap(), 0, buffer);
3090 return retval;
3093 /*****************************************************************************
3094 * set_devices_and_printerports [internal]
3096 * set the [Devices] and [PrinterPorts] entries for a printer.
3099 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3101 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3102 WCHAR *devline;
3103 HKEY hkey;
3105 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3107 /* FIXME: the driver must change to "winspool" */
3108 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3109 if (devline) {
3110 lstrcpyW(devline, driver_nt);
3111 lstrcatW(devline, commaW);
3112 lstrcatW(devline, pi->pPortName);
3114 TRACE("using %s\n", debugstr_w(devline));
3115 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
3116 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3117 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3118 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3119 RegCloseKey(hkey);
3122 lstrcatW(devline, timeout_15_45);
3123 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
3124 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3125 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3126 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3127 RegCloseKey(hkey);
3129 HeapFree(GetProcessHeap(), 0, devline);
3133 /*****************************************************************************
3134 * AddPrinterW [WINSPOOL.@]
3136 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3138 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3139 LPDEVMODEW dm;
3140 HANDLE retval;
3141 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3142 LONG size;
3144 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3146 if(pName != NULL) {
3147 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3148 SetLastError(ERROR_INVALID_PARAMETER);
3149 return 0;
3151 if(Level != 2) {
3152 ERR("Level = %d, unsupported!\n", Level);
3153 SetLastError(ERROR_INVALID_LEVEL);
3154 return 0;
3156 if(!pPrinter) {
3157 SetLastError(ERROR_INVALID_PARAMETER);
3158 return 0;
3160 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3161 ERROR_SUCCESS) {
3162 ERR("Can't create Printers key\n");
3163 return 0;
3165 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3166 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3167 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3168 RegCloseKey(hkeyPrinter);
3169 RegCloseKey(hkeyPrinters);
3170 return 0;
3172 RegCloseKey(hkeyPrinter);
3174 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3175 if(!hkeyDrivers) {
3176 ERR("Can't create Drivers key\n");
3177 RegCloseKey(hkeyPrinters);
3178 return 0;
3180 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3181 ERROR_SUCCESS) {
3182 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3183 RegCloseKey(hkeyPrinters);
3184 RegCloseKey(hkeyDrivers);
3185 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3186 return 0;
3188 RegCloseKey(hkeyDriver);
3189 RegCloseKey(hkeyDrivers);
3191 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3192 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3193 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3194 RegCloseKey(hkeyPrinters);
3195 return 0;
3198 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3199 ERROR_SUCCESS) {
3200 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3201 SetLastError(ERROR_INVALID_PRINTER_NAME);
3202 RegCloseKey(hkeyPrinters);
3203 return 0;
3206 set_devices_and_printerports(pi);
3208 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3209 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3210 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3211 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3212 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3213 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3214 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3215 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3216 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3217 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3218 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3219 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3220 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3221 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3222 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3223 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3224 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3225 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3227 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3229 if (size < 0)
3231 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3232 size = sizeof(DEVMODEW);
3234 if(pi->pDevMode)
3235 dm = pi->pDevMode;
3236 else
3238 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3239 dm->dmSize = size;
3240 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3242 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3243 HeapFree( GetProcessHeap(), 0, dm );
3244 dm = NULL;
3246 else
3248 /* set devmode to printer name */
3249 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3253 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3254 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3256 RegCloseKey(hkeyPrinter);
3257 RegCloseKey(hkeyPrinters);
3258 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3259 ERR("OpenPrinter failing\n");
3260 return 0;
3262 return retval;
3265 /*****************************************************************************
3266 * AddPrinterA [WINSPOOL.@]
3268 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3270 UNICODE_STRING pNameW;
3271 PWSTR pwstrNameW;
3272 PRINTER_INFO_2W *piW;
3273 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3274 HANDLE ret;
3276 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3277 if(Level != 2) {
3278 ERR("Level = %d, unsupported!\n", Level);
3279 SetLastError(ERROR_INVALID_LEVEL);
3280 return 0;
3282 pwstrNameW = asciitounicode(&pNameW,pName);
3283 piW = printer_info_AtoW( piA, Level );
3285 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3287 free_printer_info( piW, Level );
3288 RtlFreeUnicodeString(&pNameW);
3289 return ret;
3293 /*****************************************************************************
3294 * ClosePrinter [WINSPOOL.@]
3296 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3298 UINT_PTR i = (UINT_PTR)hPrinter;
3299 opened_printer_t *printer = NULL;
3300 BOOL ret = FALSE;
3302 TRACE("(%p)\n", hPrinter);
3304 EnterCriticalSection(&printer_handles_cs);
3306 if ((i > 0) && (i <= nb_printer_handles))
3307 printer = printer_handles[i - 1];
3310 if(printer)
3312 struct list *cursor, *cursor2;
3314 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3316 if (printer->backend_printer) {
3317 backend->fpClosePrinter(printer->backend_printer);
3320 if(printer->doc)
3321 EndDocPrinter(hPrinter);
3323 if(InterlockedDecrement(&printer->queue->ref) == 0)
3325 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3327 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3328 ScheduleJob(hPrinter, job->job_id);
3330 HeapFree(GetProcessHeap(), 0, printer->queue);
3333 free_printer_entry( printer );
3334 printer_handles[i - 1] = NULL;
3335 ret = TRUE;
3337 LeaveCriticalSection(&printer_handles_cs);
3338 return ret;
3341 /*****************************************************************************
3342 * DeleteFormA [WINSPOOL.@]
3344 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3346 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3347 return TRUE;
3350 /*****************************************************************************
3351 * DeleteFormW [WINSPOOL.@]
3353 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3355 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3356 return TRUE;
3359 /*****************************************************************************
3360 * DeletePrinter [WINSPOOL.@]
3362 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3364 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3365 HKEY hkeyPrinters, hkey;
3366 WCHAR def[MAX_PATH];
3367 DWORD size = sizeof( def ) / sizeof( def[0] );
3369 if(!lpNameW) {
3370 SetLastError(ERROR_INVALID_HANDLE);
3371 return FALSE;
3373 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3374 RegDeleteTreeW(hkeyPrinters, lpNameW);
3375 RegCloseKey(hkeyPrinters);
3377 WriteProfileStringW(devicesW, lpNameW, NULL);
3378 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3380 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3381 RegDeleteValueW(hkey, lpNameW);
3382 RegCloseKey(hkey);
3385 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3386 RegDeleteValueW(hkey, lpNameW);
3387 RegCloseKey(hkey);
3390 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3392 WriteProfileStringW( windowsW, deviceW, NULL );
3393 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3395 RegDeleteValueW( hkey, deviceW );
3396 RegCloseKey( hkey );
3398 SetDefaultPrinterW( NULL );
3401 return TRUE;
3404 /*****************************************************************************
3405 * SetPrinterA [WINSPOOL.@]
3407 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3409 BYTE *dataW = data;
3410 BOOL ret;
3412 if (level != 0)
3414 dataW = printer_info_AtoW( data, level );
3415 if (!dataW) return FALSE;
3418 ret = SetPrinterW( printer, level, dataW, command );
3420 if (dataW != data) free_printer_info( dataW, level );
3422 return ret;
3425 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3427 set_reg_szW( key, NameW, pi->pPrinterName );
3428 set_reg_szW( key, Share_NameW, pi->pShareName );
3429 set_reg_szW( key, PortW, pi->pPortName );
3430 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3431 set_reg_szW( key, DescriptionW, pi->pComment );
3432 set_reg_szW( key, LocationW, pi->pLocation );
3434 if (pi->pDevMode)
3435 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3437 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3438 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3439 set_reg_szW( key, DatatypeW, pi->pDatatype );
3440 set_reg_szW( key, ParametersW, pi->pParameters );
3442 set_reg_DWORD( key, AttributesW, pi->Attributes );
3443 set_reg_DWORD( key, PriorityW, pi->Priority );
3444 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3445 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3446 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3449 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3451 if (!pi->pDevMode) return FALSE;
3453 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3454 return TRUE;
3457 /******************************************************************************
3458 * SetPrinterW [WINSPOOL.@]
3460 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3462 HKEY key;
3463 BOOL ret = FALSE;
3465 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3467 if (command != 0) FIXME( "Ignoring command %d\n", command );
3469 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3470 return FALSE;
3472 switch (level)
3474 case 2:
3476 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3477 set_printer_2( key, pi2 );
3478 ret = TRUE;
3479 break;
3482 case 9:
3484 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3485 ret = set_printer_9( key, pi );
3486 break;
3489 default:
3490 FIXME( "Unimplemented level %d\n", level );
3491 SetLastError( ERROR_INVALID_LEVEL );
3494 RegCloseKey( key );
3495 return ret;
3498 /*****************************************************************************
3499 * SetJobA [WINSPOOL.@]
3501 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3502 LPBYTE pJob, DWORD Command)
3504 BOOL ret;
3505 LPBYTE JobW;
3506 UNICODE_STRING usBuffer;
3508 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3510 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3511 are all ignored by SetJob, so we don't bother copying them */
3512 switch(Level)
3514 case 0:
3515 JobW = NULL;
3516 break;
3517 case 1:
3519 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3520 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3522 JobW = (LPBYTE)info1W;
3523 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3524 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3525 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3526 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3527 info1W->Status = info1A->Status;
3528 info1W->Priority = info1A->Priority;
3529 info1W->Position = info1A->Position;
3530 info1W->PagesPrinted = info1A->PagesPrinted;
3531 break;
3533 case 2:
3535 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3536 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3538 JobW = (LPBYTE)info2W;
3539 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3540 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3541 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3542 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3543 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3544 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3545 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3546 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3547 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3548 info2W->Status = info2A->Status;
3549 info2W->Priority = info2A->Priority;
3550 info2W->Position = info2A->Position;
3551 info2W->StartTime = info2A->StartTime;
3552 info2W->UntilTime = info2A->UntilTime;
3553 info2W->PagesPrinted = info2A->PagesPrinted;
3554 break;
3556 case 3:
3557 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3558 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3559 break;
3560 default:
3561 SetLastError(ERROR_INVALID_LEVEL);
3562 return FALSE;
3565 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3567 switch(Level)
3569 case 1:
3571 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3572 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3573 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3574 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3575 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3576 break;
3578 case 2:
3580 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3581 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3582 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3583 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3584 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3585 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3586 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3587 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3588 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3589 break;
3592 HeapFree(GetProcessHeap(), 0, JobW);
3594 return ret;
3597 /*****************************************************************************
3598 * SetJobW [WINSPOOL.@]
3600 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3601 LPBYTE pJob, DWORD Command)
3603 BOOL ret = FALSE;
3604 job_t *job;
3606 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3607 FIXME("Ignoring everything other than document title\n");
3609 EnterCriticalSection(&printer_handles_cs);
3610 job = get_job(hPrinter, JobId);
3611 if(!job)
3612 goto end;
3614 switch(Level)
3616 case 0:
3617 break;
3618 case 1:
3620 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3621 HeapFree(GetProcessHeap(), 0, job->document_title);
3622 job->document_title = strdupW(info1->pDocument);
3623 break;
3625 case 2:
3627 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3628 HeapFree(GetProcessHeap(), 0, job->document_title);
3629 job->document_title = strdupW(info2->pDocument);
3630 HeapFree(GetProcessHeap(), 0, job->devmode);
3631 job->devmode = dup_devmode( info2->pDevMode );
3632 break;
3634 case 3:
3635 break;
3636 default:
3637 SetLastError(ERROR_INVALID_LEVEL);
3638 goto end;
3640 ret = TRUE;
3641 end:
3642 LeaveCriticalSection(&printer_handles_cs);
3643 return ret;
3646 /*****************************************************************************
3647 * EndDocPrinter [WINSPOOL.@]
3649 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3651 opened_printer_t *printer;
3652 BOOL ret = FALSE;
3653 TRACE("(%p)\n", hPrinter);
3655 EnterCriticalSection(&printer_handles_cs);
3657 printer = get_opened_printer(hPrinter);
3658 if(!printer)
3660 SetLastError(ERROR_INVALID_HANDLE);
3661 goto end;
3664 if(!printer->doc)
3666 SetLastError(ERROR_SPL_NO_STARTDOC);
3667 goto end;
3670 CloseHandle(printer->doc->hf);
3671 ScheduleJob(hPrinter, printer->doc->job_id);
3672 HeapFree(GetProcessHeap(), 0, printer->doc);
3673 printer->doc = NULL;
3674 ret = TRUE;
3675 end:
3676 LeaveCriticalSection(&printer_handles_cs);
3677 return ret;
3680 /*****************************************************************************
3681 * EndPagePrinter [WINSPOOL.@]
3683 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3685 FIXME("(%p): stub\n", hPrinter);
3686 return TRUE;
3689 /*****************************************************************************
3690 * StartDocPrinterA [WINSPOOL.@]
3692 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3694 UNICODE_STRING usBuffer;
3695 DOC_INFO_2W doc2W;
3696 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3697 DWORD ret;
3699 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3700 or one (DOC_INFO_3) extra DWORDs */
3702 switch(Level) {
3703 case 2:
3704 doc2W.JobId = doc2->JobId;
3705 /* fall through */
3706 case 3:
3707 doc2W.dwMode = doc2->dwMode;
3708 /* fall through */
3709 case 1:
3710 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3711 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3712 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3713 break;
3715 default:
3716 SetLastError(ERROR_INVALID_LEVEL);
3717 return FALSE;
3720 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3722 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3723 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3724 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3726 return ret;
3729 /*****************************************************************************
3730 * StartDocPrinterW [WINSPOOL.@]
3732 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3734 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3735 opened_printer_t *printer;
3736 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3737 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3738 JOB_INFO_1W job_info;
3739 DWORD needed, ret = 0;
3740 HANDLE hf;
3741 WCHAR *filename;
3742 job_t *job;
3744 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3745 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3746 debugstr_w(doc->pDatatype));
3748 if(Level < 1 || Level > 3)
3750 SetLastError(ERROR_INVALID_LEVEL);
3751 return 0;
3754 EnterCriticalSection(&printer_handles_cs);
3755 printer = get_opened_printer(hPrinter);
3756 if(!printer)
3758 SetLastError(ERROR_INVALID_HANDLE);
3759 goto end;
3762 if(printer->doc)
3764 SetLastError(ERROR_INVALID_PRINTER_STATE);
3765 goto end;
3768 /* Even if we're printing to a file we still add a print job, we'll
3769 just ignore the spool file name */
3771 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3773 ERR("AddJob failed gle %u\n", GetLastError());
3774 goto end;
3777 /* use pOutputFile only, when it is a real filename */
3778 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3779 filename = doc->pOutputFile;
3780 else
3781 filename = addjob->Path;
3783 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3784 if(hf == INVALID_HANDLE_VALUE)
3785 goto end;
3787 memset(&job_info, 0, sizeof(job_info));
3788 job_info.pDocument = doc->pDocName;
3789 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3791 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3792 printer->doc->hf = hf;
3793 ret = printer->doc->job_id = addjob->JobId;
3794 job = get_job(hPrinter, ret);
3795 job->portname = strdupW(doc->pOutputFile);
3797 end:
3798 LeaveCriticalSection(&printer_handles_cs);
3800 return ret;
3803 /*****************************************************************************
3804 * StartPagePrinter [WINSPOOL.@]
3806 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3808 FIXME("(%p): stub\n", hPrinter);
3809 return TRUE;
3812 /*****************************************************************************
3813 * GetFormA [WINSPOOL.@]
3815 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3816 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3818 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3819 Level,pForm,cbBuf,pcbNeeded);
3820 return FALSE;
3823 /*****************************************************************************
3824 * GetFormW [WINSPOOL.@]
3826 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3827 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3829 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3830 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3831 return FALSE;
3834 /*****************************************************************************
3835 * SetFormA [WINSPOOL.@]
3837 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3838 LPBYTE pForm)
3840 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3841 return FALSE;
3844 /*****************************************************************************
3845 * SetFormW [WINSPOOL.@]
3847 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3848 LPBYTE pForm)
3850 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3851 return FALSE;
3854 /*****************************************************************************
3855 * ReadPrinter [WINSPOOL.@]
3857 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3858 LPDWORD pNoBytesRead)
3860 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3861 return FALSE;
3864 /*****************************************************************************
3865 * ResetPrinterA [WINSPOOL.@]
3867 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3869 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3870 return FALSE;
3873 /*****************************************************************************
3874 * ResetPrinterW [WINSPOOL.@]
3876 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3878 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3879 return FALSE;
3882 /*****************************************************************************
3883 * get_filename_from_reg [internal]
3885 * Get ValueName from hkey storing result in out
3886 * when the Value in the registry has only a filename, use driverdir as prefix
3887 * outlen is space left in out
3888 * String is stored either as unicode or ascii
3892 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3893 LPBYTE out, DWORD outlen, LPDWORD needed)
3895 WCHAR filename[MAX_PATH];
3896 DWORD size;
3897 DWORD type;
3898 LONG ret;
3899 LPWSTR buffer = filename;
3900 LPWSTR ptr;
3902 *needed = 0;
3903 size = sizeof(filename);
3904 buffer[0] = '\0';
3905 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3906 if (ret == ERROR_MORE_DATA) {
3907 TRACE("need dynamic buffer: %u\n", size);
3908 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3909 if (!buffer) {
3910 /* No Memory is bad */
3911 return FALSE;
3913 buffer[0] = '\0';
3914 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3917 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3918 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3919 return FALSE;
3922 ptr = buffer;
3923 while (ptr) {
3924 /* do we have a full path ? */
3925 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3926 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3928 if (!ret) {
3929 /* we must build the full Path */
3930 *needed += dirlen;
3931 if ((out) && (outlen > dirlen)) {
3932 lstrcpyW((LPWSTR)out, driverdir);
3933 out += dirlen;
3934 outlen -= dirlen;
3936 else
3937 out = NULL;
3940 /* write the filename */
3941 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3942 if ((out) && (outlen >= size)) {
3943 lstrcpyW((LPWSTR)out, ptr);
3944 out += size;
3945 outlen -= size;
3947 else
3948 out = NULL;
3949 *needed += size;
3950 ptr += lstrlenW(ptr)+1;
3951 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3954 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3956 /* write the multisz-termination */
3957 if (type == REG_MULTI_SZ) {
3958 size = sizeof(WCHAR);
3960 *needed += size;
3961 if (out && (outlen >= size)) {
3962 memset (out, 0, size);
3965 return TRUE;
3968 /*****************************************************************************
3969 * WINSPOOL_GetStringFromReg
3971 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3972 * String is stored as unicode.
3974 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3975 DWORD buflen, DWORD *needed)
3977 DWORD sz = buflen, type;
3978 LONG ret;
3980 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3981 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3982 WARN("Got ret = %d\n", ret);
3983 *needed = 0;
3984 return FALSE;
3986 /* add space for terminating '\0' */
3987 sz += sizeof(WCHAR);
3988 *needed = sz;
3990 if (ptr)
3991 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3993 return TRUE;
3996 /*****************************************************************************
3997 * WINSPOOL_GetDefaultDevMode
3999 * Get a default DevMode values for wineps.
4001 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr, DWORD buflen, DWORD *needed)
4003 static const WCHAR winepsW[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4005 if (buflen >= sizeof(DEVMODEW))
4007 DEVMODEW *dm = (DEVMODEW *)ptr;
4009 /* the driver will update registry with real values */
4010 memset(dm, 0, sizeof(*dm));
4011 dm->dmSize = sizeof(*dm);
4012 lstrcpyW(dm->dmDeviceName, winepsW);
4014 *needed = sizeof(DEVMODEW);
4017 /*****************************************************************************
4018 * WINSPOOL_GetDevModeFromReg
4020 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4021 * DevMode is stored either as unicode or ascii.
4023 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4024 LPBYTE ptr,
4025 DWORD buflen, DWORD *needed)
4027 DWORD sz = buflen, type;
4028 LONG ret;
4030 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4031 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4032 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4033 if (sz < sizeof(DEVMODEA))
4035 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4036 return FALSE;
4038 /* ensures that dmSize is not erratically bogus if registry is invalid */
4039 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4040 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4041 sz += (CCHDEVICENAME + CCHFORMNAME);
4042 if (ptr && (buflen >= sz)) {
4043 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4044 memcpy(ptr, dmW, sz);
4045 HeapFree(GetProcessHeap(),0,dmW);
4047 *needed = sz;
4048 return TRUE;
4051 /*********************************************************************
4052 * WINSPOOL_GetPrinter_1
4054 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4056 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4057 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4059 DWORD size, left = cbBuf;
4060 BOOL space = (cbBuf > 0);
4061 LPBYTE ptr = buf;
4063 *pcbNeeded = 0;
4065 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4066 if(space && size <= left) {
4067 pi1->pName = (LPWSTR)ptr;
4068 ptr += size;
4069 left -= size;
4070 } else
4071 space = FALSE;
4072 *pcbNeeded += size;
4075 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4076 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4077 if(space && size <= left) {
4078 pi1->pDescription = (LPWSTR)ptr;
4079 ptr += size;
4080 left -= size;
4081 } else
4082 space = FALSE;
4083 *pcbNeeded += size;
4086 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4087 if(space && size <= left) {
4088 pi1->pComment = (LPWSTR)ptr;
4089 ptr += size;
4090 left -= size;
4091 } else
4092 space = FALSE;
4093 *pcbNeeded += size;
4096 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4098 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4099 memset(pi1, 0, sizeof(*pi1));
4101 return space;
4103 /*********************************************************************
4104 * WINSPOOL_GetPrinter_2
4106 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4108 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4109 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4111 DWORD size, left = cbBuf;
4112 BOOL space = (cbBuf > 0);
4113 LPBYTE ptr = buf;
4115 *pcbNeeded = 0;
4117 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4118 if(space && size <= left) {
4119 pi2->pPrinterName = (LPWSTR)ptr;
4120 ptr += size;
4121 left -= size;
4122 } else
4123 space = FALSE;
4124 *pcbNeeded += size;
4126 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4127 if(space && size <= left) {
4128 pi2->pShareName = (LPWSTR)ptr;
4129 ptr += size;
4130 left -= size;
4131 } else
4132 space = FALSE;
4133 *pcbNeeded += size;
4135 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4136 if(space && size <= left) {
4137 pi2->pPortName = (LPWSTR)ptr;
4138 ptr += size;
4139 left -= size;
4140 } else
4141 space = FALSE;
4142 *pcbNeeded += size;
4144 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4145 if(space && size <= left) {
4146 pi2->pDriverName = (LPWSTR)ptr;
4147 ptr += size;
4148 left -= size;
4149 } else
4150 space = FALSE;
4151 *pcbNeeded += size;
4153 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4154 if(space && size <= left) {
4155 pi2->pComment = (LPWSTR)ptr;
4156 ptr += size;
4157 left -= size;
4158 } else
4159 space = FALSE;
4160 *pcbNeeded += size;
4162 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4163 if(space && size <= left) {
4164 pi2->pLocation = (LPWSTR)ptr;
4165 ptr += size;
4166 left -= size;
4167 } else
4168 space = FALSE;
4169 *pcbNeeded += size;
4171 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4172 if(space && size <= left) {
4173 pi2->pDevMode = (LPDEVMODEW)ptr;
4174 ptr += size;
4175 left -= size;
4176 } else
4177 space = FALSE;
4178 *pcbNeeded += size;
4180 else
4182 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4183 if(space && size <= left) {
4184 pi2->pDevMode = (LPDEVMODEW)ptr;
4185 ptr += size;
4186 left -= size;
4187 } else
4188 space = FALSE;
4189 *pcbNeeded += size;
4191 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4192 if(space && size <= left) {
4193 pi2->pSepFile = (LPWSTR)ptr;
4194 ptr += size;
4195 left -= size;
4196 } else
4197 space = FALSE;
4198 *pcbNeeded += size;
4200 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4201 if(space && size <= left) {
4202 pi2->pPrintProcessor = (LPWSTR)ptr;
4203 ptr += size;
4204 left -= size;
4205 } else
4206 space = FALSE;
4207 *pcbNeeded += size;
4209 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4210 if(space && size <= left) {
4211 pi2->pDatatype = (LPWSTR)ptr;
4212 ptr += size;
4213 left -= size;
4214 } else
4215 space = FALSE;
4216 *pcbNeeded += size;
4218 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4219 if(space && size <= left) {
4220 pi2->pParameters = (LPWSTR)ptr;
4221 ptr += size;
4222 left -= size;
4223 } else
4224 space = FALSE;
4225 *pcbNeeded += size;
4227 if(pi2) {
4228 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4229 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4230 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4231 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4232 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4235 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4236 memset(pi2, 0, sizeof(*pi2));
4238 return space;
4241 /*********************************************************************
4242 * WINSPOOL_GetPrinter_4
4244 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4246 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4247 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4249 DWORD size, left = cbBuf;
4250 BOOL space = (cbBuf > 0);
4251 LPBYTE ptr = buf;
4253 *pcbNeeded = 0;
4255 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4256 if(space && size <= left) {
4257 pi4->pPrinterName = (LPWSTR)ptr;
4258 ptr += size;
4259 left -= size;
4260 } else
4261 space = FALSE;
4262 *pcbNeeded += size;
4264 if(pi4) {
4265 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4268 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4269 memset(pi4, 0, sizeof(*pi4));
4271 return space;
4274 /*********************************************************************
4275 * WINSPOOL_GetPrinter_5
4277 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4279 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4280 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4282 DWORD size, left = cbBuf;
4283 BOOL space = (cbBuf > 0);
4284 LPBYTE ptr = buf;
4286 *pcbNeeded = 0;
4288 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4289 if(space && size <= left) {
4290 pi5->pPrinterName = (LPWSTR)ptr;
4291 ptr += size;
4292 left -= size;
4293 } else
4294 space = FALSE;
4295 *pcbNeeded += size;
4297 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4298 if(space && size <= left) {
4299 pi5->pPortName = (LPWSTR)ptr;
4300 ptr += size;
4301 left -= size;
4302 } else
4303 space = FALSE;
4304 *pcbNeeded += size;
4306 if(pi5) {
4307 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4308 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4309 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4312 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4313 memset(pi5, 0, sizeof(*pi5));
4315 return space;
4318 /*********************************************************************
4319 * WINSPOOL_GetPrinter_7
4321 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4323 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4324 DWORD cbBuf, LPDWORD pcbNeeded)
4326 DWORD size, left = cbBuf;
4327 BOOL space = (cbBuf > 0);
4328 LPBYTE ptr = buf;
4330 *pcbNeeded = 0;
4332 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4334 ptr = NULL;
4335 size = sizeof(pi7->pszObjectGUID);
4337 if (space && size <= left) {
4338 pi7->pszObjectGUID = (LPWSTR)ptr;
4339 ptr += size;
4340 left -= size;
4341 } else
4342 space = FALSE;
4343 *pcbNeeded += size;
4344 if (pi7) {
4345 /* We do not have a Directory Service */
4346 pi7->dwAction = DSPRINT_UNPUBLISH;
4349 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4350 memset(pi7, 0, sizeof(*pi7));
4352 return space;
4355 /*********************************************************************
4356 * WINSPOOL_GetPrinter_9
4358 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4360 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4361 DWORD cbBuf, LPDWORD pcbNeeded)
4363 DWORD size;
4364 BOOL space = (cbBuf > 0);
4366 *pcbNeeded = 0;
4368 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4369 if(space && size <= cbBuf) {
4370 pi9->pDevMode = (LPDEVMODEW)buf;
4371 } else
4372 space = FALSE;
4373 *pcbNeeded += size;
4375 else
4377 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4378 if(space && size <= cbBuf) {
4379 pi9->pDevMode = (LPDEVMODEW)buf;
4380 } else
4381 space = FALSE;
4382 *pcbNeeded += size;
4385 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4386 memset(pi9, 0, sizeof(*pi9));
4388 return space;
4391 /*****************************************************************************
4392 * GetPrinterW [WINSPOOL.@]
4394 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4395 DWORD cbBuf, LPDWORD pcbNeeded)
4397 DWORD size, needed = 0, err;
4398 LPBYTE ptr = NULL;
4399 HKEY hkeyPrinter;
4400 BOOL ret;
4402 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4404 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4405 if (err)
4407 SetLastError( err );
4408 return FALSE;
4411 switch(Level) {
4412 case 2:
4414 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4416 size = sizeof(PRINTER_INFO_2W);
4417 if(size <= cbBuf) {
4418 ptr = pPrinter + size;
4419 cbBuf -= size;
4420 memset(pPrinter, 0, size);
4421 } else {
4422 pi2 = NULL;
4423 cbBuf = 0;
4425 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4426 needed += size;
4427 break;
4430 case 4:
4432 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4434 size = sizeof(PRINTER_INFO_4W);
4435 if(size <= cbBuf) {
4436 ptr = pPrinter + size;
4437 cbBuf -= size;
4438 memset(pPrinter, 0, size);
4439 } else {
4440 pi4 = NULL;
4441 cbBuf = 0;
4443 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4444 needed += size;
4445 break;
4449 case 5:
4451 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4453 size = sizeof(PRINTER_INFO_5W);
4454 if(size <= cbBuf) {
4455 ptr = pPrinter + size;
4456 cbBuf -= size;
4457 memset(pPrinter, 0, size);
4458 } else {
4459 pi5 = NULL;
4460 cbBuf = 0;
4463 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4464 needed += size;
4465 break;
4469 case 6:
4471 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4473 size = sizeof(PRINTER_INFO_6);
4474 if (size <= cbBuf) {
4475 /* FIXME: We do not update the status yet */
4476 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4477 ret = TRUE;
4478 } else {
4479 ret = FALSE;
4482 needed += size;
4483 break;
4486 case 7:
4488 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4490 size = sizeof(PRINTER_INFO_7W);
4491 if (size <= cbBuf) {
4492 ptr = pPrinter + size;
4493 cbBuf -= size;
4494 memset(pPrinter, 0, size);
4495 } else {
4496 pi7 = NULL;
4497 cbBuf = 0;
4500 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4501 needed += size;
4502 break;
4506 case 8:
4507 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4508 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4509 /* fall through */
4510 case 9:
4512 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4514 size = sizeof(PRINTER_INFO_9W);
4515 if(size <= cbBuf) {
4516 ptr = pPrinter + size;
4517 cbBuf -= size;
4518 memset(pPrinter, 0, size);
4519 } else {
4520 pi9 = NULL;
4521 cbBuf = 0;
4524 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4525 needed += size;
4526 break;
4530 default:
4531 FIXME("Unimplemented level %d\n", Level);
4532 SetLastError(ERROR_INVALID_LEVEL);
4533 RegCloseKey(hkeyPrinter);
4534 return FALSE;
4537 RegCloseKey(hkeyPrinter);
4539 TRACE("returning %d needed = %d\n", ret, needed);
4540 if(pcbNeeded) *pcbNeeded = needed;
4541 if(!ret)
4542 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4543 return ret;
4546 /*****************************************************************************
4547 * GetPrinterA [WINSPOOL.@]
4549 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4550 DWORD cbBuf, LPDWORD pcbNeeded)
4552 BOOL ret;
4553 LPBYTE buf = NULL;
4555 if (cbBuf)
4556 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4558 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4559 if (ret)
4560 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4561 HeapFree(GetProcessHeap(), 0, buf);
4563 return ret;
4566 /*****************************************************************************
4567 * WINSPOOL_EnumPrintersW
4569 * Implementation of EnumPrintersW
4571 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4572 DWORD dwLevel, LPBYTE lpbPrinters,
4573 DWORD cbBuf, LPDWORD lpdwNeeded,
4574 LPDWORD lpdwReturned)
4577 HKEY hkeyPrinters, hkeyPrinter;
4578 WCHAR PrinterName[255];
4579 DWORD needed = 0, number = 0;
4580 DWORD used, i, left;
4581 PBYTE pi, buf;
4583 if(lpbPrinters)
4584 memset(lpbPrinters, 0, cbBuf);
4585 if(lpdwReturned)
4586 *lpdwReturned = 0;
4587 if(lpdwNeeded)
4588 *lpdwNeeded = 0;
4590 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4591 if(dwType == PRINTER_ENUM_DEFAULT)
4592 return TRUE;
4594 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4595 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4596 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4597 if (!dwType) {
4598 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4599 return TRUE;
4604 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4605 FIXME("dwType = %08x\n", dwType);
4606 SetLastError(ERROR_INVALID_FLAGS);
4607 return FALSE;
4610 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4611 ERROR_SUCCESS) {
4612 ERR("Can't create Printers key\n");
4613 return FALSE;
4616 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4617 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4618 RegCloseKey(hkeyPrinters);
4619 ERR("Can't query Printers key\n");
4620 return FALSE;
4622 TRACE("Found %d printers\n", number);
4624 switch(dwLevel) {
4625 case 1:
4626 used = number * sizeof(PRINTER_INFO_1W);
4627 break;
4628 case 2:
4629 used = number * sizeof(PRINTER_INFO_2W);
4630 break;
4631 case 4:
4632 used = number * sizeof(PRINTER_INFO_4W);
4633 break;
4634 case 5:
4635 used = number * sizeof(PRINTER_INFO_5W);
4636 break;
4638 default:
4639 SetLastError(ERROR_INVALID_LEVEL);
4640 RegCloseKey(hkeyPrinters);
4641 return FALSE;
4643 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4645 for(i = 0; i < number; i++) {
4646 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4647 ERROR_SUCCESS) {
4648 ERR("Can't enum key number %d\n", i);
4649 RegCloseKey(hkeyPrinters);
4650 return FALSE;
4652 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4653 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4654 ERROR_SUCCESS) {
4655 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4656 RegCloseKey(hkeyPrinters);
4657 return FALSE;
4660 if(cbBuf > used) {
4661 buf = lpbPrinters + used;
4662 left = cbBuf - used;
4663 } else {
4664 buf = NULL;
4665 left = 0;
4668 switch(dwLevel) {
4669 case 1:
4670 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4671 left, &needed);
4672 used += needed;
4673 if(pi) pi += sizeof(PRINTER_INFO_1W);
4674 break;
4675 case 2:
4676 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4677 left, &needed);
4678 used += needed;
4679 if(pi) pi += sizeof(PRINTER_INFO_2W);
4680 break;
4681 case 4:
4682 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4683 left, &needed);
4684 used += needed;
4685 if(pi) pi += sizeof(PRINTER_INFO_4W);
4686 break;
4687 case 5:
4688 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4689 left, &needed);
4690 used += needed;
4691 if(pi) pi += sizeof(PRINTER_INFO_5W);
4692 break;
4693 default:
4694 ERR("Shouldn't be here!\n");
4695 RegCloseKey(hkeyPrinter);
4696 RegCloseKey(hkeyPrinters);
4697 return FALSE;
4699 RegCloseKey(hkeyPrinter);
4701 RegCloseKey(hkeyPrinters);
4703 if(lpdwNeeded)
4704 *lpdwNeeded = used;
4706 if(used > cbBuf) {
4707 if(lpbPrinters)
4708 memset(lpbPrinters, 0, cbBuf);
4709 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4710 return FALSE;
4712 if(lpdwReturned)
4713 *lpdwReturned = number;
4714 SetLastError(ERROR_SUCCESS);
4715 return TRUE;
4719 /******************************************************************
4720 * EnumPrintersW [WINSPOOL.@]
4722 * Enumerates the available printers, print servers and print
4723 * providers, depending on the specified flags, name and level.
4725 * RETURNS:
4727 * If level is set to 1:
4728 * Returns an array of PRINTER_INFO_1 data structures in the
4729 * lpbPrinters buffer.
4731 * If level is set to 2:
4732 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4733 * Returns an array of PRINTER_INFO_2 data structures in the
4734 * lpbPrinters buffer. Note that according to MSDN also an
4735 * OpenPrinter should be performed on every remote printer.
4737 * If level is set to 4 (officially WinNT only):
4738 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4739 * Fast: Only the registry is queried to retrieve printer names,
4740 * no connection to the driver is made.
4741 * Returns an array of PRINTER_INFO_4 data structures in the
4742 * lpbPrinters buffer.
4744 * If level is set to 5 (officially WinNT4/Win9x only):
4745 * Fast: Only the registry is queried to retrieve printer names,
4746 * no connection to the driver is made.
4747 * Returns an array of PRINTER_INFO_5 data structures in the
4748 * lpbPrinters buffer.
4750 * If level set to 3 or 6+:
4751 * returns zero (failure!)
4753 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4754 * for information.
4756 * BUGS:
4757 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4758 * - Only levels 2, 4 and 5 are implemented at the moment.
4759 * - 16-bit printer drivers are not enumerated.
4760 * - Returned amount of bytes used/needed does not match the real Windoze
4761 * implementation (as in this implementation, all strings are part
4762 * of the buffer, whereas Win32 keeps them somewhere else)
4763 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4765 * NOTE:
4766 * - In a regular Wine installation, no registry settings for printers
4767 * exist, which makes this function return an empty list.
4769 BOOL WINAPI EnumPrintersW(
4770 DWORD dwType, /* [in] Types of print objects to enumerate */
4771 LPWSTR lpszName, /* [in] name of objects to enumerate */
4772 DWORD dwLevel, /* [in] type of printer info structure */
4773 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4774 DWORD cbBuf, /* [in] max size of buffer in bytes */
4775 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4776 LPDWORD lpdwReturned /* [out] number of entries returned */
4779 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4780 lpdwNeeded, lpdwReturned);
4783 /******************************************************************
4784 * EnumPrintersA [WINSPOOL.@]
4786 * See EnumPrintersW
4789 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4790 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4792 BOOL ret;
4793 UNICODE_STRING pNameU;
4794 LPWSTR pNameW;
4795 LPBYTE pPrintersW;
4797 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4798 pPrinters, cbBuf, pcbNeeded, pcReturned);
4800 pNameW = asciitounicode(&pNameU, pName);
4802 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4803 MS Office need this */
4804 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4806 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4808 RtlFreeUnicodeString(&pNameU);
4809 if (ret) {
4810 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4812 HeapFree(GetProcessHeap(), 0, pPrintersW);
4813 return ret;
4816 /*****************************************************************************
4817 * WINSPOOL_GetDriverInfoFromReg [internal]
4819 * Enters the information from the registry into the DRIVER_INFO struct
4821 * RETURNS
4822 * zero if the printer driver does not exist in the registry
4823 * (only if Level > 1) otherwise nonzero
4825 static BOOL WINSPOOL_GetDriverInfoFromReg(
4826 HKEY hkeyDrivers,
4827 LPWSTR DriverName,
4828 const printenv_t * env,
4829 DWORD Level,
4830 LPBYTE ptr, /* DRIVER_INFO */
4831 LPBYTE pDriverStrings, /* strings buffer */
4832 DWORD cbBuf, /* size of string buffer */
4833 LPDWORD pcbNeeded) /* space needed for str. */
4835 DWORD size, tmp;
4836 HKEY hkeyDriver;
4837 WCHAR driverdir[MAX_PATH];
4838 DWORD dirlen;
4839 LPBYTE strPtr = pDriverStrings;
4840 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4842 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4843 debugstr_w(DriverName), env,
4844 Level, di, pDriverStrings, cbBuf);
4846 if (di) ZeroMemory(di, di_sizeof[Level]);
4848 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4849 if (*pcbNeeded <= cbBuf)
4850 strcpyW((LPWSTR)strPtr, DriverName);
4852 /* pName for level 1 has a different offset! */
4853 if (Level == 1) {
4854 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4855 return TRUE;
4858 /* .cVersion and .pName for level > 1 */
4859 if (di) {
4860 di->cVersion = env->driverversion;
4861 di->pName = (LPWSTR) strPtr;
4862 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4865 /* Reserve Space for the largest subdir and a Backslash*/
4866 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4867 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4868 /* Should never Fail */
4869 return FALSE;
4871 lstrcatW(driverdir, env->versionsubdir);
4872 lstrcatW(driverdir, backslashW);
4874 /* dirlen must not include the terminating zero */
4875 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4877 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4878 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4879 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4880 return FALSE;
4883 /* pEnvironment */
4884 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4886 *pcbNeeded += size;
4887 if (*pcbNeeded <= cbBuf) {
4888 lstrcpyW((LPWSTR)strPtr, env->envname);
4889 if (di) di->pEnvironment = (LPWSTR)strPtr;
4890 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4893 /* .pDriverPath is the Graphics rendering engine.
4894 The full Path is required to avoid a crash in some apps */
4895 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4896 *pcbNeeded += size;
4897 if (*pcbNeeded <= cbBuf)
4898 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4900 if (di) di->pDriverPath = (LPWSTR)strPtr;
4901 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4904 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4905 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4906 *pcbNeeded += size;
4907 if (*pcbNeeded <= cbBuf)
4908 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4910 if (di) di->pDataFile = (LPWSTR)strPtr;
4911 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4914 /* .pConfigFile is the Driver user Interface */
4915 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4916 *pcbNeeded += size;
4917 if (*pcbNeeded <= cbBuf)
4918 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4920 if (di) di->pConfigFile = (LPWSTR)strPtr;
4921 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4924 if (Level == 2 ) {
4925 RegCloseKey(hkeyDriver);
4926 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4927 return TRUE;
4930 if (Level == 5 ) {
4931 RegCloseKey(hkeyDriver);
4932 FIXME("level 5: incomplete\n");
4933 return TRUE;
4936 /* .pHelpFile */
4937 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4938 *pcbNeeded += size;
4939 if (*pcbNeeded <= cbBuf)
4940 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4942 if (di) di->pHelpFile = (LPWSTR)strPtr;
4943 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4946 /* .pDependentFiles */
4947 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4948 *pcbNeeded += size;
4949 if (*pcbNeeded <= cbBuf)
4950 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4952 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4953 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4955 else if (GetVersion() & 0x80000000) {
4956 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4957 size = 2 * sizeof(WCHAR);
4958 *pcbNeeded += size;
4959 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4961 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4962 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4965 /* .pMonitorName is the optional Language Monitor */
4966 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4967 *pcbNeeded += size;
4968 if (*pcbNeeded <= cbBuf)
4969 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4971 if (di) di->pMonitorName = (LPWSTR)strPtr;
4972 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4975 /* .pDefaultDataType */
4976 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4977 *pcbNeeded += size;
4978 if(*pcbNeeded <= cbBuf)
4979 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4981 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4982 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4985 if (Level == 3 ) {
4986 RegCloseKey(hkeyDriver);
4987 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4988 return TRUE;
4991 /* .pszzPreviousNames */
4992 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4993 *pcbNeeded += size;
4994 if(*pcbNeeded <= cbBuf)
4995 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4997 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4998 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5001 if (Level == 4 ) {
5002 RegCloseKey(hkeyDriver);
5003 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5004 return TRUE;
5007 /* support is missing, but not important enough for a FIXME */
5008 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5010 /* .pszMfgName */
5011 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5012 *pcbNeeded += size;
5013 if(*pcbNeeded <= cbBuf)
5014 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5016 if (di) di->pszMfgName = (LPWSTR)strPtr;
5017 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5020 /* .pszOEMUrl */
5021 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5022 *pcbNeeded += size;
5023 if(*pcbNeeded <= cbBuf)
5024 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5026 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5027 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5030 /* .pszHardwareID */
5031 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5032 *pcbNeeded += size;
5033 if(*pcbNeeded <= cbBuf)
5034 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5036 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5037 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5040 /* .pszProvider */
5041 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5042 *pcbNeeded += size;
5043 if(*pcbNeeded <= cbBuf)
5044 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5046 if (di) di->pszProvider = (LPWSTR)strPtr;
5047 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5050 if (Level == 6 ) {
5051 RegCloseKey(hkeyDriver);
5052 return TRUE;
5055 /* support is missing, but not important enough for a FIXME */
5056 TRACE("level 8: incomplete\n");
5058 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5059 RegCloseKey(hkeyDriver);
5060 return TRUE;
5063 /*****************************************************************************
5064 * GetPrinterDriverW [WINSPOOL.@]
5066 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5067 DWORD Level, LPBYTE pDriverInfo,
5068 DWORD cbBuf, LPDWORD pcbNeeded)
5070 LPCWSTR name;
5071 WCHAR DriverName[100];
5072 DWORD ret, type, size, needed = 0;
5073 LPBYTE ptr = NULL;
5074 HKEY hkeyPrinter, hkeyDrivers;
5075 const printenv_t * env;
5077 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5078 Level,pDriverInfo,cbBuf, pcbNeeded);
5080 if (cbBuf > 0)
5081 ZeroMemory(pDriverInfo, cbBuf);
5083 if (!(name = get_opened_printer_name(hPrinter))) {
5084 SetLastError(ERROR_INVALID_HANDLE);
5085 return FALSE;
5088 if (Level < 1 || Level == 7 || Level > 8) {
5089 SetLastError(ERROR_INVALID_LEVEL);
5090 return FALSE;
5093 env = validate_envW(pEnvironment);
5094 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5096 ret = open_printer_reg_key( name, &hkeyPrinter );
5097 if (ret)
5099 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5100 SetLastError( ret );
5101 return FALSE;
5104 size = sizeof(DriverName);
5105 DriverName[0] = 0;
5106 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5107 (LPBYTE)DriverName, &size);
5108 RegCloseKey(hkeyPrinter);
5109 if(ret != ERROR_SUCCESS) {
5110 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5111 return FALSE;
5114 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5115 if(!hkeyDrivers) {
5116 ERR("Can't create Drivers key\n");
5117 return FALSE;
5120 size = di_sizeof[Level];
5121 if ((size <= cbBuf) && pDriverInfo)
5122 ptr = pDriverInfo + size;
5124 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5125 env, Level, pDriverInfo, ptr,
5126 (cbBuf < size) ? 0 : cbBuf - size,
5127 &needed)) {
5128 RegCloseKey(hkeyDrivers);
5129 return FALSE;
5132 RegCloseKey(hkeyDrivers);
5134 if(pcbNeeded) *pcbNeeded = size + needed;
5135 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5136 if(cbBuf >= size + needed) return TRUE;
5137 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5138 return FALSE;
5141 /*****************************************************************************
5142 * GetPrinterDriverA [WINSPOOL.@]
5144 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5145 DWORD Level, LPBYTE pDriverInfo,
5146 DWORD cbBuf, LPDWORD pcbNeeded)
5148 BOOL ret;
5149 UNICODE_STRING pEnvW;
5150 PWSTR pwstrEnvW;
5151 LPBYTE buf = NULL;
5153 if (cbBuf)
5155 ZeroMemory(pDriverInfo, cbBuf);
5156 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5159 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5160 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5161 cbBuf, pcbNeeded);
5162 if (ret)
5163 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5165 HeapFree(GetProcessHeap(), 0, buf);
5167 RtlFreeUnicodeString(&pEnvW);
5168 return ret;
5171 /*****************************************************************************
5172 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5174 * Return the PATH for the Printer-Drivers (UNICODE)
5176 * PARAMS
5177 * pName [I] Servername (NT only) or NULL (local Computer)
5178 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5179 * Level [I] Structure-Level (must be 1)
5180 * pDriverDirectory [O] PTR to Buffer that receives the Result
5181 * cbBuf [I] Size of Buffer at pDriverDirectory
5182 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5183 * required for pDriverDirectory
5185 * RETURNS
5186 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5187 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5188 * if cbBuf is too small
5190 * Native Values returned in pDriverDirectory on Success:
5191 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5192 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5193 *| win9x(Windows 4.0): "%winsysdir%"
5195 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5197 * FIXME
5198 *- Only NULL or "" is supported for pName
5201 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5202 DWORD Level, LPBYTE pDriverDirectory,
5203 DWORD cbBuf, LPDWORD pcbNeeded)
5205 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5206 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5208 if ((backend == NULL) && !load_backend()) return FALSE;
5210 if (Level != 1) {
5211 /* (Level != 1) is ignored in win9x */
5212 SetLastError(ERROR_INVALID_LEVEL);
5213 return FALSE;
5215 if (pcbNeeded == NULL) {
5216 /* (pcbNeeded == NULL) is ignored in win9x */
5217 SetLastError(RPC_X_NULL_REF_POINTER);
5218 return FALSE;
5221 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5222 pDriverDirectory, cbBuf, pcbNeeded);
5227 /*****************************************************************************
5228 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5230 * Return the PATH for the Printer-Drivers (ANSI)
5232 * See GetPrinterDriverDirectoryW.
5234 * NOTES
5235 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5238 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5239 DWORD Level, LPBYTE pDriverDirectory,
5240 DWORD cbBuf, LPDWORD pcbNeeded)
5242 UNICODE_STRING nameW, environmentW;
5243 BOOL ret;
5244 DWORD pcbNeededW;
5245 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5246 WCHAR *driverDirectoryW = NULL;
5248 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5249 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5251 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5253 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5254 else nameW.Buffer = NULL;
5255 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5256 else environmentW.Buffer = NULL;
5258 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5259 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5260 if (ret) {
5261 DWORD needed;
5262 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5263 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5264 if(pcbNeeded)
5265 *pcbNeeded = needed;
5266 ret = needed <= cbBuf;
5267 } else
5268 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5270 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5272 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5273 RtlFreeUnicodeString(&environmentW);
5274 RtlFreeUnicodeString(&nameW);
5276 return ret;
5279 /*****************************************************************************
5280 * AddPrinterDriverA [WINSPOOL.@]
5282 * See AddPrinterDriverW.
5285 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5287 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5288 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5291 /******************************************************************************
5292 * AddPrinterDriverW (WINSPOOL.@)
5294 * Install a Printer Driver
5296 * PARAMS
5297 * pName [I] Servername or NULL (local Computer)
5298 * level [I] Level for the supplied DRIVER_INFO_*W struct
5299 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5301 * RESULTS
5302 * Success: TRUE
5303 * Failure: FALSE
5306 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5308 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5309 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5312 /*****************************************************************************
5313 * AddPrintProcessorA [WINSPOOL.@]
5315 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5316 LPSTR pPrintProcessorName)
5318 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5319 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5320 return FALSE;
5323 /*****************************************************************************
5324 * AddPrintProcessorW [WINSPOOL.@]
5326 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5327 LPWSTR pPrintProcessorName)
5329 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5330 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5331 return TRUE;
5334 /*****************************************************************************
5335 * AddPrintProvidorA [WINSPOOL.@]
5337 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5339 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5340 return FALSE;
5343 /*****************************************************************************
5344 * AddPrintProvidorW [WINSPOOL.@]
5346 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5348 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5349 return FALSE;
5352 /*****************************************************************************
5353 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5355 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5356 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5358 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5359 pDevModeOutput, pDevModeInput);
5360 return 0;
5363 /*****************************************************************************
5364 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5366 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5367 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5369 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5370 pDevModeOutput, pDevModeInput);
5371 return 0;
5374 /*****************************************************************************
5375 * PrinterProperties [WINSPOOL.@]
5377 * Displays a dialog to set the properties of the printer.
5379 * RETURNS
5380 * nonzero on success or zero on failure
5382 * BUGS
5383 * implemented as stub only
5385 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5386 HANDLE hPrinter /* [in] handle to printer object */
5388 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5389 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5390 return FALSE;
5393 /*****************************************************************************
5394 * EnumJobsA [WINSPOOL.@]
5397 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5398 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5399 LPDWORD pcReturned)
5401 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5402 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5404 if(pcbNeeded) *pcbNeeded = 0;
5405 if(pcReturned) *pcReturned = 0;
5406 return FALSE;
5410 /*****************************************************************************
5411 * EnumJobsW [WINSPOOL.@]
5414 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5415 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5416 LPDWORD pcReturned)
5418 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5419 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5421 if(pcbNeeded) *pcbNeeded = 0;
5422 if(pcReturned) *pcReturned = 0;
5423 return FALSE;
5426 /*****************************************************************************
5427 * WINSPOOL_EnumPrinterDrivers [internal]
5429 * Delivers information about all printer drivers installed on the
5430 * localhost or a given server
5432 * RETURNS
5433 * nonzero on success or zero on failure. If the buffer for the returned
5434 * information is too small the function will return an error
5436 * BUGS
5437 * - only implemented for localhost, foreign hosts will return an error
5439 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5440 DWORD Level, LPBYTE pDriverInfo,
5441 DWORD driver_index,
5442 DWORD cbBuf, LPDWORD pcbNeeded,
5443 LPDWORD pcFound, DWORD data_offset)
5445 { HKEY hkeyDrivers;
5446 DWORD i, size = 0;
5447 const printenv_t * env;
5449 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5450 debugstr_w(pName), debugstr_w(pEnvironment),
5451 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5453 env = validate_envW(pEnvironment);
5454 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5456 *pcFound = 0;
5458 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5459 if(!hkeyDrivers) {
5460 ERR("Can't open Drivers key\n");
5461 return FALSE;
5464 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5465 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5466 RegCloseKey(hkeyDrivers);
5467 ERR("Can't query Drivers key\n");
5468 return FALSE;
5470 TRACE("Found %d Drivers\n", *pcFound);
5472 /* get size of single struct
5473 * unicode and ascii structure have the same size
5475 size = di_sizeof[Level];
5477 if (data_offset == 0)
5478 data_offset = size * (*pcFound);
5479 *pcbNeeded = data_offset;
5481 for( i = 0; i < *pcFound; i++) {
5482 WCHAR DriverNameW[255];
5483 PBYTE table_ptr = NULL;
5484 PBYTE data_ptr = NULL;
5485 DWORD needed = 0;
5487 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5488 != ERROR_SUCCESS) {
5489 ERR("Can't enum key number %d\n", i);
5490 RegCloseKey(hkeyDrivers);
5491 return FALSE;
5494 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5495 table_ptr = pDriverInfo + (driver_index + i) * size;
5496 if (pDriverInfo && *pcbNeeded <= cbBuf)
5497 data_ptr = pDriverInfo + *pcbNeeded;
5499 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5500 env, Level, table_ptr, data_ptr,
5501 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5502 &needed)) {
5503 RegCloseKey(hkeyDrivers);
5504 return FALSE;
5507 *pcbNeeded += needed;
5510 RegCloseKey(hkeyDrivers);
5512 if(cbBuf < *pcbNeeded){
5513 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5514 return FALSE;
5517 return TRUE;
5520 /*****************************************************************************
5521 * EnumPrinterDriversW [WINSPOOL.@]
5523 * see function EnumPrinterDrivers for RETURNS, BUGS
5525 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5526 LPBYTE pDriverInfo, DWORD cbBuf,
5527 LPDWORD pcbNeeded, LPDWORD pcReturned)
5529 static const WCHAR allW[] = {'a','l','l',0};
5530 BOOL ret;
5531 DWORD found;
5533 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5535 SetLastError(RPC_X_NULL_REF_POINTER);
5536 return FALSE;
5539 /* check for local drivers */
5540 if((pName) && (pName[0])) {
5541 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5542 SetLastError(ERROR_ACCESS_DENIED);
5543 return FALSE;
5546 /* check input parameter */
5547 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5548 SetLastError(ERROR_INVALID_LEVEL);
5549 return FALSE;
5552 if(pDriverInfo && cbBuf > 0)
5553 memset( pDriverInfo, 0, cbBuf);
5555 /* Exception: pull all printers */
5556 if (pEnvironment && !strcmpW(pEnvironment, allW))
5558 DWORD i, needed, bufsize = cbBuf;
5559 DWORD total_found = 0;
5560 DWORD data_offset;
5562 /* Precompute the overall total; we need this to know
5563 where pointers end and data begins (i.e. data_offset) */
5564 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5566 needed = found = 0;
5567 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5568 NULL, 0, 0, &needed, &found, 0);
5569 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5570 total_found += found;
5573 data_offset = di_sizeof[Level] * total_found;
5575 *pcReturned = 0;
5576 *pcbNeeded = 0;
5577 total_found = 0;
5578 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5580 needed = found = 0;
5581 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5582 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5583 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5584 else if (ret)
5585 *pcReturned += found;
5586 *pcbNeeded = needed;
5587 data_offset = needed;
5588 total_found += found;
5590 return ret;
5593 /* Normal behavior */
5594 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5595 0, cbBuf, pcbNeeded, &found, 0);
5596 if (ret)
5597 *pcReturned = found;
5599 return ret;
5602 /*****************************************************************************
5603 * EnumPrinterDriversA [WINSPOOL.@]
5605 * see function EnumPrinterDrivers for RETURNS, BUGS
5607 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5608 LPBYTE pDriverInfo, DWORD cbBuf,
5609 LPDWORD pcbNeeded, LPDWORD pcReturned)
5611 BOOL ret;
5612 UNICODE_STRING pNameW, pEnvironmentW;
5613 PWSTR pwstrNameW, pwstrEnvironmentW;
5614 LPBYTE buf = NULL;
5616 if (cbBuf)
5617 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5619 pwstrNameW = asciitounicode(&pNameW, pName);
5620 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5622 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5623 buf, cbBuf, pcbNeeded, pcReturned);
5624 if (ret)
5625 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5627 HeapFree(GetProcessHeap(), 0, buf);
5629 RtlFreeUnicodeString(&pNameW);
5630 RtlFreeUnicodeString(&pEnvironmentW);
5632 return ret;
5635 /******************************************************************************
5636 * EnumPortsA (WINSPOOL.@)
5638 * See EnumPortsW.
5641 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5642 LPDWORD pcbNeeded, LPDWORD pcReturned)
5644 BOOL res;
5645 LPBYTE bufferW = NULL;
5646 LPWSTR nameW = NULL;
5647 DWORD needed = 0;
5648 DWORD numentries = 0;
5649 INT len;
5651 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5652 cbBuf, pcbNeeded, pcReturned);
5654 /* convert servername to unicode */
5655 if (pName) {
5656 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5657 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5658 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5660 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5661 needed = cbBuf * sizeof(WCHAR);
5662 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5663 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5665 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5666 if (pcbNeeded) needed = *pcbNeeded;
5667 /* HeapReAlloc return NULL, when bufferW was NULL */
5668 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5669 HeapAlloc(GetProcessHeap(), 0, needed);
5671 /* Try again with the large Buffer */
5672 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5674 needed = pcbNeeded ? *pcbNeeded : 0;
5675 numentries = pcReturned ? *pcReturned : 0;
5678 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5679 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5681 if (res) {
5682 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5683 DWORD entrysize = 0;
5684 DWORD index;
5685 LPSTR ptr;
5686 LPPORT_INFO_2W pi2w;
5687 LPPORT_INFO_2A pi2a;
5689 needed = 0;
5690 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5692 /* First pass: calculate the size for all Entries */
5693 pi2w = (LPPORT_INFO_2W) bufferW;
5694 pi2a = (LPPORT_INFO_2A) pPorts;
5695 index = 0;
5696 while (index < numentries) {
5697 index++;
5698 needed += entrysize; /* PORT_INFO_?A */
5699 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5701 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5702 NULL, 0, NULL, NULL);
5703 if (Level > 1) {
5704 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5705 NULL, 0, NULL, NULL);
5706 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5707 NULL, 0, NULL, NULL);
5709 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5710 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5711 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5714 /* check for errors and quit on failure */
5715 if (cbBuf < needed) {
5716 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5717 res = FALSE;
5718 goto cleanup;
5720 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5721 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5722 cbBuf -= len ; /* free Bytes in the user-Buffer */
5723 pi2w = (LPPORT_INFO_2W) bufferW;
5724 pi2a = (LPPORT_INFO_2A) pPorts;
5725 index = 0;
5726 /* Second Pass: Fill the User Buffer (if we have one) */
5727 while ((index < numentries) && pPorts) {
5728 index++;
5729 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5730 pi2a->pPortName = ptr;
5731 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5732 ptr, cbBuf , NULL, NULL);
5733 ptr += len;
5734 cbBuf -= len;
5735 if (Level > 1) {
5736 pi2a->pMonitorName = ptr;
5737 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5738 ptr, cbBuf, NULL, NULL);
5739 ptr += len;
5740 cbBuf -= len;
5742 pi2a->pDescription = ptr;
5743 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5744 ptr, cbBuf, NULL, NULL);
5745 ptr += len;
5746 cbBuf -= len;
5748 pi2a->fPortType = pi2w->fPortType;
5749 pi2a->Reserved = 0; /* documented: "must be zero" */
5752 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5753 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5754 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5758 cleanup:
5759 if (pcbNeeded) *pcbNeeded = needed;
5760 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5762 HeapFree(GetProcessHeap(), 0, nameW);
5763 HeapFree(GetProcessHeap(), 0, bufferW);
5765 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5766 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5768 return (res);
5772 /******************************************************************************
5773 * EnumPortsW (WINSPOOL.@)
5775 * Enumerate available Ports
5777 * PARAMS
5778 * pName [I] Servername or NULL (local Computer)
5779 * Level [I] Structure-Level (1 or 2)
5780 * pPorts [O] PTR to Buffer that receives the Result
5781 * cbBuf [I] Size of Buffer at pPorts
5782 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5783 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5785 * RETURNS
5786 * Success: TRUE
5787 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5790 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5793 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5794 cbBuf, pcbNeeded, pcReturned);
5796 if ((backend == NULL) && !load_backend()) return FALSE;
5798 /* Level is not checked in win9x */
5799 if (!Level || (Level > 2)) {
5800 WARN("level (%d) is ignored in win9x\n", Level);
5801 SetLastError(ERROR_INVALID_LEVEL);
5802 return FALSE;
5804 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5805 SetLastError(RPC_X_NULL_REF_POINTER);
5806 return FALSE;
5809 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5812 /******************************************************************************
5813 * GetDefaultPrinterW (WINSPOOL.@)
5815 * FIXME
5816 * This function must read the value from data 'device' of key
5817 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5819 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5821 BOOL retval = TRUE;
5822 DWORD insize, len;
5823 WCHAR *buffer, *ptr;
5825 if (!namesize)
5827 SetLastError(ERROR_INVALID_PARAMETER);
5828 return FALSE;
5831 /* make the buffer big enough for the stuff from the profile/registry,
5832 * the content must fit into the local buffer to compute the correct
5833 * size even if the extern buffer is too small or not given.
5834 * (20 for ,driver,port) */
5835 insize = *namesize;
5836 len = max(100, (insize + 20));
5837 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5839 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5841 SetLastError (ERROR_FILE_NOT_FOUND);
5842 retval = FALSE;
5843 goto end;
5845 TRACE("%s\n", debugstr_w(buffer));
5847 if ((ptr = strchrW(buffer, ',')) == NULL)
5849 SetLastError(ERROR_INVALID_NAME);
5850 retval = FALSE;
5851 goto end;
5854 *ptr = 0;
5855 *namesize = strlenW(buffer) + 1;
5856 if(!name || (*namesize > insize))
5858 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5859 retval = FALSE;
5860 goto end;
5862 strcpyW(name, buffer);
5864 end:
5865 HeapFree( GetProcessHeap(), 0, buffer);
5866 return retval;
5870 /******************************************************************************
5871 * GetDefaultPrinterA (WINSPOOL.@)
5873 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5875 BOOL retval = TRUE;
5876 DWORD insize = 0;
5877 WCHAR *bufferW = NULL;
5879 if (!namesize)
5881 SetLastError(ERROR_INVALID_PARAMETER);
5882 return FALSE;
5885 if(name && *namesize) {
5886 insize = *namesize;
5887 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5890 if(!GetDefaultPrinterW( bufferW, namesize)) {
5891 retval = FALSE;
5892 goto end;
5895 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5896 NULL, NULL);
5897 if (!*namesize)
5899 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5900 retval = FALSE;
5902 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5904 end:
5905 HeapFree( GetProcessHeap(), 0, bufferW);
5906 return retval;
5910 /******************************************************************************
5911 * SetDefaultPrinterW (WINSPOOL.204)
5913 * Set the Name of the Default Printer
5915 * PARAMS
5916 * pszPrinter [I] Name of the Printer or NULL
5918 * RETURNS
5919 * Success: True
5920 * Failure: FALSE
5922 * NOTES
5923 * When the Parameter is NULL or points to an Empty String and
5924 * a Default Printer was already present, then this Function changes nothing.
5925 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5926 * the First enumerated local Printer is used.
5929 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5931 WCHAR default_printer[MAX_PATH];
5932 LPWSTR buffer = NULL;
5933 HKEY hreg;
5934 DWORD size;
5935 DWORD namelen;
5936 LONG lres;
5938 TRACE("(%s)\n", debugstr_w(pszPrinter));
5939 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5941 default_printer[0] = '\0';
5942 size = sizeof(default_printer)/sizeof(WCHAR);
5944 /* if we have a default Printer, do nothing. */
5945 if (GetDefaultPrinterW(default_printer, &size))
5946 return TRUE;
5948 pszPrinter = NULL;
5949 /* we have no default Printer: search local Printers and use the first */
5950 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5952 default_printer[0] = '\0';
5953 size = sizeof(default_printer)/sizeof(WCHAR);
5954 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5956 pszPrinter = default_printer;
5957 TRACE("using %s\n", debugstr_w(pszPrinter));
5959 RegCloseKey(hreg);
5962 if (pszPrinter == NULL) {
5963 TRACE("no local printer found\n");
5964 SetLastError(ERROR_FILE_NOT_FOUND);
5965 return FALSE;
5969 /* "pszPrinter" is never empty or NULL here. */
5970 namelen = lstrlenW(pszPrinter);
5971 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5972 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5973 if (!buffer ||
5974 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5975 HeapFree(GetProcessHeap(), 0, buffer);
5976 SetLastError(ERROR_FILE_NOT_FOUND);
5977 return FALSE;
5980 /* read the devices entry for the printer (driver,port) to build the string for the
5981 default device entry (printer,driver,port) */
5982 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5983 buffer[namelen] = ',';
5984 namelen++; /* move index to the start of the driver */
5986 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5987 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5988 if (!lres) {
5989 TRACE("set device to %s\n", debugstr_w(buffer));
5991 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5992 TRACE("failed to set the device entry: %d\n", GetLastError());
5993 lres = ERROR_INVALID_PRINTER_NAME;
5996 /* remove the next section, when INIFileMapping is implemented */
5998 HKEY hdev;
5999 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
6000 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6001 RegCloseKey(hdev);
6005 else
6007 if (lres != ERROR_FILE_NOT_FOUND)
6008 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6010 SetLastError(ERROR_INVALID_PRINTER_NAME);
6013 RegCloseKey(hreg);
6014 HeapFree(GetProcessHeap(), 0, buffer);
6015 return (lres == ERROR_SUCCESS);
6018 /******************************************************************************
6019 * SetDefaultPrinterA (WINSPOOL.202)
6021 * See SetDefaultPrinterW.
6024 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6026 LPWSTR bufferW = NULL;
6027 BOOL res;
6029 TRACE("(%s)\n", debugstr_a(pszPrinter));
6030 if(pszPrinter) {
6031 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6032 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6033 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6035 res = SetDefaultPrinterW(bufferW);
6036 HeapFree(GetProcessHeap(), 0, bufferW);
6037 return res;
6040 /******************************************************************************
6041 * SetPrinterDataExA (WINSPOOL.@)
6043 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6044 LPCSTR pValueName, DWORD Type,
6045 LPBYTE pData, DWORD cbData)
6047 HKEY hkeyPrinter, hkeySubkey;
6048 DWORD ret;
6050 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6051 debugstr_a(pValueName), Type, pData, cbData);
6053 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6054 != ERROR_SUCCESS)
6055 return ret;
6057 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6058 != ERROR_SUCCESS) {
6059 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6060 RegCloseKey(hkeyPrinter);
6061 return ret;
6063 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6064 RegCloseKey(hkeySubkey);
6065 RegCloseKey(hkeyPrinter);
6066 return ret;
6069 /******************************************************************************
6070 * SetPrinterDataExW (WINSPOOL.@)
6072 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6073 LPCWSTR pValueName, DWORD Type,
6074 LPBYTE pData, DWORD cbData)
6076 HKEY hkeyPrinter, hkeySubkey;
6077 DWORD ret;
6079 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6080 debugstr_w(pValueName), Type, pData, cbData);
6082 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6083 != ERROR_SUCCESS)
6084 return ret;
6086 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6087 != ERROR_SUCCESS) {
6088 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6089 RegCloseKey(hkeyPrinter);
6090 return ret;
6092 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6093 RegCloseKey(hkeySubkey);
6094 RegCloseKey(hkeyPrinter);
6095 return ret;
6098 /******************************************************************************
6099 * SetPrinterDataA (WINSPOOL.@)
6101 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6102 LPBYTE pData, DWORD cbData)
6104 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6105 pData, cbData);
6108 /******************************************************************************
6109 * SetPrinterDataW (WINSPOOL.@)
6111 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6112 LPBYTE pData, DWORD cbData)
6114 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6115 pData, cbData);
6118 /******************************************************************************
6119 * GetPrinterDataExA (WINSPOOL.@)
6121 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6122 LPCSTR pValueName, LPDWORD pType,
6123 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6125 opened_printer_t *printer;
6126 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6127 DWORD ret;
6129 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6130 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6132 printer = get_opened_printer(hPrinter);
6133 if(!printer) return ERROR_INVALID_HANDLE;
6135 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6136 if (ret) return ret;
6138 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6140 if (printer->name) {
6142 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6143 if (ret) {
6144 RegCloseKey(hkeyPrinters);
6145 return ret;
6147 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6148 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6149 RegCloseKey(hkeyPrinter);
6150 RegCloseKey(hkeyPrinters);
6151 return ret;
6154 *pcbNeeded = nSize;
6155 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6156 0, pType, pData, pcbNeeded);
6158 if (!ret && !pData) ret = ERROR_MORE_DATA;
6160 RegCloseKey(hkeySubkey);
6161 RegCloseKey(hkeyPrinter);
6162 RegCloseKey(hkeyPrinters);
6164 TRACE("--> %d\n", ret);
6165 return ret;
6168 /******************************************************************************
6169 * GetPrinterDataExW (WINSPOOL.@)
6171 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6172 LPCWSTR pValueName, LPDWORD pType,
6173 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6175 opened_printer_t *printer;
6176 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6177 DWORD ret;
6179 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6180 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6182 printer = get_opened_printer(hPrinter);
6183 if(!printer) return ERROR_INVALID_HANDLE;
6185 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6186 if (ret) return ret;
6188 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6190 if (printer->name) {
6192 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6193 if (ret) {
6194 RegCloseKey(hkeyPrinters);
6195 return ret;
6197 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6198 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6199 RegCloseKey(hkeyPrinter);
6200 RegCloseKey(hkeyPrinters);
6201 return ret;
6204 *pcbNeeded = nSize;
6205 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6206 0, pType, pData, pcbNeeded);
6208 if (!ret && !pData) ret = ERROR_MORE_DATA;
6210 RegCloseKey(hkeySubkey);
6211 RegCloseKey(hkeyPrinter);
6212 RegCloseKey(hkeyPrinters);
6214 TRACE("--> %d\n", ret);
6215 return ret;
6218 /******************************************************************************
6219 * GetPrinterDataA (WINSPOOL.@)
6221 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6222 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6224 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6225 pData, nSize, pcbNeeded);
6228 /******************************************************************************
6229 * GetPrinterDataW (WINSPOOL.@)
6231 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6232 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6234 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6235 pData, nSize, pcbNeeded);
6238 /*******************************************************************************
6239 * EnumPrinterDataExW [WINSPOOL.@]
6241 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6242 LPBYTE pEnumValues, DWORD cbEnumValues,
6243 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6245 HKEY hkPrinter, hkSubKey;
6246 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6247 cbValueNameLen, cbMaxValueLen, cbValueLen,
6248 cbBufSize, dwType;
6249 LPWSTR lpValueName;
6250 HANDLE hHeap;
6251 PBYTE lpValue;
6252 PPRINTER_ENUM_VALUESW ppev;
6254 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6256 if (pKeyName == NULL || *pKeyName == 0)
6257 return ERROR_INVALID_PARAMETER;
6259 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6260 if (ret != ERROR_SUCCESS)
6262 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6263 hPrinter, ret);
6264 return ret;
6267 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6268 if (ret != ERROR_SUCCESS)
6270 r = RegCloseKey (hkPrinter);
6271 if (r != ERROR_SUCCESS)
6272 WARN ("RegCloseKey returned %i\n", r);
6273 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6274 debugstr_w (pKeyName), ret);
6275 return ret;
6278 ret = RegCloseKey (hkPrinter);
6279 if (ret != ERROR_SUCCESS)
6281 ERR ("RegCloseKey returned %i\n", ret);
6282 r = RegCloseKey (hkSubKey);
6283 if (r != ERROR_SUCCESS)
6284 WARN ("RegCloseKey returned %i\n", r);
6285 return ret;
6288 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6289 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6290 if (ret != ERROR_SUCCESS)
6292 r = RegCloseKey (hkSubKey);
6293 if (r != ERROR_SUCCESS)
6294 WARN ("RegCloseKey returned %i\n", r);
6295 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6296 return ret;
6299 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6300 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6302 if (cValues == 0) /* empty key */
6304 r = RegCloseKey (hkSubKey);
6305 if (r != ERROR_SUCCESS)
6306 WARN ("RegCloseKey returned %i\n", r);
6307 *pcbEnumValues = *pnEnumValues = 0;
6308 return ERROR_SUCCESS;
6311 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6313 hHeap = GetProcessHeap ();
6314 if (hHeap == NULL)
6316 ERR ("GetProcessHeap failed\n");
6317 r = RegCloseKey (hkSubKey);
6318 if (r != ERROR_SUCCESS)
6319 WARN ("RegCloseKey returned %i\n", r);
6320 return ERROR_OUTOFMEMORY;
6323 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6324 if (lpValueName == NULL)
6326 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6327 r = RegCloseKey (hkSubKey);
6328 if (r != ERROR_SUCCESS)
6329 WARN ("RegCloseKey returned %i\n", r);
6330 return ERROR_OUTOFMEMORY;
6333 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6334 if (lpValue == NULL)
6336 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6337 if (HeapFree (hHeap, 0, lpValueName) == 0)
6338 WARN ("HeapFree failed with code %i\n", GetLastError ());
6339 r = RegCloseKey (hkSubKey);
6340 if (r != ERROR_SUCCESS)
6341 WARN ("RegCloseKey returned %i\n", r);
6342 return ERROR_OUTOFMEMORY;
6345 TRACE ("pass 1: calculating buffer required for all names and values\n");
6347 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6349 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6351 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6353 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6354 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6355 NULL, NULL, lpValue, &cbValueLen);
6356 if (ret != ERROR_SUCCESS)
6358 if (HeapFree (hHeap, 0, lpValue) == 0)
6359 WARN ("HeapFree failed with code %i\n", GetLastError ());
6360 if (HeapFree (hHeap, 0, lpValueName) == 0)
6361 WARN ("HeapFree failed with code %i\n", GetLastError ());
6362 r = RegCloseKey (hkSubKey);
6363 if (r != ERROR_SUCCESS)
6364 WARN ("RegCloseKey returned %i\n", r);
6365 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6366 return ret;
6369 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6370 debugstr_w (lpValueName), dwIndex,
6371 cbValueNameLen + 1, cbValueLen);
6373 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6374 cbBufSize += cbValueLen;
6377 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6379 *pcbEnumValues = cbBufSize;
6380 *pnEnumValues = cValues;
6382 if (cbEnumValues < cbBufSize) /* buffer too small */
6384 if (HeapFree (hHeap, 0, lpValue) == 0)
6385 WARN ("HeapFree failed with code %i\n", GetLastError ());
6386 if (HeapFree (hHeap, 0, lpValueName) == 0)
6387 WARN ("HeapFree failed with code %i\n", GetLastError ());
6388 r = RegCloseKey (hkSubKey);
6389 if (r != ERROR_SUCCESS)
6390 WARN ("RegCloseKey returned %i\n", r);
6391 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6392 return ERROR_MORE_DATA;
6395 TRACE ("pass 2: copying all names and values to buffer\n");
6397 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6398 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6400 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6402 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6403 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6404 NULL, &dwType, lpValue, &cbValueLen);
6405 if (ret != ERROR_SUCCESS)
6407 if (HeapFree (hHeap, 0, lpValue) == 0)
6408 WARN ("HeapFree failed with code %i\n", GetLastError ());
6409 if (HeapFree (hHeap, 0, lpValueName) == 0)
6410 WARN ("HeapFree failed with code %i\n", GetLastError ());
6411 r = RegCloseKey (hkSubKey);
6412 if (r != ERROR_SUCCESS)
6413 WARN ("RegCloseKey returned %i\n", r);
6414 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6415 return ret;
6418 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6419 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6420 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6421 pEnumValues += cbValueNameLen;
6423 /* return # of *bytes* (including trailing \0), not # of chars */
6424 ppev[dwIndex].cbValueName = cbValueNameLen;
6426 ppev[dwIndex].dwType = dwType;
6428 memcpy (pEnumValues, lpValue, cbValueLen);
6429 ppev[dwIndex].pData = pEnumValues;
6430 pEnumValues += cbValueLen;
6432 ppev[dwIndex].cbData = cbValueLen;
6434 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6435 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6438 if (HeapFree (hHeap, 0, lpValue) == 0)
6440 ret = GetLastError ();
6441 ERR ("HeapFree failed with code %i\n", ret);
6442 if (HeapFree (hHeap, 0, lpValueName) == 0)
6443 WARN ("HeapFree failed with code %i\n", GetLastError ());
6444 r = RegCloseKey (hkSubKey);
6445 if (r != ERROR_SUCCESS)
6446 WARN ("RegCloseKey returned %i\n", r);
6447 return ret;
6450 if (HeapFree (hHeap, 0, lpValueName) == 0)
6452 ret = GetLastError ();
6453 ERR ("HeapFree failed with code %i\n", ret);
6454 r = RegCloseKey (hkSubKey);
6455 if (r != ERROR_SUCCESS)
6456 WARN ("RegCloseKey returned %i\n", r);
6457 return ret;
6460 ret = RegCloseKey (hkSubKey);
6461 if (ret != ERROR_SUCCESS)
6463 ERR ("RegCloseKey returned %i\n", ret);
6464 return ret;
6467 return ERROR_SUCCESS;
6470 /*******************************************************************************
6471 * EnumPrinterDataExA [WINSPOOL.@]
6473 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6474 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6475 * what Windows 2000 SP1 does.
6478 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6479 LPBYTE pEnumValues, DWORD cbEnumValues,
6480 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6482 INT len;
6483 LPWSTR pKeyNameW;
6484 DWORD ret, dwIndex, dwBufSize;
6485 HANDLE hHeap;
6486 LPSTR pBuffer;
6488 TRACE ("%p %s\n", hPrinter, pKeyName);
6490 if (pKeyName == NULL || *pKeyName == 0)
6491 return ERROR_INVALID_PARAMETER;
6493 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6494 if (len == 0)
6496 ret = GetLastError ();
6497 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6498 return ret;
6501 hHeap = GetProcessHeap ();
6502 if (hHeap == NULL)
6504 ERR ("GetProcessHeap failed\n");
6505 return ERROR_OUTOFMEMORY;
6508 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6509 if (pKeyNameW == NULL)
6511 ERR ("Failed to allocate %i bytes from process heap\n",
6512 (LONG)(len * sizeof (WCHAR)));
6513 return ERROR_OUTOFMEMORY;
6516 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6518 ret = GetLastError ();
6519 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6520 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6521 WARN ("HeapFree failed with code %i\n", GetLastError ());
6522 return ret;
6525 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6526 pcbEnumValues, pnEnumValues);
6527 if (ret != ERROR_SUCCESS)
6529 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6530 WARN ("HeapFree failed with code %i\n", GetLastError ());
6531 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6532 return ret;
6535 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6537 ret = GetLastError ();
6538 ERR ("HeapFree failed with code %i\n", ret);
6539 return ret;
6542 if (*pnEnumValues == 0) /* empty key */
6543 return ERROR_SUCCESS;
6545 dwBufSize = 0;
6546 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6548 PPRINTER_ENUM_VALUESW ppev =
6549 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6551 if (dwBufSize < ppev->cbValueName)
6552 dwBufSize = ppev->cbValueName;
6554 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6555 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6556 dwBufSize = ppev->cbData;
6559 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6561 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6562 if (pBuffer == NULL)
6564 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6565 return ERROR_OUTOFMEMORY;
6568 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6570 PPRINTER_ENUM_VALUESW ppev =
6571 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6573 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6574 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6575 NULL);
6576 if (len == 0)
6578 ret = GetLastError ();
6579 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6580 if (HeapFree (hHeap, 0, pBuffer) == 0)
6581 WARN ("HeapFree failed with code %i\n", GetLastError ());
6582 return ret;
6585 memcpy (ppev->pValueName, pBuffer, len);
6587 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6589 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6590 ppev->dwType != REG_MULTI_SZ)
6591 continue;
6593 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6594 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6595 if (len == 0)
6597 ret = GetLastError ();
6598 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6599 if (HeapFree (hHeap, 0, pBuffer) == 0)
6600 WARN ("HeapFree failed with code %i\n", GetLastError ());
6601 return ret;
6604 memcpy (ppev->pData, pBuffer, len);
6606 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6607 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6610 if (HeapFree (hHeap, 0, pBuffer) == 0)
6612 ret = GetLastError ();
6613 ERR ("HeapFree failed with code %i\n", ret);
6614 return ret;
6617 return ERROR_SUCCESS;
6620 /******************************************************************************
6621 * AbortPrinter (WINSPOOL.@)
6623 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6625 FIXME("(%p), stub!\n", hPrinter);
6626 return TRUE;
6629 /******************************************************************************
6630 * AddPortA (WINSPOOL.@)
6632 * See AddPortW.
6635 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6637 LPWSTR nameW = NULL;
6638 LPWSTR monitorW = NULL;
6639 DWORD len;
6640 BOOL res;
6642 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6644 if (pName) {
6645 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6646 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6647 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6650 if (pMonitorName) {
6651 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6652 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6653 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6655 res = AddPortW(nameW, hWnd, monitorW);
6656 HeapFree(GetProcessHeap(), 0, nameW);
6657 HeapFree(GetProcessHeap(), 0, monitorW);
6658 return res;
6661 /******************************************************************************
6662 * AddPortW (WINSPOOL.@)
6664 * Add a Port for a specific Monitor
6666 * PARAMS
6667 * pName [I] Servername or NULL (local Computer)
6668 * hWnd [I] Handle to parent Window for the Dialog-Box
6669 * pMonitorName [I] Name of the Monitor that manage the Port
6671 * RETURNS
6672 * Success: TRUE
6673 * Failure: FALSE
6676 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6678 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6680 if ((backend == NULL) && !load_backend()) return FALSE;
6682 if (!pMonitorName) {
6683 SetLastError(RPC_X_NULL_REF_POINTER);
6684 return FALSE;
6687 return backend->fpAddPort(pName, hWnd, pMonitorName);
6690 /******************************************************************************
6691 * AddPortExA (WINSPOOL.@)
6693 * See AddPortExW.
6696 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6698 PORT_INFO_2W pi2W;
6699 PORT_INFO_2A * pi2A;
6700 LPWSTR nameW = NULL;
6701 LPWSTR monitorW = NULL;
6702 DWORD len;
6703 BOOL res;
6705 pi2A = (PORT_INFO_2A *) pBuffer;
6707 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6708 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6710 if ((level < 1) || (level > 2)) {
6711 SetLastError(ERROR_INVALID_LEVEL);
6712 return FALSE;
6715 if (!pi2A) {
6716 SetLastError(ERROR_INVALID_PARAMETER);
6717 return FALSE;
6720 if (pName) {
6721 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6722 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6723 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6726 if (pMonitorName) {
6727 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6728 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6729 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6732 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6734 if (pi2A->pPortName) {
6735 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6736 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6737 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6740 if (level > 1) {
6741 if (pi2A->pMonitorName) {
6742 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6743 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6744 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6747 if (pi2A->pDescription) {
6748 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6749 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6750 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6752 pi2W.fPortType = pi2A->fPortType;
6753 pi2W.Reserved = pi2A->Reserved;
6756 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6758 HeapFree(GetProcessHeap(), 0, nameW);
6759 HeapFree(GetProcessHeap(), 0, monitorW);
6760 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6761 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6762 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6763 return res;
6767 /******************************************************************************
6768 * AddPortExW (WINSPOOL.@)
6770 * Add a Port for a specific Monitor, without presenting a user interface
6772 * PARAMS
6773 * pName [I] Servername or NULL (local Computer)
6774 * level [I] Structure-Level (1 or 2) for pBuffer
6775 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6776 * pMonitorName [I] Name of the Monitor that manage the Port
6778 * RETURNS
6779 * Success: TRUE
6780 * Failure: FALSE
6783 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6785 PORT_INFO_2W * pi2;
6787 pi2 = (PORT_INFO_2W *) pBuffer;
6789 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6790 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6791 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6792 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6794 if ((backend == NULL) && !load_backend()) return FALSE;
6796 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6797 SetLastError(ERROR_INVALID_PARAMETER);
6798 return FALSE;
6801 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6804 /******************************************************************************
6805 * AddPrinterConnectionA (WINSPOOL.@)
6807 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6809 FIXME("%s\n", debugstr_a(pName));
6810 return FALSE;
6813 /******************************************************************************
6814 * AddPrinterConnectionW (WINSPOOL.@)
6816 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6818 FIXME("%s\n", debugstr_w(pName));
6819 return FALSE;
6822 /******************************************************************************
6823 * AddPrinterDriverExW (WINSPOOL.@)
6825 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6827 * PARAMS
6828 * pName [I] Servername or NULL (local Computer)
6829 * level [I] Level for the supplied DRIVER_INFO_*W struct
6830 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6831 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6833 * RESULTS
6834 * Success: TRUE
6835 * Failure: FALSE
6838 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6840 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6842 if ((backend == NULL) && !load_backend()) return FALSE;
6844 if (level < 2 || level == 5 || level == 7 || level > 8) {
6845 SetLastError(ERROR_INVALID_LEVEL);
6846 return FALSE;
6849 if (!pDriverInfo) {
6850 SetLastError(ERROR_INVALID_PARAMETER);
6851 return FALSE;
6854 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6857 /******************************************************************************
6858 * AddPrinterDriverExA (WINSPOOL.@)
6860 * See AddPrinterDriverExW.
6863 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6865 DRIVER_INFO_8A *diA;
6866 DRIVER_INFO_8W diW;
6867 LPWSTR nameW = NULL;
6868 DWORD lenA;
6869 DWORD len;
6870 BOOL res = FALSE;
6872 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6874 diA = (DRIVER_INFO_8A *) pDriverInfo;
6875 ZeroMemory(&diW, sizeof(diW));
6877 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6878 SetLastError(ERROR_INVALID_LEVEL);
6879 return FALSE;
6882 if (diA == NULL) {
6883 SetLastError(ERROR_INVALID_PARAMETER);
6884 return FALSE;
6887 /* convert servername to unicode */
6888 if (pName) {
6889 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6890 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6891 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6894 /* common fields */
6895 diW.cVersion = diA->cVersion;
6897 if (diA->pName) {
6898 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6899 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6900 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6903 if (diA->pEnvironment) {
6904 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6905 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6906 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6909 if (diA->pDriverPath) {
6910 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6911 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6912 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6915 if (diA->pDataFile) {
6916 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6917 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6918 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6921 if (diA->pConfigFile) {
6922 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6923 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6924 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6927 if ((Level > 2) && diA->pDependentFiles) {
6928 lenA = multi_sz_lenA(diA->pDependentFiles);
6929 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6930 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6931 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6934 if ((Level > 2) && diA->pMonitorName) {
6935 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6936 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6937 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6940 if ((Level > 3) && diA->pDefaultDataType) {
6941 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6942 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6943 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6946 if ((Level > 3) && diA->pszzPreviousNames) {
6947 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6948 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6949 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6950 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6953 if ((Level > 5) && diA->pszMfgName) {
6954 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6955 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6956 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6959 if ((Level > 5) && diA->pszOEMUrl) {
6960 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6961 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6962 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6965 if ((Level > 5) && diA->pszHardwareID) {
6966 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6967 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6968 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6971 if ((Level > 5) && diA->pszProvider) {
6972 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6973 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6974 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6977 if (Level > 7) {
6978 FIXME("level %u is incomplete\n", Level);
6981 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6982 TRACE("got %u with %u\n", res, GetLastError());
6983 HeapFree(GetProcessHeap(), 0, nameW);
6984 HeapFree(GetProcessHeap(), 0, diW.pName);
6985 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6986 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6987 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6988 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6989 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6990 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6991 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6992 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6993 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6994 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6995 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6996 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6998 TRACE("=> %u with %u\n", res, GetLastError());
6999 return res;
7002 /******************************************************************************
7003 * ConfigurePortA (WINSPOOL.@)
7005 * See ConfigurePortW.
7008 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7010 LPWSTR nameW = NULL;
7011 LPWSTR portW = NULL;
7012 INT len;
7013 DWORD res;
7015 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7017 /* convert servername to unicode */
7018 if (pName) {
7019 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7020 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7021 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7024 /* convert portname to unicode */
7025 if (pPortName) {
7026 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7027 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7028 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7031 res = ConfigurePortW(nameW, hWnd, portW);
7032 HeapFree(GetProcessHeap(), 0, nameW);
7033 HeapFree(GetProcessHeap(), 0, portW);
7034 return res;
7037 /******************************************************************************
7038 * ConfigurePortW (WINSPOOL.@)
7040 * Display the Configuration-Dialog for a specific Port
7042 * PARAMS
7043 * pName [I] Servername or NULL (local Computer)
7044 * hWnd [I] Handle to parent Window for the Dialog-Box
7045 * pPortName [I] Name of the Port, that should be configured
7047 * RETURNS
7048 * Success: TRUE
7049 * Failure: FALSE
7052 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7055 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7057 if ((backend == NULL) && !load_backend()) return FALSE;
7059 if (!pPortName) {
7060 SetLastError(RPC_X_NULL_REF_POINTER);
7061 return FALSE;
7064 return backend->fpConfigurePort(pName, hWnd, pPortName);
7067 /******************************************************************************
7068 * ConnectToPrinterDlg (WINSPOOL.@)
7070 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7072 FIXME("%p %x\n", hWnd, Flags);
7073 return NULL;
7076 /******************************************************************************
7077 * DeletePrinterConnectionA (WINSPOOL.@)
7079 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7081 FIXME("%s\n", debugstr_a(pName));
7082 return TRUE;
7085 /******************************************************************************
7086 * DeletePrinterConnectionW (WINSPOOL.@)
7088 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7090 FIXME("%s\n", debugstr_w(pName));
7091 return TRUE;
7094 /******************************************************************************
7095 * DeletePrinterDriverExW (WINSPOOL.@)
7097 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7098 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7100 HKEY hkey_drivers;
7101 BOOL ret = FALSE;
7103 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7104 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7106 if(pName && pName[0])
7108 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7109 SetLastError(ERROR_INVALID_PARAMETER);
7110 return FALSE;
7113 if(dwDeleteFlag)
7115 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7116 SetLastError(ERROR_INVALID_PARAMETER);
7117 return FALSE;
7120 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7122 if(!hkey_drivers)
7124 ERR("Can't open drivers key\n");
7125 return FALSE;
7128 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7129 ret = TRUE;
7131 RegCloseKey(hkey_drivers);
7133 return ret;
7136 /******************************************************************************
7137 * DeletePrinterDriverExA (WINSPOOL.@)
7139 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7140 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7142 UNICODE_STRING NameW, EnvW, DriverW;
7143 BOOL ret;
7145 asciitounicode(&NameW, pName);
7146 asciitounicode(&EnvW, pEnvironment);
7147 asciitounicode(&DriverW, pDriverName);
7149 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7151 RtlFreeUnicodeString(&DriverW);
7152 RtlFreeUnicodeString(&EnvW);
7153 RtlFreeUnicodeString(&NameW);
7155 return ret;
7158 /******************************************************************************
7159 * DeletePrinterDataExW (WINSPOOL.@)
7161 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7162 LPCWSTR pValueName)
7164 FIXME("%p %s %s\n", hPrinter,
7165 debugstr_w(pKeyName), debugstr_w(pValueName));
7166 return ERROR_INVALID_PARAMETER;
7169 /******************************************************************************
7170 * DeletePrinterDataExA (WINSPOOL.@)
7172 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7173 LPCSTR pValueName)
7175 FIXME("%p %s %s\n", hPrinter,
7176 debugstr_a(pKeyName), debugstr_a(pValueName));
7177 return ERROR_INVALID_PARAMETER;
7180 /******************************************************************************
7181 * DeletePrintProcessorA (WINSPOOL.@)
7183 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7185 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7186 debugstr_a(pPrintProcessorName));
7187 return TRUE;
7190 /******************************************************************************
7191 * DeletePrintProcessorW (WINSPOOL.@)
7193 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7195 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7196 debugstr_w(pPrintProcessorName));
7197 return TRUE;
7200 /******************************************************************************
7201 * DeletePrintProvidorA (WINSPOOL.@)
7203 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7205 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7206 debugstr_a(pPrintProviderName));
7207 return TRUE;
7210 /******************************************************************************
7211 * DeletePrintProvidorW (WINSPOOL.@)
7213 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7215 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7216 debugstr_w(pPrintProviderName));
7217 return TRUE;
7220 /******************************************************************************
7221 * EnumFormsA (WINSPOOL.@)
7223 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7224 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7226 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7227 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7228 return FALSE;
7231 /******************************************************************************
7232 * EnumFormsW (WINSPOOL.@)
7234 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7235 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7237 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7238 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7239 return FALSE;
7242 /*****************************************************************************
7243 * EnumMonitorsA [WINSPOOL.@]
7245 * See EnumMonitorsW.
7248 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7249 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7251 BOOL res;
7252 LPBYTE bufferW = NULL;
7253 LPWSTR nameW = NULL;
7254 DWORD needed = 0;
7255 DWORD numentries = 0;
7256 INT len;
7258 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7259 cbBuf, pcbNeeded, pcReturned);
7261 /* convert servername to unicode */
7262 if (pName) {
7263 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7264 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7265 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7267 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7268 needed = cbBuf * sizeof(WCHAR);
7269 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7270 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7272 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7273 if (pcbNeeded) needed = *pcbNeeded;
7274 /* HeapReAlloc return NULL, when bufferW was NULL */
7275 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7276 HeapAlloc(GetProcessHeap(), 0, needed);
7278 /* Try again with the large Buffer */
7279 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7281 numentries = pcReturned ? *pcReturned : 0;
7282 needed = 0;
7284 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7285 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7287 if (res) {
7288 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7289 DWORD entrysize = 0;
7290 DWORD index;
7291 LPSTR ptr;
7292 LPMONITOR_INFO_2W mi2w;
7293 LPMONITOR_INFO_2A mi2a;
7295 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7296 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7298 /* First pass: calculate the size for all Entries */
7299 mi2w = (LPMONITOR_INFO_2W) bufferW;
7300 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7301 index = 0;
7302 while (index < numentries) {
7303 index++;
7304 needed += entrysize; /* MONITOR_INFO_?A */
7305 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7307 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7308 NULL, 0, NULL, NULL);
7309 if (Level > 1) {
7310 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7311 NULL, 0, NULL, NULL);
7312 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7313 NULL, 0, NULL, NULL);
7315 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7316 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7317 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7320 /* check for errors and quit on failure */
7321 if (cbBuf < needed) {
7322 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7323 res = FALSE;
7324 goto emA_cleanup;
7326 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7327 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7328 cbBuf -= len ; /* free Bytes in the user-Buffer */
7329 mi2w = (LPMONITOR_INFO_2W) bufferW;
7330 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7331 index = 0;
7332 /* Second Pass: Fill the User Buffer (if we have one) */
7333 while ((index < numentries) && pMonitors) {
7334 index++;
7335 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7336 mi2a->pName = ptr;
7337 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7338 ptr, cbBuf , NULL, NULL);
7339 ptr += len;
7340 cbBuf -= len;
7341 if (Level > 1) {
7342 mi2a->pEnvironment = ptr;
7343 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7344 ptr, cbBuf, NULL, NULL);
7345 ptr += len;
7346 cbBuf -= len;
7348 mi2a->pDLLName = ptr;
7349 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7350 ptr, cbBuf, NULL, NULL);
7351 ptr += len;
7352 cbBuf -= len;
7354 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7355 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7356 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7359 emA_cleanup:
7360 if (pcbNeeded) *pcbNeeded = needed;
7361 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7363 HeapFree(GetProcessHeap(), 0, nameW);
7364 HeapFree(GetProcessHeap(), 0, bufferW);
7366 TRACE("returning %d with %d (%d byte for %d entries)\n",
7367 (res), GetLastError(), needed, numentries);
7369 return (res);
7373 /*****************************************************************************
7374 * EnumMonitorsW [WINSPOOL.@]
7376 * Enumerate available Port-Monitors
7378 * PARAMS
7379 * pName [I] Servername or NULL (local Computer)
7380 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7381 * pMonitors [O] PTR to Buffer that receives the Result
7382 * cbBuf [I] Size of Buffer at pMonitors
7383 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7384 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7386 * RETURNS
7387 * Success: TRUE
7388 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7391 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7392 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7395 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7396 cbBuf, pcbNeeded, pcReturned);
7398 if ((backend == NULL) && !load_backend()) return FALSE;
7400 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7401 SetLastError(RPC_X_NULL_REF_POINTER);
7402 return FALSE;
7405 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7408 /******************************************************************************
7409 * SpoolerInit (WINSPOOL.@)
7411 * Initialize the Spooler
7413 * RETURNS
7414 * Success: TRUE
7415 * Failure: FALSE
7417 * NOTES
7418 * The function fails on windows, when the spooler service is not running
7421 BOOL WINAPI SpoolerInit(void)
7424 if ((backend == NULL) && !load_backend()) return FALSE;
7425 return TRUE;
7428 /******************************************************************************
7429 * XcvDataW (WINSPOOL.@)
7431 * Execute commands in the Printmonitor DLL
7433 * PARAMS
7434 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7435 * pszDataName [i] Name of the command to execute
7436 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7437 * cbInputData [i] Size in Bytes of Buffer at pInputData
7438 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7439 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7440 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7441 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7443 * RETURNS
7444 * Success: TRUE
7445 * Failure: FALSE
7447 * NOTES
7448 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7449 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7451 * Minimal List of commands, that a Printmonitor DLL should support:
7453 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7454 *| "AddPort" : Add a Port
7455 *| "DeletePort": Delete a Port
7457 * Many Printmonitors support additional commands. Examples for localspl.dll:
7458 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7459 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7462 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7463 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7464 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7466 opened_printer_t *printer;
7468 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7469 pInputData, cbInputData, pOutputData,
7470 cbOutputData, pcbOutputNeeded, pdwStatus);
7472 if ((backend == NULL) && !load_backend()) return FALSE;
7474 printer = get_opened_printer(hXcv);
7475 if (!printer || (!printer->backend_printer)) {
7476 SetLastError(ERROR_INVALID_HANDLE);
7477 return FALSE;
7480 if (!pcbOutputNeeded) {
7481 SetLastError(ERROR_INVALID_PARAMETER);
7482 return FALSE;
7485 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7486 SetLastError(RPC_X_NULL_REF_POINTER);
7487 return FALSE;
7490 *pcbOutputNeeded = 0;
7492 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7493 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7497 /*****************************************************************************
7498 * EnumPrinterDataA [WINSPOOL.@]
7501 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7502 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7503 DWORD cbData, LPDWORD pcbData )
7505 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7506 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7507 return ERROR_NO_MORE_ITEMS;
7510 /*****************************************************************************
7511 * EnumPrinterDataW [WINSPOOL.@]
7514 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7515 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7516 DWORD cbData, LPDWORD pcbData )
7518 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7519 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7520 return ERROR_NO_MORE_ITEMS;
7523 /*****************************************************************************
7524 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7527 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7528 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7529 LPDWORD pcbNeeded, LPDWORD pcReturned)
7531 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7532 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7533 pcbNeeded, pcReturned);
7534 return FALSE;
7537 /*****************************************************************************
7538 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7541 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7542 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7543 LPDWORD pcbNeeded, LPDWORD pcReturned)
7545 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7546 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7547 pcbNeeded, pcReturned);
7548 return FALSE;
7551 /*****************************************************************************
7552 * EnumPrintProcessorsA [WINSPOOL.@]
7554 * See EnumPrintProcessorsW.
7557 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7558 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7560 BOOL res;
7561 LPBYTE bufferW = NULL;
7562 LPWSTR nameW = NULL;
7563 LPWSTR envW = NULL;
7564 DWORD needed = 0;
7565 DWORD numentries = 0;
7566 INT len;
7568 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7569 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7571 /* convert names to unicode */
7572 if (pName) {
7573 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7574 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7575 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7577 if (pEnvironment) {
7578 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7579 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7580 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7583 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7584 needed = cbBuf * sizeof(WCHAR);
7585 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7586 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7588 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7589 if (pcbNeeded) needed = *pcbNeeded;
7590 /* HeapReAlloc return NULL, when bufferW was NULL */
7591 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7592 HeapAlloc(GetProcessHeap(), 0, needed);
7594 /* Try again with the large Buffer */
7595 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7597 numentries = pcReturned ? *pcReturned : 0;
7598 needed = 0;
7600 if (res) {
7601 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7602 DWORD index;
7603 LPSTR ptr;
7604 PPRINTPROCESSOR_INFO_1W ppiw;
7605 PPRINTPROCESSOR_INFO_1A ppia;
7607 /* First pass: calculate the size for all Entries */
7608 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7609 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7610 index = 0;
7611 while (index < numentries) {
7612 index++;
7613 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7614 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7616 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7617 NULL, 0, NULL, NULL);
7619 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7620 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7623 /* check for errors and quit on failure */
7624 if (cbBuf < needed) {
7625 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7626 res = FALSE;
7627 goto epp_cleanup;
7630 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7631 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7632 cbBuf -= len ; /* free Bytes in the user-Buffer */
7633 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7634 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7635 index = 0;
7636 /* Second Pass: Fill the User Buffer (if we have one) */
7637 while ((index < numentries) && pPPInfo) {
7638 index++;
7639 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7640 ppia->pName = ptr;
7641 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7642 ptr, cbBuf , NULL, NULL);
7643 ptr += len;
7644 cbBuf -= len;
7646 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7647 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7651 epp_cleanup:
7652 if (pcbNeeded) *pcbNeeded = needed;
7653 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7655 HeapFree(GetProcessHeap(), 0, nameW);
7656 HeapFree(GetProcessHeap(), 0, envW);
7657 HeapFree(GetProcessHeap(), 0, bufferW);
7659 TRACE("returning %d with %d (%d byte for %d entries)\n",
7660 (res), GetLastError(), needed, numentries);
7662 return (res);
7665 /*****************************************************************************
7666 * EnumPrintProcessorsW [WINSPOOL.@]
7668 * Enumerate available Print Processors
7670 * PARAMS
7671 * pName [I] Servername or NULL (local Computer)
7672 * pEnvironment [I] Printing-Environment or NULL (Default)
7673 * Level [I] Structure-Level (Only 1 is allowed)
7674 * pPPInfo [O] PTR to Buffer that receives the Result
7675 * cbBuf [I] Size of Buffer at pPPInfo
7676 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7677 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7679 * RETURNS
7680 * Success: TRUE
7681 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7684 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7685 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7688 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7689 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7691 if ((backend == NULL) && !load_backend()) return FALSE;
7693 if (!pcbNeeded || !pcReturned) {
7694 SetLastError(RPC_X_NULL_REF_POINTER);
7695 return FALSE;
7698 if (!pPPInfo && (cbBuf > 0)) {
7699 SetLastError(ERROR_INVALID_USER_BUFFER);
7700 return FALSE;
7703 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7704 cbBuf, pcbNeeded, pcReturned);
7707 /*****************************************************************************
7708 * ExtDeviceMode [WINSPOOL.@]
7711 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7712 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7713 DWORD fMode)
7715 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7716 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7717 debugstr_a(pProfile), fMode);
7718 return -1;
7721 /*****************************************************************************
7722 * FindClosePrinterChangeNotification [WINSPOOL.@]
7725 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7727 FIXME("Stub: %p\n", hChange);
7728 return TRUE;
7731 /*****************************************************************************
7732 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7735 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7736 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7738 FIXME("Stub: %p %x %x %p\n",
7739 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7740 return INVALID_HANDLE_VALUE;
7743 /*****************************************************************************
7744 * FindNextPrinterChangeNotification [WINSPOOL.@]
7747 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7748 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7750 FIXME("Stub: %p %p %p %p\n",
7751 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7752 return FALSE;
7755 /*****************************************************************************
7756 * FreePrinterNotifyInfo [WINSPOOL.@]
7759 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7761 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7762 return TRUE;
7765 /*****************************************************************************
7766 * string_to_buf
7768 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7769 * ansi depending on the unicode parameter.
7771 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7773 if(!str)
7775 *size = 0;
7776 return TRUE;
7779 if(unicode)
7781 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7782 if(*size <= cb)
7784 memcpy(ptr, str, *size);
7785 return TRUE;
7787 return FALSE;
7789 else
7791 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7792 if(*size <= cb)
7794 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7795 return TRUE;
7797 return FALSE;
7801 /*****************************************************************************
7802 * get_job_info_1
7804 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7805 LPDWORD pcbNeeded, BOOL unicode)
7807 DWORD size, left = cbBuf;
7808 BOOL space = (cbBuf > 0);
7809 LPBYTE ptr = buf;
7811 *pcbNeeded = 0;
7813 if(space)
7815 ji1->JobId = job->job_id;
7818 string_to_buf(job->document_title, ptr, left, &size, unicode);
7819 if(space && size <= left)
7821 ji1->pDocument = (LPWSTR)ptr;
7822 ptr += size;
7823 left -= size;
7825 else
7826 space = FALSE;
7827 *pcbNeeded += size;
7829 if (job->printer_name)
7831 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7832 if(space && size <= left)
7834 ji1->pPrinterName = (LPWSTR)ptr;
7835 ptr += size;
7836 left -= size;
7838 else
7839 space = FALSE;
7840 *pcbNeeded += size;
7843 return space;
7846 /*****************************************************************************
7847 * get_job_info_2
7849 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7850 LPDWORD pcbNeeded, BOOL unicode)
7852 DWORD size, left = cbBuf;
7853 DWORD shift;
7854 BOOL space = (cbBuf > 0);
7855 LPBYTE ptr = buf;
7856 LPDEVMODEA dmA = NULL;
7857 LPDEVMODEW devmode;
7859 *pcbNeeded = 0;
7861 if(space)
7863 ji2->JobId = job->job_id;
7866 string_to_buf(job->document_title, ptr, left, &size, unicode);
7867 if(space && size <= left)
7869 ji2->pDocument = (LPWSTR)ptr;
7870 ptr += size;
7871 left -= size;
7873 else
7874 space = FALSE;
7875 *pcbNeeded += size;
7877 if (job->printer_name)
7879 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7880 if(space && size <= left)
7882 ji2->pPrinterName = (LPWSTR)ptr;
7883 ptr += size;
7884 left -= size;
7886 else
7887 space = FALSE;
7888 *pcbNeeded += size;
7891 if (job->devmode)
7893 if (!unicode)
7895 dmA = DEVMODEdupWtoA(job->devmode);
7896 devmode = (LPDEVMODEW) dmA;
7897 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7899 else
7901 devmode = job->devmode;
7902 size = devmode->dmSize + devmode->dmDriverExtra;
7905 if (!devmode)
7906 FIXME("Can't convert DEVMODE W to A\n");
7907 else
7909 /* align DEVMODE to a DWORD boundary */
7910 shift = (4 - (*pcbNeeded & 3)) & 3;
7911 size += shift;
7913 if (size <= left)
7915 ptr += shift;
7916 memcpy(ptr, devmode, size-shift);
7917 ji2->pDevMode = (LPDEVMODEW)ptr;
7918 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7919 ptr += size-shift;
7920 left -= size;
7922 else
7923 space = FALSE;
7924 *pcbNeeded +=size;
7928 return space;
7931 /*****************************************************************************
7932 * get_job_info
7934 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7935 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7937 BOOL ret = FALSE;
7938 DWORD needed = 0, size;
7939 job_t *job;
7940 LPBYTE ptr = pJob;
7942 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7944 EnterCriticalSection(&printer_handles_cs);
7945 job = get_job(hPrinter, JobId);
7946 if(!job)
7947 goto end;
7949 switch(Level)
7951 case 1:
7952 size = sizeof(JOB_INFO_1W);
7953 if(cbBuf >= size)
7955 cbBuf -= size;
7956 ptr += size;
7957 memset(pJob, 0, size);
7959 else
7960 cbBuf = 0;
7961 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7962 needed += size;
7963 break;
7965 case 2:
7966 size = sizeof(JOB_INFO_2W);
7967 if(cbBuf >= size)
7969 cbBuf -= size;
7970 ptr += size;
7971 memset(pJob, 0, size);
7973 else
7974 cbBuf = 0;
7975 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7976 needed += size;
7977 break;
7979 case 3:
7980 size = sizeof(JOB_INFO_3);
7981 if(cbBuf >= size)
7983 cbBuf -= size;
7984 memset(pJob, 0, size);
7985 ret = TRUE;
7987 else
7988 cbBuf = 0;
7989 needed = size;
7990 break;
7992 default:
7993 SetLastError(ERROR_INVALID_LEVEL);
7994 goto end;
7996 if(pcbNeeded)
7997 *pcbNeeded = needed;
7998 end:
7999 LeaveCriticalSection(&printer_handles_cs);
8000 return ret;
8003 /*****************************************************************************
8004 * GetJobA [WINSPOOL.@]
8007 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8008 DWORD cbBuf, LPDWORD pcbNeeded)
8010 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8013 /*****************************************************************************
8014 * GetJobW [WINSPOOL.@]
8017 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8018 DWORD cbBuf, LPDWORD pcbNeeded)
8020 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8023 /*****************************************************************************
8024 * schedule_pipe
8026 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8028 #ifdef HAVE_FORK
8029 char *unixname, *cmdA;
8030 DWORD len;
8031 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8032 BOOL ret = FALSE;
8033 char buf[1024];
8034 pid_t pid, wret;
8035 int status;
8037 if(!(unixname = wine_get_unix_file_name(filename)))
8038 return FALSE;
8040 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8041 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8042 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8044 TRACE("printing with: %s\n", cmdA);
8046 if((file_fd = open(unixname, O_RDONLY)) == -1)
8047 goto end;
8049 if (pipe(fds))
8051 ERR("pipe() failed!\n");
8052 goto end;
8055 if ((pid = fork()) == 0)
8057 close(0);
8058 dup2(fds[0], 0);
8059 close(fds[1]);
8061 /* reset signals that we previously set to SIG_IGN */
8062 signal(SIGPIPE, SIG_DFL);
8064 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8065 _exit(1);
8067 else if (pid == -1)
8069 ERR("fork() failed!\n");
8070 goto end;
8073 close(fds[0]);
8074 fds[0] = -1;
8075 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8076 write(fds[1], buf, no_read);
8078 close(fds[1]);
8079 fds[1] = -1;
8081 /* reap child */
8082 do {
8083 wret = waitpid(pid, &status, 0);
8084 } while (wret < 0 && errno == EINTR);
8085 if (wret < 0)
8087 ERR("waitpid() failed!\n");
8088 goto end;
8090 if (!WIFEXITED(status) || WEXITSTATUS(status))
8092 ERR("child process failed! %d\n", status);
8093 goto end;
8096 ret = TRUE;
8098 end:
8099 if(file_fd != -1) close(file_fd);
8100 if(fds[0] != -1) close(fds[0]);
8101 if(fds[1] != -1) close(fds[1]);
8103 HeapFree(GetProcessHeap(), 0, cmdA);
8104 HeapFree(GetProcessHeap(), 0, unixname);
8105 return ret;
8106 #else
8107 return FALSE;
8108 #endif
8111 /*****************************************************************************
8112 * schedule_lpr
8114 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8116 WCHAR *cmd;
8117 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8118 BOOL r;
8120 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8121 sprintfW(cmd, fmtW, printer_name);
8123 r = schedule_pipe(cmd, filename);
8125 HeapFree(GetProcessHeap(), 0, cmd);
8126 return r;
8129 #ifdef SONAME_LIBCUPS
8130 /*****************************************************************************
8131 * get_cups_jobs_ticket_options
8133 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8134 * The CUPS scheduler only looks for these in Print-File requests, and since
8135 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8136 * parsed.
8138 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8140 FILE *fp = fopen( file, "r" );
8141 char buf[257]; /* DSC max of 256 + '\0' */
8142 const char *ps_adobe = "%!PS-Adobe-";
8143 const char *cups_job = "%cupsJobTicket:";
8145 if (!fp) return num_options;
8146 if (!fgets( buf, sizeof(buf), fp )) goto end;
8147 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8148 while (fgets( buf, sizeof(buf), fp ))
8150 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8151 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8154 end:
8155 fclose( fp );
8156 return num_options;
8159 static int get_cups_default_options( const char *printer, int num_options, cups_option_t **options )
8161 cups_dest_t *dest;
8162 int i;
8164 if (!pcupsGetNamedDest) return num_options;
8166 dest = pcupsGetNamedDest( NULL, printer, NULL );
8167 if (!dest) return num_options;
8169 for (i = 0; i < dest->num_options; i++)
8171 if (!pcupsGetOption( dest->options[i].name, num_options, *options ))
8172 num_options = pcupsAddOption( dest->options[i].name, dest->options[i].value,
8173 num_options, options );
8176 pcupsFreeDests( 1, dest );
8177 return num_options;
8179 #endif
8181 /*****************************************************************************
8182 * schedule_cups
8184 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8186 #ifdef SONAME_LIBCUPS
8187 if(pcupsPrintFile)
8189 char *unixname, *queue, *unix_doc_title;
8190 DWORD len;
8191 BOOL ret;
8192 int num_options = 0, i;
8193 cups_option_t *options = NULL;
8195 if(!(unixname = wine_get_unix_file_name(filename)))
8196 return FALSE;
8198 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8199 queue = HeapAlloc(GetProcessHeap(), 0, len);
8200 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8202 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8203 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8204 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8206 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8207 num_options = get_cups_default_options( queue, num_options, &options );
8209 TRACE( "printing via cups with options:\n" );
8210 for (i = 0; i < num_options; i++)
8211 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8213 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8215 pcupsFreeOptions( num_options, options );
8217 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8218 HeapFree(GetProcessHeap(), 0, queue);
8219 HeapFree(GetProcessHeap(), 0, unixname);
8220 return ret;
8222 else
8223 #endif
8225 return schedule_lpr(printer_name, filename);
8229 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8231 LPWSTR filename;
8233 switch(msg)
8235 case WM_INITDIALOG:
8236 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8237 return TRUE;
8239 case WM_COMMAND:
8240 if(HIWORD(wparam) == BN_CLICKED)
8242 if(LOWORD(wparam) == IDOK)
8244 HANDLE hf;
8245 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8246 LPWSTR *output;
8248 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8249 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8251 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8253 WCHAR caption[200], message[200];
8254 int mb_ret;
8256 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8257 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8258 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8259 if(mb_ret == IDCANCEL)
8261 HeapFree(GetProcessHeap(), 0, filename);
8262 return TRUE;
8265 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8266 if(hf == INVALID_HANDLE_VALUE)
8268 WCHAR caption[200], message[200];
8270 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8271 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8272 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8273 HeapFree(GetProcessHeap(), 0, filename);
8274 return TRUE;
8276 CloseHandle(hf);
8277 DeleteFileW(filename);
8278 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8279 *output = filename;
8280 EndDialog(hwnd, IDOK);
8281 return TRUE;
8283 if(LOWORD(wparam) == IDCANCEL)
8285 EndDialog(hwnd, IDCANCEL);
8286 return TRUE;
8289 return FALSE;
8291 return FALSE;
8294 /*****************************************************************************
8295 * get_filename
8297 static BOOL get_filename(LPWSTR *filename)
8299 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8300 file_dlg_proc, (LPARAM)filename) == IDOK;
8303 /*****************************************************************************
8304 * schedule_file
8306 static BOOL schedule_file(LPCWSTR filename)
8308 LPWSTR output = NULL;
8310 if(get_filename(&output))
8312 BOOL r;
8313 TRACE("copy to %s\n", debugstr_w(output));
8314 r = CopyFileW(filename, output, FALSE);
8315 HeapFree(GetProcessHeap(), 0, output);
8316 return r;
8318 return FALSE;
8321 /*****************************************************************************
8322 * schedule_unixfile
8324 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8326 int in_fd, out_fd, no_read;
8327 char buf[1024];
8328 BOOL ret = FALSE;
8329 char *unixname, *outputA;
8330 DWORD len;
8332 if(!(unixname = wine_get_unix_file_name(filename)))
8333 return FALSE;
8335 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8336 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8337 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8339 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8340 in_fd = open(unixname, O_RDONLY);
8341 if(out_fd == -1 || in_fd == -1)
8342 goto end;
8344 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8345 write(out_fd, buf, no_read);
8347 ret = TRUE;
8348 end:
8349 if(in_fd != -1) close(in_fd);
8350 if(out_fd != -1) close(out_fd);
8351 HeapFree(GetProcessHeap(), 0, outputA);
8352 HeapFree(GetProcessHeap(), 0, unixname);
8353 return ret;
8356 /*****************************************************************************
8357 * ScheduleJob [WINSPOOL.@]
8360 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8362 opened_printer_t *printer;
8363 BOOL ret = FALSE;
8364 struct list *cursor, *cursor2;
8366 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8367 EnterCriticalSection(&printer_handles_cs);
8368 printer = get_opened_printer(hPrinter);
8369 if(!printer)
8370 goto end;
8372 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8374 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8375 HANDLE hf;
8377 if(job->job_id != dwJobID) continue;
8379 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8380 if(hf != INVALID_HANDLE_VALUE)
8382 PRINTER_INFO_5W *pi5 = NULL;
8383 LPWSTR portname = job->portname;
8384 DWORD needed;
8385 HKEY hkey;
8386 WCHAR output[1024];
8387 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8388 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8390 if (!portname)
8392 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8393 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8394 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8395 portname = pi5->pPortName;
8397 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8398 debugstr_w(portname));
8400 output[0] = 0;
8402 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8403 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8405 DWORD type, count = sizeof(output);
8406 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8407 RegCloseKey(hkey);
8409 if(output[0] == '|')
8411 ret = schedule_pipe(output + 1, job->filename);
8413 else if(output[0])
8415 ret = schedule_unixfile(output, job->filename);
8417 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8419 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8421 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8423 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8425 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8427 ret = schedule_file(job->filename);
8429 else
8431 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8433 HeapFree(GetProcessHeap(), 0, pi5);
8434 CloseHandle(hf);
8435 DeleteFileW(job->filename);
8437 list_remove(cursor);
8438 HeapFree(GetProcessHeap(), 0, job->document_title);
8439 HeapFree(GetProcessHeap(), 0, job->printer_name);
8440 HeapFree(GetProcessHeap(), 0, job->portname);
8441 HeapFree(GetProcessHeap(), 0, job->filename);
8442 HeapFree(GetProcessHeap(), 0, job->devmode);
8443 HeapFree(GetProcessHeap(), 0, job);
8444 break;
8446 end:
8447 LeaveCriticalSection(&printer_handles_cs);
8448 return ret;
8451 /*****************************************************************************
8452 * StartDocDlgA [WINSPOOL.@]
8454 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8456 UNICODE_STRING usBuffer;
8457 DOCINFOW docW;
8458 LPWSTR retW;
8459 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8460 LPSTR ret = NULL;
8462 docW.cbSize = sizeof(docW);
8463 if (doc->lpszDocName)
8465 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8466 if (!(docW.lpszDocName = docnameW)) return NULL;
8468 if (doc->lpszOutput)
8470 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8471 if (!(docW.lpszOutput = outputW)) return NULL;
8473 if (doc->lpszDatatype)
8475 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8476 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8478 docW.fwType = doc->fwType;
8480 retW = StartDocDlgW(hPrinter, &docW);
8482 if(retW)
8484 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8485 ret = HeapAlloc(GetProcessHeap(), 0, len);
8486 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8487 HeapFree(GetProcessHeap(), 0, retW);
8490 HeapFree(GetProcessHeap(), 0, datatypeW);
8491 HeapFree(GetProcessHeap(), 0, outputW);
8492 HeapFree(GetProcessHeap(), 0, docnameW);
8494 return ret;
8497 /*****************************************************************************
8498 * StartDocDlgW [WINSPOOL.@]
8500 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8501 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8502 * port is "FILE:". Also returns the full path if passed a relative path.
8504 * The caller should free the returned string from the process heap.
8506 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8508 LPWSTR ret = NULL;
8509 DWORD len, attr;
8511 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8513 PRINTER_INFO_5W *pi5;
8514 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8515 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8516 return NULL;
8517 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8518 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8519 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8521 HeapFree(GetProcessHeap(), 0, pi5);
8522 return NULL;
8524 HeapFree(GetProcessHeap(), 0, pi5);
8527 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8529 LPWSTR name;
8531 if (get_filename(&name))
8533 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8535 HeapFree(GetProcessHeap(), 0, name);
8536 return NULL;
8538 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8539 GetFullPathNameW(name, len, ret, NULL);
8540 HeapFree(GetProcessHeap(), 0, name);
8542 return ret;
8545 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8546 return NULL;
8548 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8549 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8551 attr = GetFileAttributesW(ret);
8552 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8554 HeapFree(GetProcessHeap(), 0, ret);
8555 ret = NULL;
8557 return ret;
8560 /*****************************************************************************
8561 * UploadPrinterDriverPackageA [WINSPOOL.@]
8563 HRESULT WINAPI UploadPrinterDriverPackageA( LPCSTR server, LPCSTR path, LPCSTR env,
8564 DWORD flags, HWND hwnd, LPSTR dst, PULONG dstlen )
8566 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server), debugstr_a(path), debugstr_a(env),
8567 flags, hwnd, dst, dstlen);
8568 return E_NOTIMPL;
8571 /*****************************************************************************
8572 * UploadPrinterDriverPackageW [WINSPOOL.@]
8574 HRESULT WINAPI UploadPrinterDriverPackageW( LPCWSTR server, LPCWSTR path, LPCWSTR env,
8575 DWORD flags, HWND hwnd, LPWSTR dst, PULONG dstlen )
8577 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server), debugstr_w(path), debugstr_w(env),
8578 flags, hwnd, dst, dstlen);
8579 return E_NOTIMPL;