po: Update German translation.
[wine.git] / dlls / winspool.drv / info.c
blob7653d2f15c84fb2ec244be428a2b85679f366613
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()))
951 HeapFree( GetProcessHeap(), 0, port );
952 break;
954 ppd = get_ppd_filename( ppd_dir, nameW );
955 if (get_cups_ppd( dests[i].name, ppd ))
957 added_driver = add_printer_driver( nameW, ppd );
958 unlink_ppd( ppd );
960 HeapFree( GetProcessHeap(), 0, ppd );
961 if (!added_driver)
963 HeapFree( GetProcessHeap(), 0, port );
964 continue;
967 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
968 pi2.pPrinterName = nameW;
969 pi2.pDatatype = rawW;
970 pi2.pPrintProcessor = WinPrintW;
971 pi2.pDriverName = nameW;
972 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
973 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
974 pi2.pPortName = port;
975 pi2.pParameters = emptyStringW;
976 pi2.pShareName = emptyStringW;
977 pi2.pSepFile = emptyStringW;
979 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
980 if (added_printer) ClosePrinter( added_printer );
981 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
982 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
984 HeapFree( GetProcessHeap(), 0, pi2.pComment );
985 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
987 HeapFree( GetProcessHeap(), 0, port );
989 hadprinter = TRUE;
990 if (dests[i].is_default) {
991 SetDefaultPrinterW(nameW);
992 haddefault = TRUE;
996 if (ppd_dir)
998 RemoveDirectoryW( ppd_dir );
999 HeapFree( GetProcessHeap(), 0, ppd_dir );
1002 if (hadprinter && !haddefault) {
1003 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
1004 SetDefaultPrinterW(nameW);
1006 pcupsFreeDests(nrofdests, dests);
1007 RegCloseKey(hkeyPrinters);
1008 return TRUE;
1011 #endif
1013 static char *get_queue_name( HANDLE printer, BOOL *cups )
1015 WCHAR *port, *name = NULL;
1016 DWORD err, needed, type;
1017 char *ret = NULL;
1018 HKEY key;
1020 *cups = FALSE;
1022 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1023 if (err) return NULL;
1024 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1025 if (err) goto end;
1026 port = HeapAlloc( GetProcessHeap(), 0, needed );
1027 if (!port) goto end;
1028 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1030 if (!strncmpW( port, CUPS_Port, sizeof(CUPS_Port) / sizeof(WCHAR) -1 ))
1032 name = port + sizeof(CUPS_Port) / sizeof(WCHAR) - 1;
1033 *cups = TRUE;
1035 else if (!strncmpW( port, LPR_Port, sizeof(LPR_Port) / sizeof(WCHAR) -1 ))
1036 name = port + sizeof(LPR_Port) / sizeof(WCHAR) - 1;
1037 if (name)
1039 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1040 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1041 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1043 HeapFree( GetProcessHeap(), 0, port );
1044 end:
1045 RegCloseKey( key );
1046 return ret;
1050 static void set_ppd_overrides( HANDLE printer )
1052 WCHAR *wstr = NULL;
1053 int size = 0;
1054 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1055 OSStatus status;
1056 PMPrintSession session = NULL;
1057 PMPageFormat format = NULL;
1058 PMPaper paper;
1059 CFStringRef paper_name;
1060 CFRange range;
1062 status = PMCreateSession( &session );
1063 if (status) goto end;
1065 status = PMCreatePageFormat( &format );
1066 if (status) goto end;
1068 status = PMSessionDefaultPageFormat( session, format );
1069 if (status) goto end;
1071 status = PMGetPageFormatPaper( format, &paper );
1072 if (status) goto end;
1074 status = PMPaperGetPPDPaperName( paper, &paper_name );
1075 if (status) goto end;
1077 range.location = 0;
1078 range.length = CFStringGetLength( paper_name );
1079 size = (range.length + 1) * sizeof(WCHAR);
1081 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1082 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1083 wstr[range.length] = 0;
1085 end:
1086 if (format) PMRelease( format );
1087 if (session) PMRelease( session );
1088 #endif
1090 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1091 HeapFree( GetProcessHeap(), 0, wstr );
1094 static BOOL update_driver( HANDLE printer )
1096 BOOL ret, is_cups;
1097 const WCHAR *name = get_opened_printer_name( printer );
1098 WCHAR *ppd_dir, *ppd;
1099 char *queue_name;
1101 if (!name) return FALSE;
1102 queue_name = get_queue_name( printer, &is_cups );
1103 if (!queue_name) return FALSE;
1105 if (!(ppd_dir = get_ppd_dir()))
1107 HeapFree( GetProcessHeap(), 0, queue_name );
1108 return FALSE;
1110 ppd = get_ppd_filename( ppd_dir, name );
1112 #ifdef SONAME_LIBCUPS
1113 if (is_cups)
1114 ret = get_cups_ppd( queue_name, ppd );
1115 else
1116 #endif
1117 ret = get_fallback_ppd( queue_name, ppd );
1119 if (ret)
1121 TRACE( "updating driver %s\n", debugstr_w( name ) );
1122 ret = add_printer_driver( name, ppd );
1123 unlink_ppd( ppd );
1125 HeapFree( GetProcessHeap(), 0, ppd_dir );
1126 HeapFree( GetProcessHeap(), 0, ppd );
1127 HeapFree( GetProcessHeap(), 0, queue_name );
1129 set_ppd_overrides( printer );
1131 /* call into the driver to update the devmode */
1132 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1134 return ret;
1137 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1139 PRINTER_INFO_2A pinfo2a;
1140 const char *r;
1141 size_t name_len;
1142 char *e,*s,*name,*prettyname,*devname;
1143 BOOL ret = FALSE, set_default = FALSE;
1144 char *port = NULL, *env_default;
1145 HKEY hkeyPrinter, hkeyPrinters = NULL;
1146 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1147 HANDLE added_printer;
1149 while (isspace(*pent)) pent++;
1150 r = strchr(pent,':');
1151 if (r)
1152 name_len = r - pent;
1153 else
1154 name_len = strlen(pent);
1155 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1156 memcpy(name, pent, name_len);
1157 name[name_len] = '\0';
1158 if (r)
1159 pent = r;
1160 else
1161 pent = "";
1163 TRACE("name=%s entry=%s\n",name, pent);
1165 if(ispunct(*name)) { /* a tc entry, not a real printer */
1166 TRACE("skipping tc entry\n");
1167 goto end;
1170 if(strstr(pent,":server")) { /* server only version so skip */
1171 TRACE("skipping server entry\n");
1172 goto end;
1175 /* Determine whether this is a postscript printer. */
1177 ret = TRUE;
1178 env_default = getenv("PRINTER");
1179 prettyname = name;
1180 /* Get longest name, usually the one at the right for later display. */
1181 while((s=strchr(prettyname,'|'))) {
1182 *s = '\0';
1183 e = s;
1184 while(isspace(*--e)) *e = '\0';
1185 TRACE("\t%s\n", debugstr_a(prettyname));
1186 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1187 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1190 e = prettyname + strlen(prettyname);
1191 while(isspace(*--e)) *e = '\0';
1192 TRACE("\t%s\n", debugstr_a(prettyname));
1193 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1195 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1196 * if it is too long, we use it as comment below. */
1197 devname = prettyname;
1198 if (strlen(devname)>=CCHDEVICENAME-1)
1199 devname = name;
1200 if (strlen(devname)>=CCHDEVICENAME-1) {
1201 ret = FALSE;
1202 goto end;
1205 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1206 sprintf(port,"LPR:%s",name);
1208 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1209 ERROR_SUCCESS) {
1210 ERR("Can't create Printers key\n");
1211 ret = FALSE;
1212 goto end;
1215 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
1217 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1218 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1219 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1220 and continue */
1221 TRACE("Printer already exists\n");
1222 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1223 /* flag that the PPD file should be checked for an update */
1224 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1225 RegCloseKey(hkeyPrinter);
1226 } else {
1227 static CHAR data_type[] = "RAW",
1228 print_proc[] = "WinPrint",
1229 comment[] = "WINEPS Printer using LPR",
1230 params[] = "<parameters?>",
1231 share_name[] = "<share name?>",
1232 sep_file[] = "<sep file?>";
1233 BOOL added_driver = FALSE;
1235 if (!ppd_dir && !(ppd_dir = get_ppd_dir())) goto end;
1236 ppd = get_ppd_filename( ppd_dir, devnameW );
1237 if (get_fallback_ppd( devname, ppd ))
1239 added_driver = add_printer_driver( devnameW, ppd );
1240 unlink_ppd( ppd );
1242 HeapFree( GetProcessHeap(), 0, ppd );
1243 if (!added_driver) goto end;
1245 memset(&pinfo2a,0,sizeof(pinfo2a));
1246 pinfo2a.pPrinterName = devname;
1247 pinfo2a.pDatatype = data_type;
1248 pinfo2a.pPrintProcessor = print_proc;
1249 pinfo2a.pDriverName = devname;
1250 pinfo2a.pComment = comment;
1251 pinfo2a.pLocation = prettyname;
1252 pinfo2a.pPortName = port;
1253 pinfo2a.pParameters = params;
1254 pinfo2a.pShareName = share_name;
1255 pinfo2a.pSepFile = sep_file;
1257 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1258 if (added_printer) ClosePrinter( added_printer );
1259 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1260 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1263 if (isfirst || set_default)
1264 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1266 end:
1267 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1268 if (ppd_dir)
1270 RemoveDirectoryW( ppd_dir );
1271 HeapFree( GetProcessHeap(), 0, ppd_dir );
1273 HeapFree(GetProcessHeap(), 0, port);
1274 HeapFree(GetProcessHeap(), 0, name);
1275 return ret;
1278 static BOOL
1279 PRINTCAP_LoadPrinters(void) {
1280 BOOL hadprinter = FALSE;
1281 char buf[200];
1282 FILE *f;
1283 char *pent = NULL;
1284 BOOL had_bash = FALSE;
1286 f = fopen("/etc/printcap","r");
1287 if (!f)
1288 return FALSE;
1290 while(fgets(buf,sizeof(buf),f)) {
1291 char *start, *end;
1293 end=strchr(buf,'\n');
1294 if (end) *end='\0';
1296 start = buf;
1297 while(isspace(*start)) start++;
1298 if(*start == '#' || *start == '\0')
1299 continue;
1301 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1302 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1303 HeapFree(GetProcessHeap(),0,pent);
1304 pent = NULL;
1307 if (end && *--end == '\\') {
1308 *end = '\0';
1309 had_bash = TRUE;
1310 } else
1311 had_bash = FALSE;
1313 if (pent) {
1314 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1315 strcat(pent,start);
1316 } else {
1317 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1318 strcpy(pent,start);
1322 if(pent) {
1323 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1324 HeapFree(GetProcessHeap(),0,pent);
1326 fclose(f);
1327 return hadprinter;
1330 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1332 if (value)
1333 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1334 (lstrlenW(value) + 1) * sizeof(WCHAR));
1335 else
1336 return ERROR_FILE_NOT_FOUND;
1339 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1341 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1342 DWORD ret = ERROR_FILE_NOT_FOUND;
1344 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1345 and we support these drivers. NT writes DEVMODEW so somehow
1346 we'll need to distinguish between these when we support NT
1347 drivers */
1349 if (dmA)
1351 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1352 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1353 HeapFree( GetProcessHeap(), 0, dmA );
1356 return ret;
1359 /******************************************************************
1360 * get_servername_from_name (internal)
1362 * for an external server, a copy of the serverpart from the full name is returned
1365 static LPWSTR get_servername_from_name(LPCWSTR name)
1367 LPWSTR server;
1368 LPWSTR ptr;
1369 WCHAR buffer[MAX_PATH];
1370 DWORD len;
1372 if (name == NULL) return NULL;
1373 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1375 server = strdupW(&name[2]); /* skip over both backslash */
1376 if (server == NULL) return NULL;
1378 /* strip '\' and the printername */
1379 ptr = strchrW(server, '\\');
1380 if (ptr) ptr[0] = '\0';
1382 TRACE("found %s\n", debugstr_w(server));
1384 len = sizeof(buffer)/sizeof(buffer[0]);
1385 if (GetComputerNameW(buffer, &len)) {
1386 if (lstrcmpW(buffer, server) == 0) {
1387 /* The requested Servername is our computername */
1388 HeapFree(GetProcessHeap(), 0, server);
1389 return NULL;
1392 return server;
1395 /******************************************************************
1396 * get_basename_from_name (internal)
1398 * skip over the serverpart from the full name
1401 static LPCWSTR get_basename_from_name(LPCWSTR name)
1403 if (name == NULL) return NULL;
1404 if ((name[0] == '\\') && (name[1] == '\\')) {
1405 /* skip over the servername and search for the following '\' */
1406 name = strchrW(&name[2], '\\');
1407 if ((name) && (name[1])) {
1408 /* found a separator ('\') followed by a name:
1409 skip over the separator and return the rest */
1410 name++;
1412 else
1414 /* no basename present (we found only a servername) */
1415 return NULL;
1418 return name;
1421 static void free_printer_entry( opened_printer_t *printer )
1423 /* the queue is shared, so don't free that here */
1424 HeapFree( GetProcessHeap(), 0, printer->printername );
1425 HeapFree( GetProcessHeap(), 0, printer->name );
1426 HeapFree( GetProcessHeap(), 0, printer->devmode );
1427 HeapFree( GetProcessHeap(), 0, printer );
1430 /******************************************************************
1431 * get_opened_printer_entry
1432 * Get the first place empty in the opened printer table
1434 * ToDo:
1435 * - pDefault is ignored
1437 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1439 UINT_PTR handle = nb_printer_handles, i;
1440 jobqueue_t *queue = NULL;
1441 opened_printer_t *printer = NULL;
1442 LPWSTR servername;
1443 LPCWSTR printername;
1445 if ((backend == NULL) && !load_backend()) return NULL;
1447 servername = get_servername_from_name(name);
1448 if (servername) {
1449 FIXME("server %s not supported\n", debugstr_w(servername));
1450 HeapFree(GetProcessHeap(), 0, servername);
1451 SetLastError(ERROR_INVALID_PRINTER_NAME);
1452 return NULL;
1455 printername = get_basename_from_name(name);
1456 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1458 /* an empty printername is invalid */
1459 if (printername && (!printername[0])) {
1460 SetLastError(ERROR_INVALID_PARAMETER);
1461 return NULL;
1464 EnterCriticalSection(&printer_handles_cs);
1466 for (i = 0; i < nb_printer_handles; i++)
1468 if (!printer_handles[i])
1470 if(handle == nb_printer_handles)
1471 handle = i;
1473 else
1475 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1476 queue = printer_handles[i]->queue;
1480 if (handle >= nb_printer_handles)
1482 opened_printer_t **new_array;
1483 if (printer_handles)
1484 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1485 (nb_printer_handles + 16) * sizeof(*new_array) );
1486 else
1487 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1488 (nb_printer_handles + 16) * sizeof(*new_array) );
1490 if (!new_array)
1492 handle = 0;
1493 goto end;
1495 printer_handles = new_array;
1496 nb_printer_handles += 16;
1499 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1501 handle = 0;
1502 goto end;
1505 /* get a printer handle from the backend */
1506 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1507 handle = 0;
1508 goto end;
1511 /* clone the base name. This is NULL for the printserver */
1512 printer->printername = strdupW(printername);
1514 /* clone the full name */
1515 printer->name = strdupW(name);
1516 if (name && (!printer->name)) {
1517 handle = 0;
1518 goto end;
1521 if (pDefault && pDefault->pDevMode)
1522 printer->devmode = dup_devmode( pDefault->pDevMode );
1524 if(queue)
1525 printer->queue = queue;
1526 else
1528 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1529 if (!printer->queue) {
1530 handle = 0;
1531 goto end;
1533 list_init(&printer->queue->jobs);
1534 printer->queue->ref = 0;
1536 InterlockedIncrement(&printer->queue->ref);
1538 printer_handles[handle] = printer;
1539 handle++;
1540 end:
1541 LeaveCriticalSection(&printer_handles_cs);
1542 if (!handle && printer) {
1543 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1544 free_printer_entry( printer );
1547 return (HANDLE)handle;
1550 static void old_printer_check( BOOL delete_phase )
1552 PRINTER_INFO_5W* pi;
1553 DWORD needed, type, num, delete, i, size;
1554 const DWORD one = 1;
1555 HKEY key;
1556 HANDLE hprn;
1558 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1559 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1561 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1562 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1563 for (i = 0; i < num; i++)
1565 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1566 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1567 continue;
1569 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1571 if (!delete_phase)
1573 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1574 RegCloseKey( key );
1576 else
1578 delete = 0;
1579 size = sizeof( delete );
1580 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1581 RegCloseKey( key );
1582 if (delete)
1584 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1585 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1587 DeletePrinter( hprn );
1588 ClosePrinter( hprn );
1590 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1594 HeapFree(GetProcessHeap(), 0, pi);
1597 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1598 'M','U','T','E','X','_','_','\0'};
1599 static HANDLE init_mutex;
1601 void WINSPOOL_LoadSystemPrinters(void)
1603 HKEY hkey, hkeyPrinters;
1604 DWORD needed, num, i;
1605 WCHAR PrinterName[256];
1606 BOOL done = FALSE;
1608 #ifdef SONAME_LIBCUPS
1609 load_cups();
1610 #endif
1612 /* FIXME: The init code should be moved to spoolsv.exe */
1613 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1614 if (!init_mutex)
1616 ERR( "Failed to create mutex\n" );
1617 return;
1619 if (GetLastError() == ERROR_ALREADY_EXISTS)
1621 WaitForSingleObject( init_mutex, INFINITE );
1622 ReleaseMutex( init_mutex );
1623 TRACE( "Init already done\n" );
1624 return;
1627 /* This ensures that all printer entries have a valid Name value. If causes
1628 problems later if they don't. If one is found to be missed we create one
1629 and set it equal to the name of the key */
1630 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1631 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1632 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1633 for(i = 0; i < num; i++) {
1634 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1635 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1636 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1637 set_reg_szW(hkey, NameW, PrinterName);
1639 RegCloseKey(hkey);
1644 RegCloseKey(hkeyPrinters);
1647 old_printer_check( FALSE );
1649 #ifdef SONAME_LIBCUPS
1650 done = CUPS_LoadPrinters();
1651 #endif
1653 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1654 PRINTCAP_LoadPrinters();
1656 old_printer_check( TRUE );
1658 ReleaseMutex( init_mutex );
1659 return;
1662 /******************************************************************
1663 * get_job
1665 * Get the pointer to the specified job.
1666 * Should hold the printer_handles_cs before calling.
1668 static job_t *get_job(HANDLE hprn, DWORD JobId)
1670 opened_printer_t *printer = get_opened_printer(hprn);
1671 job_t *job;
1673 if(!printer) return NULL;
1674 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1676 if(job->job_id == JobId)
1677 return job;
1679 return NULL;
1682 /***********************************************************
1683 * DEVMODEcpyAtoW
1685 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1687 BOOL Formname;
1688 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1689 DWORD size;
1691 Formname = (dmA->dmSize > off_formname);
1692 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1693 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1694 dmW->dmDeviceName, CCHDEVICENAME);
1695 if(!Formname) {
1696 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1697 dmA->dmSize - CCHDEVICENAME);
1698 } else {
1699 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1700 off_formname - CCHDEVICENAME);
1701 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1702 dmW->dmFormName, CCHFORMNAME);
1703 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1704 (off_formname + CCHFORMNAME));
1706 dmW->dmSize = size;
1707 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1708 dmA->dmDriverExtra);
1709 return dmW;
1712 /******************************************************************
1713 * convert_printerinfo_W_to_A [internal]
1716 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1717 DWORD level, DWORD outlen, DWORD numentries)
1719 DWORD id = 0;
1720 LPSTR ptr;
1721 INT len;
1723 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1725 len = pi_sizeof[level] * numentries;
1726 ptr = (LPSTR) out + len;
1727 outlen -= len;
1729 /* copy the numbers of all PRINTER_INFO_* first */
1730 memcpy(out, pPrintersW, len);
1732 while (id < numentries) {
1733 switch (level) {
1734 case 1:
1736 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1737 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1739 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1740 if (piW->pDescription) {
1741 piA->pDescription = ptr;
1742 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1743 ptr, outlen, NULL, NULL);
1744 ptr += len;
1745 outlen -= len;
1747 if (piW->pName) {
1748 piA->pName = ptr;
1749 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1750 ptr, outlen, NULL, NULL);
1751 ptr += len;
1752 outlen -= len;
1754 if (piW->pComment) {
1755 piA->pComment = ptr;
1756 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1757 ptr, outlen, NULL, NULL);
1758 ptr += len;
1759 outlen -= len;
1761 break;
1764 case 2:
1766 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1767 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1768 LPDEVMODEA dmA;
1770 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1771 if (piW->pServerName) {
1772 piA->pServerName = ptr;
1773 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1774 ptr, outlen, NULL, NULL);
1775 ptr += len;
1776 outlen -= len;
1778 if (piW->pPrinterName) {
1779 piA->pPrinterName = ptr;
1780 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1781 ptr, outlen, NULL, NULL);
1782 ptr += len;
1783 outlen -= len;
1785 if (piW->pShareName) {
1786 piA->pShareName = ptr;
1787 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1788 ptr, outlen, NULL, NULL);
1789 ptr += len;
1790 outlen -= len;
1792 if (piW->pPortName) {
1793 piA->pPortName = ptr;
1794 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1795 ptr, outlen, NULL, NULL);
1796 ptr += len;
1797 outlen -= len;
1799 if (piW->pDriverName) {
1800 piA->pDriverName = ptr;
1801 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1802 ptr, outlen, NULL, NULL);
1803 ptr += len;
1804 outlen -= len;
1806 if (piW->pComment) {
1807 piA->pComment = ptr;
1808 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1809 ptr, outlen, NULL, NULL);
1810 ptr += len;
1811 outlen -= len;
1813 if (piW->pLocation) {
1814 piA->pLocation = ptr;
1815 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1816 ptr, outlen, NULL, NULL);
1817 ptr += len;
1818 outlen -= len;
1821 dmA = DEVMODEdupWtoA(piW->pDevMode);
1822 if (dmA) {
1823 /* align DEVMODEA to a DWORD boundary */
1824 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1825 ptr += len;
1826 outlen -= len;
1828 piA->pDevMode = (LPDEVMODEA) ptr;
1829 len = dmA->dmSize + dmA->dmDriverExtra;
1830 memcpy(ptr, dmA, len);
1831 HeapFree(GetProcessHeap(), 0, dmA);
1833 ptr += len;
1834 outlen -= len;
1837 if (piW->pSepFile) {
1838 piA->pSepFile = ptr;
1839 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1840 ptr, outlen, NULL, NULL);
1841 ptr += len;
1842 outlen -= len;
1844 if (piW->pPrintProcessor) {
1845 piA->pPrintProcessor = ptr;
1846 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1847 ptr, outlen, NULL, NULL);
1848 ptr += len;
1849 outlen -= len;
1851 if (piW->pDatatype) {
1852 piA->pDatatype = ptr;
1853 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1854 ptr, outlen, NULL, NULL);
1855 ptr += len;
1856 outlen -= len;
1858 if (piW->pParameters) {
1859 piA->pParameters = ptr;
1860 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1861 ptr, outlen, NULL, NULL);
1862 ptr += len;
1863 outlen -= len;
1865 if (piW->pSecurityDescriptor) {
1866 piA->pSecurityDescriptor = NULL;
1867 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1869 break;
1872 case 4:
1874 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1875 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1877 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1879 if (piW->pPrinterName) {
1880 piA->pPrinterName = ptr;
1881 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1882 ptr, outlen, NULL, NULL);
1883 ptr += len;
1884 outlen -= len;
1886 if (piW->pServerName) {
1887 piA->pServerName = ptr;
1888 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1889 ptr, outlen, NULL, NULL);
1890 ptr += len;
1891 outlen -= len;
1893 break;
1896 case 5:
1898 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1899 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1901 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1903 if (piW->pPrinterName) {
1904 piA->pPrinterName = ptr;
1905 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1906 ptr, outlen, NULL, NULL);
1907 ptr += len;
1908 outlen -= len;
1910 if (piW->pPortName) {
1911 piA->pPortName = ptr;
1912 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1913 ptr, outlen, NULL, NULL);
1914 ptr += len;
1915 outlen -= len;
1917 break;
1920 case 6: /* 6A and 6W are the same structure */
1921 break;
1923 case 7:
1925 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1926 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1928 TRACE("(%u) #%u\n", level, id);
1929 if (piW->pszObjectGUID) {
1930 piA->pszObjectGUID = ptr;
1931 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1932 ptr, outlen, NULL, NULL);
1933 ptr += len;
1934 outlen -= len;
1936 break;
1939 case 8:
1940 case 9:
1942 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1943 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1944 LPDEVMODEA dmA;
1946 TRACE("(%u) #%u\n", level, id);
1947 dmA = DEVMODEdupWtoA(piW->pDevMode);
1948 if (dmA) {
1949 /* align DEVMODEA to a DWORD boundary */
1950 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1951 ptr += len;
1952 outlen -= len;
1954 piA->pDevMode = (LPDEVMODEA) ptr;
1955 len = dmA->dmSize + dmA->dmDriverExtra;
1956 memcpy(ptr, dmA, len);
1957 HeapFree(GetProcessHeap(), 0, dmA);
1959 ptr += len;
1960 outlen -= len;
1963 break;
1966 default:
1967 FIXME("for level %u\n", level);
1969 pPrintersW += pi_sizeof[level];
1970 out += pi_sizeof[level];
1971 id++;
1975 /******************************************************************
1976 * convert_driverinfo_W_to_A [internal]
1979 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1980 DWORD level, DWORD outlen, DWORD numentries)
1982 DWORD id = 0;
1983 LPSTR ptr;
1984 INT len;
1986 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1988 len = di_sizeof[level] * numentries;
1989 ptr = (LPSTR) out + len;
1990 outlen -= len;
1992 /* copy the numbers of all PRINTER_INFO_* first */
1993 memcpy(out, pDriversW, len);
1995 #define COPY_STRING(fld) \
1996 { if (diW->fld){ \
1997 diA->fld = ptr; \
1998 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1999 ptr += len; outlen -= len;\
2001 #define COPY_MULTIZ_STRING(fld) \
2002 { LPWSTR p = diW->fld; if (p){ \
2003 diA->fld = ptr; \
2004 do {\
2005 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2006 ptr += len; outlen -= len; p += len;\
2008 while(len > 1 && outlen > 0); \
2011 while (id < numentries)
2013 switch (level)
2015 case 1:
2017 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
2018 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
2020 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2022 COPY_STRING(pName);
2023 break;
2025 case 2:
2027 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2028 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2030 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2032 COPY_STRING(pName);
2033 COPY_STRING(pEnvironment);
2034 COPY_STRING(pDriverPath);
2035 COPY_STRING(pDataFile);
2036 COPY_STRING(pConfigFile);
2037 break;
2039 case 3:
2041 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2042 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2044 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2046 COPY_STRING(pName);
2047 COPY_STRING(pEnvironment);
2048 COPY_STRING(pDriverPath);
2049 COPY_STRING(pDataFile);
2050 COPY_STRING(pConfigFile);
2051 COPY_STRING(pHelpFile);
2052 COPY_MULTIZ_STRING(pDependentFiles);
2053 COPY_STRING(pMonitorName);
2054 COPY_STRING(pDefaultDataType);
2055 break;
2057 case 4:
2059 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2060 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2062 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2064 COPY_STRING(pName);
2065 COPY_STRING(pEnvironment);
2066 COPY_STRING(pDriverPath);
2067 COPY_STRING(pDataFile);
2068 COPY_STRING(pConfigFile);
2069 COPY_STRING(pHelpFile);
2070 COPY_MULTIZ_STRING(pDependentFiles);
2071 COPY_STRING(pMonitorName);
2072 COPY_STRING(pDefaultDataType);
2073 COPY_MULTIZ_STRING(pszzPreviousNames);
2074 break;
2076 case 5:
2078 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2079 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2081 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2083 COPY_STRING(pName);
2084 COPY_STRING(pEnvironment);
2085 COPY_STRING(pDriverPath);
2086 COPY_STRING(pDataFile);
2087 COPY_STRING(pConfigFile);
2088 break;
2090 case 6:
2092 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2093 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2095 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2097 COPY_STRING(pName);
2098 COPY_STRING(pEnvironment);
2099 COPY_STRING(pDriverPath);
2100 COPY_STRING(pDataFile);
2101 COPY_STRING(pConfigFile);
2102 COPY_STRING(pHelpFile);
2103 COPY_MULTIZ_STRING(pDependentFiles);
2104 COPY_STRING(pMonitorName);
2105 COPY_STRING(pDefaultDataType);
2106 COPY_MULTIZ_STRING(pszzPreviousNames);
2107 COPY_STRING(pszMfgName);
2108 COPY_STRING(pszOEMUrl);
2109 COPY_STRING(pszHardwareID);
2110 COPY_STRING(pszProvider);
2111 break;
2113 case 8:
2115 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2116 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2118 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2120 COPY_STRING(pName);
2121 COPY_STRING(pEnvironment);
2122 COPY_STRING(pDriverPath);
2123 COPY_STRING(pDataFile);
2124 COPY_STRING(pConfigFile);
2125 COPY_STRING(pHelpFile);
2126 COPY_MULTIZ_STRING(pDependentFiles);
2127 COPY_STRING(pMonitorName);
2128 COPY_STRING(pDefaultDataType);
2129 COPY_MULTIZ_STRING(pszzPreviousNames);
2130 COPY_STRING(pszMfgName);
2131 COPY_STRING(pszOEMUrl);
2132 COPY_STRING(pszHardwareID);
2133 COPY_STRING(pszProvider);
2134 COPY_STRING(pszPrintProcessor);
2135 COPY_STRING(pszVendorSetup);
2136 COPY_MULTIZ_STRING(pszzColorProfiles);
2137 COPY_STRING(pszInfPath);
2138 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2139 break;
2143 default:
2144 FIXME("for level %u\n", level);
2147 pDriversW += di_sizeof[level];
2148 out += di_sizeof[level];
2149 id++;
2152 #undef COPY_STRING
2153 #undef COPY_MULTIZ_STRING
2157 /***********************************************************
2158 * printer_info_AtoW
2160 static void *printer_info_AtoW( const void *data, DWORD level )
2162 void *ret;
2163 UNICODE_STRING usBuffer;
2165 if (!data) return NULL;
2167 if (level < 1 || level > 9) return NULL;
2169 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2170 if (!ret) return NULL;
2172 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2174 switch (level)
2176 case 2:
2178 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2179 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2181 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2182 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2183 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2184 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2185 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2186 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2187 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2188 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2189 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2190 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2191 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2192 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2193 break;
2196 case 8:
2197 case 9:
2199 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2200 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2202 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2203 break;
2206 default:
2207 FIXME( "Unhandled level %d\n", level );
2208 HeapFree( GetProcessHeap(), 0, ret );
2209 return NULL;
2212 return ret;
2215 /***********************************************************
2216 * free_printer_info
2218 static void free_printer_info( void *data, DWORD level )
2220 if (!data) return;
2222 switch (level)
2224 case 2:
2226 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2228 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2229 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2230 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2231 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2232 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2233 HeapFree( GetProcessHeap(), 0, piW->pComment );
2234 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2235 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2236 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2237 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2238 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2239 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2240 break;
2243 case 8:
2244 case 9:
2246 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2248 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2249 break;
2252 default:
2253 FIXME( "Unhandled level %d\n", level );
2256 HeapFree( GetProcessHeap(), 0, data );
2257 return;
2260 /******************************************************************
2261 * DeviceCapabilities [WINSPOOL.@]
2262 * DeviceCapabilitiesA [WINSPOOL.@]
2265 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2266 LPSTR pOutput, LPDEVMODEA lpdm)
2268 INT ret;
2270 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice), debugstr_a(pPort), cap, pOutput, lpdm);
2272 if (!GDI_CallDeviceCapabilities16)
2274 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2275 (LPCSTR)104 );
2276 if (!GDI_CallDeviceCapabilities16) return -1;
2278 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2280 /* If DC_PAPERSIZE map POINT16s to POINTs */
2281 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2282 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2283 POINT *pt = (POINT *)pOutput;
2284 INT i;
2285 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2286 for(i = 0; i < ret; i++, pt++)
2288 pt->x = tmp[i].x;
2289 pt->y = tmp[i].y;
2291 HeapFree( GetProcessHeap(), 0, tmp );
2293 return ret;
2297 /*****************************************************************************
2298 * DeviceCapabilitiesW [WINSPOOL.@]
2300 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2303 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2304 WORD fwCapability, LPWSTR pOutput,
2305 const DEVMODEW *pDevMode)
2307 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2308 LPSTR pDeviceA = strdupWtoA(pDevice);
2309 LPSTR pPortA = strdupWtoA(pPort);
2310 INT ret;
2312 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability, pOutput, pDevMode);
2314 if(pOutput && (fwCapability == DC_BINNAMES ||
2315 fwCapability == DC_FILEDEPENDENCIES ||
2316 fwCapability == DC_PAPERNAMES)) {
2317 /* These need A -> W translation */
2318 INT size = 0, i;
2319 LPSTR pOutputA;
2320 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2321 dmA);
2322 if(ret == -1)
2323 return ret;
2324 switch(fwCapability) {
2325 case DC_BINNAMES:
2326 size = 24;
2327 break;
2328 case DC_PAPERNAMES:
2329 case DC_FILEDEPENDENCIES:
2330 size = 64;
2331 break;
2333 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2334 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2335 dmA);
2336 for(i = 0; i < ret; i++)
2337 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2338 pOutput + (i * size), size);
2339 HeapFree(GetProcessHeap(), 0, pOutputA);
2340 } else {
2341 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2342 (LPSTR)pOutput, dmA);
2344 HeapFree(GetProcessHeap(),0,pPortA);
2345 HeapFree(GetProcessHeap(),0,pDeviceA);
2346 HeapFree(GetProcessHeap(),0,dmA);
2347 return ret;
2350 /******************************************************************
2351 * DocumentPropertiesA [WINSPOOL.@]
2353 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2355 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2356 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2357 LPDEVMODEA pDevModeInput,DWORD fMode )
2359 LPSTR lpName = pDeviceName, dupname = NULL;
2360 static CHAR port[] = "LPT1:";
2361 LONG ret;
2363 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2364 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2367 if(!pDeviceName || !*pDeviceName) {
2368 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2369 if(!lpNameW) {
2370 ERR("no name from hPrinter?\n");
2371 SetLastError(ERROR_INVALID_HANDLE);
2372 return -1;
2374 lpName = dupname = strdupWtoA(lpNameW);
2377 if (!GDI_CallExtDeviceMode16)
2379 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2380 (LPCSTR)102 );
2381 if (!GDI_CallExtDeviceMode16) {
2382 ERR("No CallExtDeviceMode16?\n");
2383 ret = -1;
2384 goto end;
2387 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2388 pDevModeInput, NULL, fMode);
2390 end:
2391 HeapFree(GetProcessHeap(), 0, dupname);
2392 return ret;
2396 /*****************************************************************************
2397 * DocumentPropertiesW (WINSPOOL.@)
2399 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2401 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2402 LPWSTR pDeviceName,
2403 LPDEVMODEW pDevModeOutput,
2404 LPDEVMODEW pDevModeInput, DWORD fMode)
2407 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2408 LPDEVMODEA pDevModeInputA;
2409 LPDEVMODEA pDevModeOutputA = NULL;
2410 LONG ret;
2412 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2413 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2414 fMode);
2415 if(pDevModeOutput) {
2416 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2417 if(ret < 0) return ret;
2418 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2420 pDevModeInputA = (fMode & DM_IN_BUFFER) ? DEVMODEdupWtoA(pDevModeInput) : NULL;
2421 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2422 pDevModeInputA, fMode);
2423 if(pDevModeOutput) {
2424 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2425 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2427 if(fMode == 0 && ret > 0)
2428 ret += (CCHDEVICENAME + CCHFORMNAME);
2429 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2430 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2431 return ret;
2434 /*****************************************************************************
2435 * IsValidDevmodeA [WINSPOOL.@]
2437 * Validate a DEVMODE structure and fix errors if possible.
2440 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2442 FIXME("(%p,%ld): stub\n", pDevMode, size);
2444 if(!pDevMode)
2445 return FALSE;
2447 return TRUE;
2450 /*****************************************************************************
2451 * IsValidDevmodeW [WINSPOOL.@]
2453 * Validate a DEVMODE structure and fix errors if possible.
2456 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2458 FIXME("(%p,%ld): stub\n", pDevMode, size);
2460 if(!pDevMode)
2461 return FALSE;
2463 return TRUE;
2466 /******************************************************************
2467 * OpenPrinterA [WINSPOOL.@]
2469 * See OpenPrinterW.
2472 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2473 LPPRINTER_DEFAULTSA pDefault)
2475 UNICODE_STRING lpPrinterNameW;
2476 UNICODE_STRING usBuffer;
2477 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2478 PWSTR pwstrPrinterNameW;
2479 BOOL ret;
2481 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName), phPrinter, pDefault);
2483 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2485 if(pDefault) {
2486 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2487 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2488 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2489 pDefaultW = &DefaultW;
2491 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2492 if(pDefault) {
2493 RtlFreeUnicodeString(&usBuffer);
2494 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2496 RtlFreeUnicodeString(&lpPrinterNameW);
2497 return ret;
2500 /******************************************************************
2501 * OpenPrinterW [WINSPOOL.@]
2503 * Open a Printer / Printserver or a Printer-Object
2505 * PARAMS
2506 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2507 * phPrinter [O] The resulting Handle is stored here
2508 * pDefault [I] PTR to Default Printer Settings or NULL
2510 * RETURNS
2511 * Success: TRUE
2512 * Failure: FALSE
2514 * NOTES
2515 * lpPrinterName is one of:
2516 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2517 *| Printer: "PrinterName"
2518 *| Printer-Object: "PrinterName,Job xxx"
2519 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2520 *| XcvPort: "Servername,XcvPort PortName"
2522 * BUGS
2523 *| Printer-Object not supported
2524 *| pDefaults is ignored
2527 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2529 HKEY key;
2531 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2533 if(!phPrinter) {
2534 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2535 SetLastError(ERROR_INVALID_PARAMETER);
2536 return FALSE;
2539 /* Get the unique handle of the printer or Printserver */
2540 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2542 if (*phPrinter && WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key ) == ERROR_SUCCESS)
2544 DWORD deleting = 0, size = sizeof( deleting ), type;
2545 DWORD status;
2546 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2547 WaitForSingleObject( init_mutex, INFINITE );
2548 status = get_dword_from_reg( key, StatusW );
2549 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2550 ReleaseMutex( init_mutex );
2551 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2552 update_driver( *phPrinter );
2553 RegCloseKey( key );
2556 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2557 return (*phPrinter != 0);
2560 /******************************************************************
2561 * AddMonitorA [WINSPOOL.@]
2563 * See AddMonitorW.
2566 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2568 LPWSTR nameW = NULL;
2569 INT len;
2570 BOOL res;
2571 LPMONITOR_INFO_2A mi2a;
2572 MONITOR_INFO_2W mi2w;
2574 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2575 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2576 debugstr_a(mi2a ? mi2a->pName : NULL),
2577 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2578 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2580 if (Level != 2) {
2581 SetLastError(ERROR_INVALID_LEVEL);
2582 return FALSE;
2585 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2586 if (mi2a == NULL) {
2587 return FALSE;
2590 if (pName) {
2591 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2592 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2593 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2596 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2597 if (mi2a->pName) {
2598 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2599 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2600 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2602 if (mi2a->pEnvironment) {
2603 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2604 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2605 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2607 if (mi2a->pDLLName) {
2608 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2609 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2610 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2613 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2615 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2616 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2617 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2619 HeapFree(GetProcessHeap(), 0, nameW);
2620 return (res);
2623 /******************************************************************************
2624 * AddMonitorW [WINSPOOL.@]
2626 * Install a Printmonitor
2628 * PARAMS
2629 * pName [I] Servername or NULL (local Computer)
2630 * Level [I] Structure-Level (Must be 2)
2631 * pMonitors [I] PTR to MONITOR_INFO_2
2633 * RETURNS
2634 * Success: TRUE
2635 * Failure: FALSE
2637 * NOTES
2638 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2641 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2643 LPMONITOR_INFO_2W mi2w;
2645 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2646 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2647 debugstr_w(mi2w ? mi2w->pName : NULL),
2648 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2649 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2651 if ((backend == NULL) && !load_backend()) return FALSE;
2653 if (Level != 2) {
2654 SetLastError(ERROR_INVALID_LEVEL);
2655 return FALSE;
2658 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2659 if (mi2w == NULL) {
2660 return FALSE;
2663 return backend->fpAddMonitor(pName, Level, pMonitors);
2666 /******************************************************************
2667 * DeletePrinterDriverA [WINSPOOL.@]
2670 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2672 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2675 /******************************************************************
2676 * DeletePrinterDriverW [WINSPOOL.@]
2679 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2681 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2684 /******************************************************************
2685 * DeleteMonitorA [WINSPOOL.@]
2687 * See DeleteMonitorW.
2690 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2692 LPWSTR nameW = NULL;
2693 LPWSTR EnvironmentW = NULL;
2694 LPWSTR MonitorNameW = NULL;
2695 BOOL res;
2696 INT len;
2698 if (pName) {
2699 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2700 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2701 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2704 if (pEnvironment) {
2705 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2706 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2707 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2709 if (pMonitorName) {
2710 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2711 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2712 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2715 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2717 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2718 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2719 HeapFree(GetProcessHeap(), 0, nameW);
2720 return (res);
2723 /******************************************************************
2724 * DeleteMonitorW [WINSPOOL.@]
2726 * Delete a specific Printmonitor from a Printing-Environment
2728 * PARAMS
2729 * pName [I] Servername or NULL (local Computer)
2730 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2731 * pMonitorName [I] Name of the Monitor, that should be deleted
2733 * RETURNS
2734 * Success: TRUE
2735 * Failure: FALSE
2737 * NOTES
2738 * pEnvironment is ignored in Windows for the local Computer.
2741 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2744 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2745 debugstr_w(pMonitorName));
2747 if ((backend == NULL) && !load_backend()) return FALSE;
2749 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2753 /******************************************************************
2754 * DeletePortA [WINSPOOL.@]
2756 * See DeletePortW.
2759 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2761 LPWSTR nameW = NULL;
2762 LPWSTR portW = NULL;
2763 INT len;
2764 DWORD res;
2766 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2768 /* convert servername to unicode */
2769 if (pName) {
2770 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2771 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2772 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2775 /* convert portname to unicode */
2776 if (pPortName) {
2777 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2778 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2779 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2782 res = DeletePortW(nameW, hWnd, portW);
2783 HeapFree(GetProcessHeap(), 0, nameW);
2784 HeapFree(GetProcessHeap(), 0, portW);
2785 return res;
2788 /******************************************************************
2789 * DeletePortW [WINSPOOL.@]
2791 * Delete a specific Port
2793 * PARAMS
2794 * pName [I] Servername or NULL (local Computer)
2795 * hWnd [I] Handle to parent Window for the Dialog-Box
2796 * pPortName [I] Name of the Port, that should be deleted
2798 * RETURNS
2799 * Success: TRUE
2800 * Failure: FALSE
2803 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2805 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2807 if ((backend == NULL) && !load_backend()) return FALSE;
2809 if (!pPortName) {
2810 SetLastError(RPC_X_NULL_REF_POINTER);
2811 return FALSE;
2814 return backend->fpDeletePort(pName, hWnd, pPortName);
2817 /******************************************************************************
2818 * WritePrinter [WINSPOOL.@]
2820 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2822 opened_printer_t *printer;
2823 BOOL ret = FALSE;
2825 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2827 EnterCriticalSection(&printer_handles_cs);
2828 printer = get_opened_printer(hPrinter);
2829 if(!printer)
2831 SetLastError(ERROR_INVALID_HANDLE);
2832 goto end;
2835 if(!printer->doc)
2837 SetLastError(ERROR_SPL_NO_STARTDOC);
2838 goto end;
2841 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2842 end:
2843 LeaveCriticalSection(&printer_handles_cs);
2844 return ret;
2847 /*****************************************************************************
2848 * AddFormA [WINSPOOL.@]
2850 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2852 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2853 return TRUE;
2856 /*****************************************************************************
2857 * AddFormW [WINSPOOL.@]
2859 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2861 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2862 return TRUE;
2865 /*****************************************************************************
2866 * AddJobA [WINSPOOL.@]
2868 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2870 BOOL ret;
2871 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2872 DWORD needed;
2874 if(Level != 1) {
2875 SetLastError(ERROR_INVALID_LEVEL);
2876 return FALSE;
2879 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2881 if(ret) {
2882 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2883 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2884 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2885 if(*pcbNeeded > cbBuf) {
2886 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2887 ret = FALSE;
2888 } else {
2889 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2890 addjobA->JobId = addjobW->JobId;
2891 addjobA->Path = (char *)(addjobA + 1);
2892 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2895 return ret;
2898 /*****************************************************************************
2899 * AddJobW [WINSPOOL.@]
2901 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2903 opened_printer_t *printer;
2904 job_t *job;
2905 BOOL ret = FALSE;
2906 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2907 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2908 WCHAR path[MAX_PATH], filename[MAX_PATH];
2909 DWORD len;
2910 ADDJOB_INFO_1W *addjob;
2912 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2914 EnterCriticalSection(&printer_handles_cs);
2916 printer = get_opened_printer(hPrinter);
2918 if(!printer) {
2919 SetLastError(ERROR_INVALID_HANDLE);
2920 goto end;
2923 if(Level != 1) {
2924 SetLastError(ERROR_INVALID_LEVEL);
2925 goto end;
2928 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2929 if(!job)
2930 goto end;
2932 job->job_id = InterlockedIncrement(&next_job_id);
2934 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2935 if(path[len - 1] != '\\')
2936 path[len++] = '\\';
2937 memcpy(path + len, spool_path, sizeof(spool_path));
2938 sprintfW(filename, fmtW, path, job->job_id);
2940 len = strlenW(filename);
2941 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2942 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2943 job->portname = NULL;
2944 job->document_title = strdupW(default_doc_title);
2945 job->printer_name = strdupW(printer->name);
2946 job->devmode = dup_devmode( printer->devmode );
2947 list_add_tail(&printer->queue->jobs, &job->entry);
2949 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2950 if(*pcbNeeded <= cbBuf) {
2951 addjob = (ADDJOB_INFO_1W*)pData;
2952 addjob->JobId = job->job_id;
2953 addjob->Path = (WCHAR *)(addjob + 1);
2954 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2955 ret = TRUE;
2956 } else
2957 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2959 end:
2960 LeaveCriticalSection(&printer_handles_cs);
2961 return ret;
2964 /*****************************************************************************
2965 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2967 * Return the PATH for the Print-Processors
2969 * See GetPrintProcessorDirectoryW.
2973 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2974 DWORD level, LPBYTE Info,
2975 DWORD cbBuf, LPDWORD pcbNeeded)
2977 LPWSTR serverW = NULL;
2978 LPWSTR envW = NULL;
2979 BOOL ret;
2980 INT len;
2982 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2983 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2986 if (server) {
2987 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2988 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2989 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2992 if (env) {
2993 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2994 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2995 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2998 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2999 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
3001 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
3002 cbBuf, pcbNeeded);
3004 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
3005 cbBuf, NULL, NULL) > 0;
3008 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3009 HeapFree(GetProcessHeap(), 0, envW);
3010 HeapFree(GetProcessHeap(), 0, serverW);
3011 return ret;
3014 /*****************************************************************************
3015 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3017 * Return the PATH for the Print-Processors
3019 * PARAMS
3020 * server [I] Servername (NT only) or NULL (local Computer)
3021 * env [I] Printing-Environment (see below) or NULL (Default)
3022 * level [I] Structure-Level (must be 1)
3023 * Info [O] PTR to Buffer that receives the Result
3024 * cbBuf [I] Size of Buffer at "Info"
3025 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3026 * required for the Buffer at "Info"
3028 * RETURNS
3029 * Success: TRUE and in pcbNeeded the Bytes used in Info
3030 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3031 * if cbBuf is too small
3033 * Native Values returned in Info on Success:
3034 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3035 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3036 *| win9x(Windows 4.0): "%winsysdir%"
3038 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3040 * BUGS
3041 * Only NULL or "" is supported for server
3044 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3045 DWORD level, LPBYTE Info,
3046 DWORD cbBuf, LPDWORD pcbNeeded)
3049 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3050 Info, cbBuf, pcbNeeded);
3052 if ((backend == NULL) && !load_backend()) return FALSE;
3054 if (level != 1) {
3055 /* (Level != 1) is ignored in win9x */
3056 SetLastError(ERROR_INVALID_LEVEL);
3057 return FALSE;
3060 if (pcbNeeded == NULL) {
3061 /* (pcbNeeded == NULL) is ignored in win9x */
3062 SetLastError(RPC_X_NULL_REF_POINTER);
3063 return FALSE;
3066 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3069 /*****************************************************************************
3070 * WINSPOOL_OpenDriverReg [internal]
3072 * opens the registry for the printer drivers depending on the given input
3073 * variable pEnvironment
3075 * RETURNS:
3076 * the opened hkey on success
3077 * NULL on error
3079 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3081 HKEY retval = NULL;
3082 LPWSTR buffer;
3083 const printenv_t * env;
3085 TRACE("(%s)\n", debugstr_w(pEnvironment));
3087 env = validate_envW(pEnvironment);
3088 if (!env) return NULL;
3090 buffer = HeapAlloc( GetProcessHeap(), 0,
3091 (strlenW(DriversW) + strlenW(env->envname) +
3092 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3093 if(buffer) {
3094 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3095 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3096 HeapFree(GetProcessHeap(), 0, buffer);
3098 return retval;
3101 /*****************************************************************************
3102 * set_devices_and_printerports [internal]
3104 * set the [Devices] and [PrinterPorts] entries for a printer.
3107 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3109 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3110 WCHAR *devline;
3111 HKEY hkey;
3113 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3115 /* FIXME: the driver must change to "winspool" */
3116 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3117 if (devline) {
3118 lstrcpyW(devline, driver_nt);
3119 lstrcatW(devline, commaW);
3120 lstrcatW(devline, pi->pPortName);
3122 TRACE("using %s\n", debugstr_w(devline));
3123 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
3124 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3125 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3126 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3127 RegCloseKey(hkey);
3130 lstrcatW(devline, timeout_15_45);
3131 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
3132 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3133 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3134 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3135 RegCloseKey(hkey);
3137 HeapFree(GetProcessHeap(), 0, devline);
3141 /*****************************************************************************
3142 * AddPrinterW [WINSPOOL.@]
3144 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3146 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3147 LPDEVMODEW dm;
3148 HANDLE retval;
3149 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3150 LONG size;
3152 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3154 if(pName != NULL) {
3155 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3156 SetLastError(ERROR_INVALID_PARAMETER);
3157 return 0;
3159 if(Level != 2) {
3160 ERR("Level = %d, unsupported!\n", Level);
3161 SetLastError(ERROR_INVALID_LEVEL);
3162 return 0;
3164 if(!pPrinter) {
3165 SetLastError(ERROR_INVALID_PARAMETER);
3166 return 0;
3168 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3169 ERROR_SUCCESS) {
3170 ERR("Can't create Printers key\n");
3171 return 0;
3173 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3174 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3175 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3176 RegCloseKey(hkeyPrinter);
3177 RegCloseKey(hkeyPrinters);
3178 return 0;
3180 RegCloseKey(hkeyPrinter);
3182 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3183 if(!hkeyDrivers) {
3184 ERR("Can't create Drivers key\n");
3185 RegCloseKey(hkeyPrinters);
3186 return 0;
3188 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3189 ERROR_SUCCESS) {
3190 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3191 RegCloseKey(hkeyPrinters);
3192 RegCloseKey(hkeyDrivers);
3193 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3194 return 0;
3196 RegCloseKey(hkeyDriver);
3197 RegCloseKey(hkeyDrivers);
3199 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3200 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3201 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3202 RegCloseKey(hkeyPrinters);
3203 return 0;
3206 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3207 ERROR_SUCCESS) {
3208 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3209 SetLastError(ERROR_INVALID_PRINTER_NAME);
3210 RegCloseKey(hkeyPrinters);
3211 return 0;
3214 set_devices_and_printerports(pi);
3216 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3217 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3218 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3219 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3220 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3221 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3222 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3223 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3224 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3225 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3226 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3227 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3228 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3229 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3230 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3231 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3232 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3233 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3235 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3237 if (size < 0)
3239 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3240 size = sizeof(DEVMODEW);
3242 if(pi->pDevMode)
3243 dm = pi->pDevMode;
3244 else
3246 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3247 dm->dmSize = size;
3248 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3250 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3251 HeapFree( GetProcessHeap(), 0, dm );
3252 dm = NULL;
3254 else
3256 /* set devmode to printer name */
3257 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3261 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3262 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3264 RegCloseKey(hkeyPrinter);
3265 RegCloseKey(hkeyPrinters);
3266 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3267 ERR("OpenPrinter failing\n");
3268 return 0;
3270 return retval;
3273 /*****************************************************************************
3274 * AddPrinterA [WINSPOOL.@]
3276 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3278 UNICODE_STRING pNameW;
3279 PWSTR pwstrNameW;
3280 PRINTER_INFO_2W *piW;
3281 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3282 HANDLE ret;
3284 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3285 if(Level != 2) {
3286 ERR("Level = %d, unsupported!\n", Level);
3287 SetLastError(ERROR_INVALID_LEVEL);
3288 return 0;
3290 pwstrNameW = asciitounicode(&pNameW,pName);
3291 piW = printer_info_AtoW( piA, Level );
3293 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3295 free_printer_info( piW, Level );
3296 RtlFreeUnicodeString(&pNameW);
3297 return ret;
3301 /*****************************************************************************
3302 * ClosePrinter [WINSPOOL.@]
3304 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3306 UINT_PTR i = (UINT_PTR)hPrinter;
3307 opened_printer_t *printer = NULL;
3308 BOOL ret = FALSE;
3310 TRACE("(%p)\n", hPrinter);
3312 EnterCriticalSection(&printer_handles_cs);
3314 if ((i > 0) && (i <= nb_printer_handles))
3315 printer = printer_handles[i - 1];
3318 if(printer)
3320 struct list *cursor, *cursor2;
3322 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3324 if (printer->backend_printer) {
3325 backend->fpClosePrinter(printer->backend_printer);
3328 if(printer->doc)
3329 EndDocPrinter(hPrinter);
3331 if(InterlockedDecrement(&printer->queue->ref) == 0)
3333 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3335 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3336 ScheduleJob(hPrinter, job->job_id);
3338 HeapFree(GetProcessHeap(), 0, printer->queue);
3341 free_printer_entry( printer );
3342 printer_handles[i - 1] = NULL;
3343 ret = TRUE;
3345 LeaveCriticalSection(&printer_handles_cs);
3346 return ret;
3349 /*****************************************************************************
3350 * DeleteFormA [WINSPOOL.@]
3352 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3354 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3355 return TRUE;
3358 /*****************************************************************************
3359 * DeleteFormW [WINSPOOL.@]
3361 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3363 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3364 return TRUE;
3367 /*****************************************************************************
3368 * DeletePrinter [WINSPOOL.@]
3370 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3372 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3373 HKEY hkeyPrinters, hkey;
3374 WCHAR def[MAX_PATH];
3375 DWORD size = sizeof( def ) / sizeof( def[0] );
3377 if(!lpNameW) {
3378 SetLastError(ERROR_INVALID_HANDLE);
3379 return FALSE;
3381 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3382 RegDeleteTreeW(hkeyPrinters, lpNameW);
3383 RegCloseKey(hkeyPrinters);
3385 WriteProfileStringW(devicesW, lpNameW, NULL);
3386 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3388 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3389 RegDeleteValueW(hkey, lpNameW);
3390 RegCloseKey(hkey);
3393 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3394 RegDeleteValueW(hkey, lpNameW);
3395 RegCloseKey(hkey);
3398 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3400 WriteProfileStringW( windowsW, deviceW, NULL );
3401 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3403 RegDeleteValueW( hkey, deviceW );
3404 RegCloseKey( hkey );
3406 SetDefaultPrinterW( NULL );
3409 return TRUE;
3412 /*****************************************************************************
3413 * SetPrinterA [WINSPOOL.@]
3415 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3417 BYTE *dataW = data;
3418 BOOL ret;
3420 if (level != 0)
3422 dataW = printer_info_AtoW( data, level );
3423 if (!dataW) return FALSE;
3426 ret = SetPrinterW( printer, level, dataW, command );
3428 if (dataW != data) free_printer_info( dataW, level );
3430 return ret;
3433 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3435 set_reg_szW( key, NameW, pi->pPrinterName );
3436 set_reg_szW( key, Share_NameW, pi->pShareName );
3437 set_reg_szW( key, PortW, pi->pPortName );
3438 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3439 set_reg_szW( key, DescriptionW, pi->pComment );
3440 set_reg_szW( key, LocationW, pi->pLocation );
3442 if (pi->pDevMode)
3443 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3445 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3446 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3447 set_reg_szW( key, DatatypeW, pi->pDatatype );
3448 set_reg_szW( key, ParametersW, pi->pParameters );
3450 set_reg_DWORD( key, AttributesW, pi->Attributes );
3451 set_reg_DWORD( key, PriorityW, pi->Priority );
3452 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3453 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3454 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3457 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3459 if (!pi->pDevMode) return FALSE;
3461 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3462 return TRUE;
3465 /******************************************************************************
3466 * SetPrinterW [WINSPOOL.@]
3468 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3470 HKEY key;
3471 BOOL ret = FALSE;
3473 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3475 if (command != 0) FIXME( "Ignoring command %d\n", command );
3477 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3478 return FALSE;
3480 switch (level)
3482 case 2:
3484 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3485 set_printer_2( key, pi2 );
3486 ret = TRUE;
3487 break;
3490 case 9:
3492 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3493 ret = set_printer_9( key, pi );
3494 break;
3497 default:
3498 FIXME( "Unimplemented level %d\n", level );
3499 SetLastError( ERROR_INVALID_LEVEL );
3502 RegCloseKey( key );
3503 return ret;
3506 /*****************************************************************************
3507 * SetJobA [WINSPOOL.@]
3509 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3510 LPBYTE pJob, DWORD Command)
3512 BOOL ret;
3513 LPBYTE JobW;
3514 UNICODE_STRING usBuffer;
3516 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3518 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3519 are all ignored by SetJob, so we don't bother copying them */
3520 switch(Level)
3522 case 0:
3523 JobW = NULL;
3524 break;
3525 case 1:
3527 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3528 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3530 JobW = (LPBYTE)info1W;
3531 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3532 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3533 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3534 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3535 info1W->Status = info1A->Status;
3536 info1W->Priority = info1A->Priority;
3537 info1W->Position = info1A->Position;
3538 info1W->PagesPrinted = info1A->PagesPrinted;
3539 break;
3541 case 2:
3543 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3544 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3546 JobW = (LPBYTE)info2W;
3547 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3548 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3549 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3550 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3551 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3552 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3553 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3554 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3555 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3556 info2W->Status = info2A->Status;
3557 info2W->Priority = info2A->Priority;
3558 info2W->Position = info2A->Position;
3559 info2W->StartTime = info2A->StartTime;
3560 info2W->UntilTime = info2A->UntilTime;
3561 info2W->PagesPrinted = info2A->PagesPrinted;
3562 break;
3564 case 3:
3565 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3566 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3567 break;
3568 default:
3569 SetLastError(ERROR_INVALID_LEVEL);
3570 return FALSE;
3573 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3575 switch(Level)
3577 case 1:
3579 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3580 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3581 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3582 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3583 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3584 break;
3586 case 2:
3588 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3589 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3590 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3591 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3592 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3593 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3594 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3595 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3596 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3597 break;
3600 HeapFree(GetProcessHeap(), 0, JobW);
3602 return ret;
3605 /*****************************************************************************
3606 * SetJobW [WINSPOOL.@]
3608 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3609 LPBYTE pJob, DWORD Command)
3611 BOOL ret = FALSE;
3612 job_t *job;
3614 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3615 FIXME("Ignoring everything other than document title\n");
3617 EnterCriticalSection(&printer_handles_cs);
3618 job = get_job(hPrinter, JobId);
3619 if(!job)
3620 goto end;
3622 switch(Level)
3624 case 0:
3625 break;
3626 case 1:
3628 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3629 HeapFree(GetProcessHeap(), 0, job->document_title);
3630 job->document_title = strdupW(info1->pDocument);
3631 break;
3633 case 2:
3635 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3636 HeapFree(GetProcessHeap(), 0, job->document_title);
3637 job->document_title = strdupW(info2->pDocument);
3638 HeapFree(GetProcessHeap(), 0, job->devmode);
3639 job->devmode = dup_devmode( info2->pDevMode );
3640 break;
3642 case 3:
3643 break;
3644 default:
3645 SetLastError(ERROR_INVALID_LEVEL);
3646 goto end;
3648 ret = TRUE;
3649 end:
3650 LeaveCriticalSection(&printer_handles_cs);
3651 return ret;
3654 /*****************************************************************************
3655 * EndDocPrinter [WINSPOOL.@]
3657 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3659 opened_printer_t *printer;
3660 BOOL ret = FALSE;
3661 TRACE("(%p)\n", hPrinter);
3663 EnterCriticalSection(&printer_handles_cs);
3665 printer = get_opened_printer(hPrinter);
3666 if(!printer)
3668 SetLastError(ERROR_INVALID_HANDLE);
3669 goto end;
3672 if(!printer->doc)
3674 SetLastError(ERROR_SPL_NO_STARTDOC);
3675 goto end;
3678 CloseHandle(printer->doc->hf);
3679 ScheduleJob(hPrinter, printer->doc->job_id);
3680 HeapFree(GetProcessHeap(), 0, printer->doc);
3681 printer->doc = NULL;
3682 ret = TRUE;
3683 end:
3684 LeaveCriticalSection(&printer_handles_cs);
3685 return ret;
3688 /*****************************************************************************
3689 * EndPagePrinter [WINSPOOL.@]
3691 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3693 FIXME("(%p): stub\n", hPrinter);
3694 return TRUE;
3697 /*****************************************************************************
3698 * StartDocPrinterA [WINSPOOL.@]
3700 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3702 UNICODE_STRING usBuffer;
3703 DOC_INFO_2W doc2W;
3704 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3705 DWORD ret;
3707 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3708 or one (DOC_INFO_3) extra DWORDs */
3710 switch(Level) {
3711 case 2:
3712 doc2W.JobId = doc2->JobId;
3713 /* fall through */
3714 case 3:
3715 doc2W.dwMode = doc2->dwMode;
3716 /* fall through */
3717 case 1:
3718 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3719 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3720 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3721 break;
3723 default:
3724 SetLastError(ERROR_INVALID_LEVEL);
3725 return FALSE;
3728 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3730 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3731 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3732 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3734 return ret;
3737 /*****************************************************************************
3738 * StartDocPrinterW [WINSPOOL.@]
3740 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3742 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3743 opened_printer_t *printer;
3744 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3745 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3746 JOB_INFO_1W job_info;
3747 DWORD needed, ret = 0;
3748 HANDLE hf;
3749 WCHAR *filename;
3750 job_t *job;
3752 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3753 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3754 debugstr_w(doc->pDatatype));
3756 if(Level < 1 || Level > 3)
3758 SetLastError(ERROR_INVALID_LEVEL);
3759 return 0;
3762 EnterCriticalSection(&printer_handles_cs);
3763 printer = get_opened_printer(hPrinter);
3764 if(!printer)
3766 SetLastError(ERROR_INVALID_HANDLE);
3767 goto end;
3770 if(printer->doc)
3772 SetLastError(ERROR_INVALID_PRINTER_STATE);
3773 goto end;
3776 /* Even if we're printing to a file we still add a print job, we'll
3777 just ignore the spool file name */
3779 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3781 ERR("AddJob failed gle %u\n", GetLastError());
3782 goto end;
3785 /* use pOutputFile only, when it is a real filename */
3786 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3787 filename = doc->pOutputFile;
3788 else
3789 filename = addjob->Path;
3791 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3792 if(hf == INVALID_HANDLE_VALUE)
3793 goto end;
3795 memset(&job_info, 0, sizeof(job_info));
3796 job_info.pDocument = doc->pDocName;
3797 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3799 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3800 printer->doc->hf = hf;
3801 ret = printer->doc->job_id = addjob->JobId;
3802 job = get_job(hPrinter, ret);
3803 job->portname = strdupW(doc->pOutputFile);
3805 end:
3806 LeaveCriticalSection(&printer_handles_cs);
3808 return ret;
3811 /*****************************************************************************
3812 * StartPagePrinter [WINSPOOL.@]
3814 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3816 FIXME("(%p): stub\n", hPrinter);
3817 return TRUE;
3820 /*****************************************************************************
3821 * GetFormA [WINSPOOL.@]
3823 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3824 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3826 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3827 Level,pForm,cbBuf,pcbNeeded);
3828 return FALSE;
3831 /*****************************************************************************
3832 * GetFormW [WINSPOOL.@]
3834 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3835 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3837 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3838 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3839 return FALSE;
3842 /*****************************************************************************
3843 * SetFormA [WINSPOOL.@]
3845 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3846 LPBYTE pForm)
3848 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3849 return FALSE;
3852 /*****************************************************************************
3853 * SetFormW [WINSPOOL.@]
3855 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3856 LPBYTE pForm)
3858 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3859 return FALSE;
3862 /*****************************************************************************
3863 * ReadPrinter [WINSPOOL.@]
3865 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3866 LPDWORD pNoBytesRead)
3868 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3869 return FALSE;
3872 /*****************************************************************************
3873 * ResetPrinterA [WINSPOOL.@]
3875 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3877 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3878 return FALSE;
3881 /*****************************************************************************
3882 * ResetPrinterW [WINSPOOL.@]
3884 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3886 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3887 return FALSE;
3890 /*****************************************************************************
3891 * get_filename_from_reg [internal]
3893 * Get ValueName from hkey storing result in out
3894 * when the Value in the registry has only a filename, use driverdir as prefix
3895 * outlen is space left in out
3896 * String is stored either as unicode or ascii
3900 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3901 LPBYTE out, DWORD outlen, LPDWORD needed)
3903 WCHAR filename[MAX_PATH];
3904 DWORD size;
3905 DWORD type;
3906 LONG ret;
3907 LPWSTR buffer = filename;
3908 LPWSTR ptr;
3910 *needed = 0;
3911 size = sizeof(filename);
3912 buffer[0] = '\0';
3913 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3914 if (ret == ERROR_MORE_DATA) {
3915 TRACE("need dynamic buffer: %u\n", size);
3916 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3917 if (!buffer) {
3918 /* No Memory is bad */
3919 return FALSE;
3921 buffer[0] = '\0';
3922 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3925 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3926 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3927 return FALSE;
3930 ptr = buffer;
3931 while (ptr) {
3932 /* do we have a full path ? */
3933 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3934 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3936 if (!ret) {
3937 /* we must build the full Path */
3938 *needed += dirlen;
3939 if ((out) && (outlen > dirlen)) {
3940 lstrcpyW((LPWSTR)out, driverdir);
3941 out += dirlen;
3942 outlen -= dirlen;
3944 else
3945 out = NULL;
3948 /* write the filename */
3949 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3950 if ((out) && (outlen >= size)) {
3951 lstrcpyW((LPWSTR)out, ptr);
3952 out += size;
3953 outlen -= size;
3955 else
3956 out = NULL;
3957 *needed += size;
3958 ptr += lstrlenW(ptr)+1;
3959 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3962 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3964 /* write the multisz-termination */
3965 if (type == REG_MULTI_SZ) {
3966 size = sizeof(WCHAR);
3968 *needed += size;
3969 if (out && (outlen >= size)) {
3970 memset (out, 0, size);
3973 return TRUE;
3976 /*****************************************************************************
3977 * WINSPOOL_GetStringFromReg
3979 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3980 * String is stored as unicode.
3982 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3983 DWORD buflen, DWORD *needed)
3985 DWORD sz = buflen, type;
3986 LONG ret;
3988 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3989 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3990 WARN("Got ret = %d\n", ret);
3991 *needed = 0;
3992 return FALSE;
3994 /* add space for terminating '\0' */
3995 sz += sizeof(WCHAR);
3996 *needed = sz;
3998 if (ptr)
3999 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
4001 return TRUE;
4004 /*****************************************************************************
4005 * WINSPOOL_GetDefaultDevMode
4007 * Get a default DevMode values for wineps.
4009 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr, DWORD buflen, DWORD *needed)
4011 static const WCHAR winepsW[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4013 if (buflen >= sizeof(DEVMODEW))
4015 DEVMODEW *dm = (DEVMODEW *)ptr;
4017 /* the driver will update registry with real values */
4018 memset(dm, 0, sizeof(*dm));
4019 dm->dmSize = sizeof(*dm);
4020 lstrcpyW(dm->dmDeviceName, winepsW);
4022 *needed = sizeof(DEVMODEW);
4025 /*****************************************************************************
4026 * WINSPOOL_GetDevModeFromReg
4028 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4029 * DevMode is stored either as unicode or ascii.
4031 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4032 LPBYTE ptr,
4033 DWORD buflen, DWORD *needed)
4035 DWORD sz = buflen, type;
4036 LONG ret;
4038 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4039 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4040 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4041 if (sz < sizeof(DEVMODEA))
4043 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4044 return FALSE;
4046 /* ensures that dmSize is not erratically bogus if registry is invalid */
4047 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4048 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4049 sz += (CCHDEVICENAME + CCHFORMNAME);
4050 if (ptr && (buflen >= sz)) {
4051 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4052 memcpy(ptr, dmW, sz);
4053 HeapFree(GetProcessHeap(),0,dmW);
4055 *needed = sz;
4056 return TRUE;
4059 /*********************************************************************
4060 * WINSPOOL_GetPrinter_1
4062 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4064 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4065 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4067 DWORD size, left = cbBuf;
4068 BOOL space = (cbBuf > 0);
4069 LPBYTE ptr = buf;
4071 *pcbNeeded = 0;
4073 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4074 if(space && size <= left) {
4075 pi1->pName = (LPWSTR)ptr;
4076 ptr += size;
4077 left -= size;
4078 } else
4079 space = FALSE;
4080 *pcbNeeded += size;
4083 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4084 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4085 if(space && size <= left) {
4086 pi1->pDescription = (LPWSTR)ptr;
4087 ptr += size;
4088 left -= size;
4089 } else
4090 space = FALSE;
4091 *pcbNeeded += size;
4094 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4095 if(space && size <= left) {
4096 pi1->pComment = (LPWSTR)ptr;
4097 ptr += size;
4098 left -= size;
4099 } else
4100 space = FALSE;
4101 *pcbNeeded += size;
4104 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4106 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4107 memset(pi1, 0, sizeof(*pi1));
4109 return space;
4111 /*********************************************************************
4112 * WINSPOOL_GetPrinter_2
4114 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4116 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4117 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4119 DWORD size, left = cbBuf;
4120 BOOL space = (cbBuf > 0);
4121 LPBYTE ptr = buf;
4123 *pcbNeeded = 0;
4125 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4126 if(space && size <= left) {
4127 pi2->pPrinterName = (LPWSTR)ptr;
4128 ptr += size;
4129 left -= size;
4130 } else
4131 space = FALSE;
4132 *pcbNeeded += size;
4134 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4135 if(space && size <= left) {
4136 pi2->pShareName = (LPWSTR)ptr;
4137 ptr += size;
4138 left -= size;
4139 } else
4140 space = FALSE;
4141 *pcbNeeded += size;
4143 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4144 if(space && size <= left) {
4145 pi2->pPortName = (LPWSTR)ptr;
4146 ptr += size;
4147 left -= size;
4148 } else
4149 space = FALSE;
4150 *pcbNeeded += size;
4152 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4153 if(space && size <= left) {
4154 pi2->pDriverName = (LPWSTR)ptr;
4155 ptr += size;
4156 left -= size;
4157 } else
4158 space = FALSE;
4159 *pcbNeeded += size;
4161 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4162 if(space && size <= left) {
4163 pi2->pComment = (LPWSTR)ptr;
4164 ptr += size;
4165 left -= size;
4166 } else
4167 space = FALSE;
4168 *pcbNeeded += size;
4170 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4171 if(space && size <= left) {
4172 pi2->pLocation = (LPWSTR)ptr;
4173 ptr += size;
4174 left -= size;
4175 } else
4176 space = FALSE;
4177 *pcbNeeded += size;
4179 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4180 if(space && size <= left) {
4181 pi2->pDevMode = (LPDEVMODEW)ptr;
4182 ptr += size;
4183 left -= size;
4184 } else
4185 space = FALSE;
4186 *pcbNeeded += size;
4188 else
4190 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4191 if(space && size <= left) {
4192 pi2->pDevMode = (LPDEVMODEW)ptr;
4193 ptr += size;
4194 left -= size;
4195 } else
4196 space = FALSE;
4197 *pcbNeeded += size;
4199 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4200 if(space && size <= left) {
4201 pi2->pSepFile = (LPWSTR)ptr;
4202 ptr += size;
4203 left -= size;
4204 } else
4205 space = FALSE;
4206 *pcbNeeded += size;
4208 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4209 if(space && size <= left) {
4210 pi2->pPrintProcessor = (LPWSTR)ptr;
4211 ptr += size;
4212 left -= size;
4213 } else
4214 space = FALSE;
4215 *pcbNeeded += size;
4217 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4218 if(space && size <= left) {
4219 pi2->pDatatype = (LPWSTR)ptr;
4220 ptr += size;
4221 left -= size;
4222 } else
4223 space = FALSE;
4224 *pcbNeeded += size;
4226 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4227 if(space && size <= left) {
4228 pi2->pParameters = (LPWSTR)ptr;
4229 ptr += size;
4230 left -= size;
4231 } else
4232 space = FALSE;
4233 *pcbNeeded += size;
4235 if(pi2) {
4236 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4237 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4238 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4239 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4240 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4243 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4244 memset(pi2, 0, sizeof(*pi2));
4246 return space;
4249 /*********************************************************************
4250 * WINSPOOL_GetPrinter_4
4252 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4254 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4255 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4257 DWORD size, left = cbBuf;
4258 BOOL space = (cbBuf > 0);
4259 LPBYTE ptr = buf;
4261 *pcbNeeded = 0;
4263 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4264 if(space && size <= left) {
4265 pi4->pPrinterName = (LPWSTR)ptr;
4266 ptr += size;
4267 left -= size;
4268 } else
4269 space = FALSE;
4270 *pcbNeeded += size;
4272 if(pi4) {
4273 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4276 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4277 memset(pi4, 0, sizeof(*pi4));
4279 return space;
4282 /*********************************************************************
4283 * WINSPOOL_GetPrinter_5
4285 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4287 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4288 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4290 DWORD size, left = cbBuf;
4291 BOOL space = (cbBuf > 0);
4292 LPBYTE ptr = buf;
4294 *pcbNeeded = 0;
4296 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4297 if(space && size <= left) {
4298 pi5->pPrinterName = (LPWSTR)ptr;
4299 ptr += size;
4300 left -= size;
4301 } else
4302 space = FALSE;
4303 *pcbNeeded += size;
4305 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4306 if(space && size <= left) {
4307 pi5->pPortName = (LPWSTR)ptr;
4308 ptr += size;
4309 left -= size;
4310 } else
4311 space = FALSE;
4312 *pcbNeeded += size;
4314 if(pi5) {
4315 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4316 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4317 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4320 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4321 memset(pi5, 0, sizeof(*pi5));
4323 return space;
4326 /*********************************************************************
4327 * WINSPOOL_GetPrinter_7
4329 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4331 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4332 DWORD cbBuf, LPDWORD pcbNeeded)
4334 DWORD size, left = cbBuf;
4335 BOOL space = (cbBuf > 0);
4336 LPBYTE ptr = buf;
4338 *pcbNeeded = 0;
4340 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4342 ptr = NULL;
4343 size = sizeof(pi7->pszObjectGUID);
4345 if (space && size <= left) {
4346 pi7->pszObjectGUID = (LPWSTR)ptr;
4347 ptr += size;
4348 left -= size;
4349 } else
4350 space = FALSE;
4351 *pcbNeeded += size;
4352 if (pi7) {
4353 /* We do not have a Directory Service */
4354 pi7->dwAction = DSPRINT_UNPUBLISH;
4357 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4358 memset(pi7, 0, sizeof(*pi7));
4360 return space;
4363 /*********************************************************************
4364 * WINSPOOL_GetPrinter_9
4366 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4368 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4369 DWORD cbBuf, LPDWORD pcbNeeded)
4371 DWORD size;
4372 BOOL space = (cbBuf > 0);
4374 *pcbNeeded = 0;
4376 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4377 if(space && size <= cbBuf) {
4378 pi9->pDevMode = (LPDEVMODEW)buf;
4379 } else
4380 space = FALSE;
4381 *pcbNeeded += size;
4383 else
4385 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4386 if(space && size <= cbBuf) {
4387 pi9->pDevMode = (LPDEVMODEW)buf;
4388 } else
4389 space = FALSE;
4390 *pcbNeeded += size;
4393 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4394 memset(pi9, 0, sizeof(*pi9));
4396 return space;
4399 /*****************************************************************************
4400 * GetPrinterW [WINSPOOL.@]
4402 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4403 DWORD cbBuf, LPDWORD pcbNeeded)
4405 DWORD size, needed = 0, err;
4406 LPBYTE ptr = NULL;
4407 HKEY hkeyPrinter;
4408 BOOL ret;
4410 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4412 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4413 if (err)
4415 SetLastError( err );
4416 return FALSE;
4419 switch(Level) {
4420 case 2:
4422 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4424 size = sizeof(PRINTER_INFO_2W);
4425 if(size <= cbBuf) {
4426 ptr = pPrinter + size;
4427 cbBuf -= size;
4428 memset(pPrinter, 0, size);
4429 } else {
4430 pi2 = NULL;
4431 cbBuf = 0;
4433 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4434 needed += size;
4435 break;
4438 case 4:
4440 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4442 size = sizeof(PRINTER_INFO_4W);
4443 if(size <= cbBuf) {
4444 ptr = pPrinter + size;
4445 cbBuf -= size;
4446 memset(pPrinter, 0, size);
4447 } else {
4448 pi4 = NULL;
4449 cbBuf = 0;
4451 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4452 needed += size;
4453 break;
4457 case 5:
4459 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4461 size = sizeof(PRINTER_INFO_5W);
4462 if(size <= cbBuf) {
4463 ptr = pPrinter + size;
4464 cbBuf -= size;
4465 memset(pPrinter, 0, size);
4466 } else {
4467 pi5 = NULL;
4468 cbBuf = 0;
4471 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4472 needed += size;
4473 break;
4477 case 6:
4479 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4481 size = sizeof(PRINTER_INFO_6);
4482 if (size <= cbBuf) {
4483 /* FIXME: We do not update the status yet */
4484 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4485 ret = TRUE;
4486 } else {
4487 ret = FALSE;
4490 needed += size;
4491 break;
4494 case 7:
4496 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4498 size = sizeof(PRINTER_INFO_7W);
4499 if (size <= cbBuf) {
4500 ptr = pPrinter + size;
4501 cbBuf -= size;
4502 memset(pPrinter, 0, size);
4503 } else {
4504 pi7 = NULL;
4505 cbBuf = 0;
4508 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4509 needed += size;
4510 break;
4514 case 8:
4515 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4516 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4517 /* fall through */
4518 case 9:
4520 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4522 size = sizeof(PRINTER_INFO_9W);
4523 if(size <= cbBuf) {
4524 ptr = pPrinter + size;
4525 cbBuf -= size;
4526 memset(pPrinter, 0, size);
4527 } else {
4528 pi9 = NULL;
4529 cbBuf = 0;
4532 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4533 needed += size;
4534 break;
4538 default:
4539 FIXME("Unimplemented level %d\n", Level);
4540 SetLastError(ERROR_INVALID_LEVEL);
4541 RegCloseKey(hkeyPrinter);
4542 return FALSE;
4545 RegCloseKey(hkeyPrinter);
4547 TRACE("returning %d needed = %d\n", ret, needed);
4548 if(pcbNeeded) *pcbNeeded = needed;
4549 if(!ret)
4550 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4551 return ret;
4554 /*****************************************************************************
4555 * GetPrinterA [WINSPOOL.@]
4557 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4558 DWORD cbBuf, LPDWORD pcbNeeded)
4560 BOOL ret;
4561 LPBYTE buf = NULL;
4563 if (cbBuf)
4564 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4566 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4567 if (ret)
4568 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4569 HeapFree(GetProcessHeap(), 0, buf);
4571 return ret;
4574 /*****************************************************************************
4575 * WINSPOOL_EnumPrintersW
4577 * Implementation of EnumPrintersW
4579 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4580 DWORD dwLevel, LPBYTE lpbPrinters,
4581 DWORD cbBuf, LPDWORD lpdwNeeded,
4582 LPDWORD lpdwReturned)
4585 HKEY hkeyPrinters, hkeyPrinter;
4586 WCHAR PrinterName[255];
4587 DWORD needed = 0, number = 0;
4588 DWORD used, i, left;
4589 PBYTE pi, buf;
4591 if(lpbPrinters)
4592 memset(lpbPrinters, 0, cbBuf);
4593 if(lpdwReturned)
4594 *lpdwReturned = 0;
4595 if(lpdwNeeded)
4596 *lpdwNeeded = 0;
4598 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4599 if(dwType == PRINTER_ENUM_DEFAULT)
4600 return TRUE;
4602 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4603 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4604 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4605 if (!dwType) {
4606 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4607 return TRUE;
4612 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4613 FIXME("dwType = %08x\n", dwType);
4614 SetLastError(ERROR_INVALID_FLAGS);
4615 return FALSE;
4618 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4619 ERROR_SUCCESS) {
4620 ERR("Can't create Printers key\n");
4621 return FALSE;
4624 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4625 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4626 RegCloseKey(hkeyPrinters);
4627 ERR("Can't query Printers key\n");
4628 return FALSE;
4630 TRACE("Found %d printers\n", number);
4632 switch(dwLevel) {
4633 case 1:
4634 used = number * sizeof(PRINTER_INFO_1W);
4635 break;
4636 case 2:
4637 used = number * sizeof(PRINTER_INFO_2W);
4638 break;
4639 case 4:
4640 used = number * sizeof(PRINTER_INFO_4W);
4641 break;
4642 case 5:
4643 used = number * sizeof(PRINTER_INFO_5W);
4644 break;
4646 default:
4647 SetLastError(ERROR_INVALID_LEVEL);
4648 RegCloseKey(hkeyPrinters);
4649 return FALSE;
4651 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4653 for(i = 0; i < number; i++) {
4654 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4655 ERROR_SUCCESS) {
4656 ERR("Can't enum key number %d\n", i);
4657 RegCloseKey(hkeyPrinters);
4658 return FALSE;
4660 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4661 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4662 ERROR_SUCCESS) {
4663 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4664 RegCloseKey(hkeyPrinters);
4665 return FALSE;
4668 if(cbBuf > used) {
4669 buf = lpbPrinters + used;
4670 left = cbBuf - used;
4671 } else {
4672 buf = NULL;
4673 left = 0;
4676 switch(dwLevel) {
4677 case 1:
4678 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4679 left, &needed);
4680 used += needed;
4681 if(pi) pi += sizeof(PRINTER_INFO_1W);
4682 break;
4683 case 2:
4684 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4685 left, &needed);
4686 used += needed;
4687 if(pi) pi += sizeof(PRINTER_INFO_2W);
4688 break;
4689 case 4:
4690 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4691 left, &needed);
4692 used += needed;
4693 if(pi) pi += sizeof(PRINTER_INFO_4W);
4694 break;
4695 case 5:
4696 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4697 left, &needed);
4698 used += needed;
4699 if(pi) pi += sizeof(PRINTER_INFO_5W);
4700 break;
4701 default:
4702 ERR("Shouldn't be here!\n");
4703 RegCloseKey(hkeyPrinter);
4704 RegCloseKey(hkeyPrinters);
4705 return FALSE;
4707 RegCloseKey(hkeyPrinter);
4709 RegCloseKey(hkeyPrinters);
4711 if(lpdwNeeded)
4712 *lpdwNeeded = used;
4714 if(used > cbBuf) {
4715 if(lpbPrinters)
4716 memset(lpbPrinters, 0, cbBuf);
4717 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4718 return FALSE;
4720 if(lpdwReturned)
4721 *lpdwReturned = number;
4722 SetLastError(ERROR_SUCCESS);
4723 return TRUE;
4727 /******************************************************************
4728 * EnumPrintersW [WINSPOOL.@]
4730 * Enumerates the available printers, print servers and print
4731 * providers, depending on the specified flags, name and level.
4733 * RETURNS:
4735 * If level is set to 1:
4736 * Returns an array of PRINTER_INFO_1 data structures in the
4737 * lpbPrinters buffer.
4739 * If level is set to 2:
4740 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4741 * Returns an array of PRINTER_INFO_2 data structures in the
4742 * lpbPrinters buffer. Note that according to MSDN also an
4743 * OpenPrinter should be performed on every remote printer.
4745 * If level is set to 4 (officially WinNT only):
4746 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4747 * Fast: Only the registry is queried to retrieve printer names,
4748 * no connection to the driver is made.
4749 * Returns an array of PRINTER_INFO_4 data structures in the
4750 * lpbPrinters buffer.
4752 * If level is set to 5 (officially WinNT4/Win9x only):
4753 * Fast: Only the registry is queried to retrieve printer names,
4754 * no connection to the driver is made.
4755 * Returns an array of PRINTER_INFO_5 data structures in the
4756 * lpbPrinters buffer.
4758 * If level set to 3 or 6+:
4759 * returns zero (failure!)
4761 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4762 * for information.
4764 * BUGS:
4765 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4766 * - Only levels 2, 4 and 5 are implemented at the moment.
4767 * - 16-bit printer drivers are not enumerated.
4768 * - Returned amount of bytes used/needed does not match the real Windoze
4769 * implementation (as in this implementation, all strings are part
4770 * of the buffer, whereas Win32 keeps them somewhere else)
4771 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4773 * NOTE:
4774 * - In a regular Wine installation, no registry settings for printers
4775 * exist, which makes this function return an empty list.
4777 BOOL WINAPI EnumPrintersW(
4778 DWORD dwType, /* [in] Types of print objects to enumerate */
4779 LPWSTR lpszName, /* [in] name of objects to enumerate */
4780 DWORD dwLevel, /* [in] type of printer info structure */
4781 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4782 DWORD cbBuf, /* [in] max size of buffer in bytes */
4783 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4784 LPDWORD lpdwReturned /* [out] number of entries returned */
4787 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4788 lpdwNeeded, lpdwReturned);
4791 /******************************************************************
4792 * EnumPrintersA [WINSPOOL.@]
4794 * See EnumPrintersW
4797 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4798 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4800 BOOL ret;
4801 UNICODE_STRING pNameU;
4802 LPWSTR pNameW;
4803 LPBYTE pPrintersW;
4805 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4806 pPrinters, cbBuf, pcbNeeded, pcReturned);
4808 pNameW = asciitounicode(&pNameU, pName);
4810 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4811 MS Office need this */
4812 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4814 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4816 RtlFreeUnicodeString(&pNameU);
4817 if (ret) {
4818 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4820 HeapFree(GetProcessHeap(), 0, pPrintersW);
4821 return ret;
4824 /*****************************************************************************
4825 * WINSPOOL_GetDriverInfoFromReg [internal]
4827 * Enters the information from the registry into the DRIVER_INFO struct
4829 * RETURNS
4830 * zero if the printer driver does not exist in the registry
4831 * (only if Level > 1) otherwise nonzero
4833 static BOOL WINSPOOL_GetDriverInfoFromReg(
4834 HKEY hkeyDrivers,
4835 LPWSTR DriverName,
4836 const printenv_t * env,
4837 DWORD Level,
4838 LPBYTE ptr, /* DRIVER_INFO */
4839 LPBYTE pDriverStrings, /* strings buffer */
4840 DWORD cbBuf, /* size of string buffer */
4841 LPDWORD pcbNeeded) /* space needed for str. */
4843 DWORD size, tmp;
4844 HKEY hkeyDriver;
4845 WCHAR driverdir[MAX_PATH];
4846 DWORD dirlen;
4847 LPBYTE strPtr = pDriverStrings;
4848 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4850 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4851 debugstr_w(DriverName), env,
4852 Level, di, pDriverStrings, cbBuf);
4854 if (di) ZeroMemory(di, di_sizeof[Level]);
4856 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4857 if (*pcbNeeded <= cbBuf)
4858 strcpyW((LPWSTR)strPtr, DriverName);
4860 /* pName for level 1 has a different offset! */
4861 if (Level == 1) {
4862 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4863 return TRUE;
4866 /* .cVersion and .pName for level > 1 */
4867 if (di) {
4868 di->cVersion = env->driverversion;
4869 di->pName = (LPWSTR) strPtr;
4870 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4873 /* Reserve Space for the largest subdir and a Backslash*/
4874 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4875 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4876 /* Should never Fail */
4877 return FALSE;
4879 lstrcatW(driverdir, env->versionsubdir);
4880 lstrcatW(driverdir, backslashW);
4882 /* dirlen must not include the terminating zero */
4883 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4885 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4886 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4887 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4888 return FALSE;
4891 /* pEnvironment */
4892 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4894 *pcbNeeded += size;
4895 if (*pcbNeeded <= cbBuf) {
4896 lstrcpyW((LPWSTR)strPtr, env->envname);
4897 if (di) di->pEnvironment = (LPWSTR)strPtr;
4898 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4901 /* .pDriverPath is the Graphics rendering engine.
4902 The full Path is required to avoid a crash in some apps */
4903 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4904 *pcbNeeded += size;
4905 if (*pcbNeeded <= cbBuf)
4906 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4908 if (di) di->pDriverPath = (LPWSTR)strPtr;
4909 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4912 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4913 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4914 *pcbNeeded += size;
4915 if (*pcbNeeded <= cbBuf)
4916 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4918 if (di) di->pDataFile = (LPWSTR)strPtr;
4919 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4922 /* .pConfigFile is the Driver user Interface */
4923 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4924 *pcbNeeded += size;
4925 if (*pcbNeeded <= cbBuf)
4926 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4928 if (di) di->pConfigFile = (LPWSTR)strPtr;
4929 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4932 if (Level == 2 ) {
4933 RegCloseKey(hkeyDriver);
4934 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4935 return TRUE;
4938 if (Level == 5 ) {
4939 RegCloseKey(hkeyDriver);
4940 FIXME("level 5: incomplete\n");
4941 return TRUE;
4944 /* .pHelpFile */
4945 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4946 *pcbNeeded += size;
4947 if (*pcbNeeded <= cbBuf)
4948 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4950 if (di) di->pHelpFile = (LPWSTR)strPtr;
4951 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4954 /* .pDependentFiles */
4955 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4956 *pcbNeeded += size;
4957 if (*pcbNeeded <= cbBuf)
4958 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4960 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4961 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4963 else if (GetVersion() & 0x80000000) {
4964 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4965 size = 2 * sizeof(WCHAR);
4966 *pcbNeeded += size;
4967 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4969 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4970 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4973 /* .pMonitorName is the optional Language Monitor */
4974 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4975 *pcbNeeded += size;
4976 if (*pcbNeeded <= cbBuf)
4977 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4979 if (di) di->pMonitorName = (LPWSTR)strPtr;
4980 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4983 /* .pDefaultDataType */
4984 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4985 *pcbNeeded += size;
4986 if(*pcbNeeded <= cbBuf)
4987 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4989 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4990 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4993 if (Level == 3 ) {
4994 RegCloseKey(hkeyDriver);
4995 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4996 return TRUE;
4999 /* .pszzPreviousNames */
5000 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
5001 *pcbNeeded += size;
5002 if(*pcbNeeded <= cbBuf)
5003 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
5005 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
5006 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5009 if (Level == 4 ) {
5010 RegCloseKey(hkeyDriver);
5011 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5012 return TRUE;
5015 /* support is missing, but not important enough for a FIXME */
5016 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5018 /* .pszMfgName */
5019 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5020 *pcbNeeded += size;
5021 if(*pcbNeeded <= cbBuf)
5022 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5024 if (di) di->pszMfgName = (LPWSTR)strPtr;
5025 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5028 /* .pszOEMUrl */
5029 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5030 *pcbNeeded += size;
5031 if(*pcbNeeded <= cbBuf)
5032 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5034 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5035 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5038 /* .pszHardwareID */
5039 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5040 *pcbNeeded += size;
5041 if(*pcbNeeded <= cbBuf)
5042 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5044 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5045 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5048 /* .pszProvider */
5049 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5050 *pcbNeeded += size;
5051 if(*pcbNeeded <= cbBuf)
5052 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5054 if (di) di->pszProvider = (LPWSTR)strPtr;
5055 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5058 if (Level == 6 ) {
5059 RegCloseKey(hkeyDriver);
5060 return TRUE;
5063 /* support is missing, but not important enough for a FIXME */
5064 TRACE("level 8: incomplete\n");
5066 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5067 RegCloseKey(hkeyDriver);
5068 return TRUE;
5071 /*****************************************************************************
5072 * GetPrinterDriverW [WINSPOOL.@]
5074 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5075 DWORD Level, LPBYTE pDriverInfo,
5076 DWORD cbBuf, LPDWORD pcbNeeded)
5078 LPCWSTR name;
5079 WCHAR DriverName[100];
5080 DWORD ret, type, size, needed = 0;
5081 LPBYTE ptr = NULL;
5082 HKEY hkeyPrinter, hkeyDrivers;
5083 const printenv_t * env;
5085 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5086 Level,pDriverInfo,cbBuf, pcbNeeded);
5088 if (cbBuf > 0)
5089 ZeroMemory(pDriverInfo, cbBuf);
5091 if (!(name = get_opened_printer_name(hPrinter))) {
5092 SetLastError(ERROR_INVALID_HANDLE);
5093 return FALSE;
5096 if (Level < 1 || Level == 7 || Level > 8) {
5097 SetLastError(ERROR_INVALID_LEVEL);
5098 return FALSE;
5101 env = validate_envW(pEnvironment);
5102 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5104 ret = open_printer_reg_key( name, &hkeyPrinter );
5105 if (ret)
5107 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5108 SetLastError( ret );
5109 return FALSE;
5112 size = sizeof(DriverName);
5113 DriverName[0] = 0;
5114 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5115 (LPBYTE)DriverName, &size);
5116 RegCloseKey(hkeyPrinter);
5117 if(ret != ERROR_SUCCESS) {
5118 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5119 return FALSE;
5122 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5123 if(!hkeyDrivers) {
5124 ERR("Can't create Drivers key\n");
5125 return FALSE;
5128 size = di_sizeof[Level];
5129 if ((size <= cbBuf) && pDriverInfo)
5130 ptr = pDriverInfo + size;
5132 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5133 env, Level, pDriverInfo, ptr,
5134 (cbBuf < size) ? 0 : cbBuf - size,
5135 &needed)) {
5136 RegCloseKey(hkeyDrivers);
5137 return FALSE;
5140 RegCloseKey(hkeyDrivers);
5142 if(pcbNeeded) *pcbNeeded = size + needed;
5143 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5144 if(cbBuf >= size + needed) return TRUE;
5145 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5146 return FALSE;
5149 /*****************************************************************************
5150 * GetPrinterDriverA [WINSPOOL.@]
5152 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5153 DWORD Level, LPBYTE pDriverInfo,
5154 DWORD cbBuf, LPDWORD pcbNeeded)
5156 BOOL ret;
5157 UNICODE_STRING pEnvW;
5158 PWSTR pwstrEnvW;
5159 LPBYTE buf = NULL;
5161 if (cbBuf)
5163 ZeroMemory(pDriverInfo, cbBuf);
5164 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5167 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5168 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5169 cbBuf, pcbNeeded);
5170 if (ret)
5171 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5173 HeapFree(GetProcessHeap(), 0, buf);
5175 RtlFreeUnicodeString(&pEnvW);
5176 return ret;
5179 /*****************************************************************************
5180 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5182 * Return the PATH for the Printer-Drivers (UNICODE)
5184 * PARAMS
5185 * pName [I] Servername (NT only) or NULL (local Computer)
5186 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5187 * Level [I] Structure-Level (must be 1)
5188 * pDriverDirectory [O] PTR to Buffer that receives the Result
5189 * cbBuf [I] Size of Buffer at pDriverDirectory
5190 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5191 * required for pDriverDirectory
5193 * RETURNS
5194 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5195 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5196 * if cbBuf is too small
5198 * Native Values returned in pDriverDirectory on Success:
5199 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5200 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5201 *| win9x(Windows 4.0): "%winsysdir%"
5203 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5205 * FIXME
5206 *- Only NULL or "" is supported for pName
5209 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5210 DWORD Level, LPBYTE pDriverDirectory,
5211 DWORD cbBuf, LPDWORD pcbNeeded)
5213 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5214 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5216 if ((backend == NULL) && !load_backend()) return FALSE;
5218 if (Level != 1) {
5219 /* (Level != 1) is ignored in win9x */
5220 SetLastError(ERROR_INVALID_LEVEL);
5221 return FALSE;
5223 if (pcbNeeded == NULL) {
5224 /* (pcbNeeded == NULL) is ignored in win9x */
5225 SetLastError(RPC_X_NULL_REF_POINTER);
5226 return FALSE;
5229 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5230 pDriverDirectory, cbBuf, pcbNeeded);
5235 /*****************************************************************************
5236 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5238 * Return the PATH for the Printer-Drivers (ANSI)
5240 * See GetPrinterDriverDirectoryW.
5242 * NOTES
5243 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5246 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5247 DWORD Level, LPBYTE pDriverDirectory,
5248 DWORD cbBuf, LPDWORD pcbNeeded)
5250 UNICODE_STRING nameW, environmentW;
5251 BOOL ret;
5252 DWORD pcbNeededW;
5253 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5254 WCHAR *driverDirectoryW = NULL;
5256 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5257 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5259 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5261 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5262 else nameW.Buffer = NULL;
5263 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5264 else environmentW.Buffer = NULL;
5266 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5267 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5268 if (ret) {
5269 DWORD needed;
5270 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5271 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5272 if(pcbNeeded)
5273 *pcbNeeded = needed;
5274 ret = needed <= cbBuf;
5275 } else
5276 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5278 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5280 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5281 RtlFreeUnicodeString(&environmentW);
5282 RtlFreeUnicodeString(&nameW);
5284 return ret;
5287 /*****************************************************************************
5288 * AddPrinterDriverA [WINSPOOL.@]
5290 * See AddPrinterDriverW.
5293 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5295 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5296 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5299 /******************************************************************************
5300 * AddPrinterDriverW (WINSPOOL.@)
5302 * Install a Printer Driver
5304 * PARAMS
5305 * pName [I] Servername or NULL (local Computer)
5306 * level [I] Level for the supplied DRIVER_INFO_*W struct
5307 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5309 * RESULTS
5310 * Success: TRUE
5311 * Failure: FALSE
5314 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5316 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5317 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5320 /*****************************************************************************
5321 * AddPrintProcessorA [WINSPOOL.@]
5323 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5324 LPSTR pPrintProcessorName)
5326 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5327 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5328 return FALSE;
5331 /*****************************************************************************
5332 * AddPrintProcessorW [WINSPOOL.@]
5334 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5335 LPWSTR pPrintProcessorName)
5337 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5338 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5339 return TRUE;
5342 /*****************************************************************************
5343 * AddPrintProvidorA [WINSPOOL.@]
5345 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5347 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5348 return FALSE;
5351 /*****************************************************************************
5352 * AddPrintProvidorW [WINSPOOL.@]
5354 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5356 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5357 return FALSE;
5360 /*****************************************************************************
5361 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5363 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5364 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5366 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5367 pDevModeOutput, pDevModeInput);
5368 return 0;
5371 /*****************************************************************************
5372 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5374 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5375 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5377 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5378 pDevModeOutput, pDevModeInput);
5379 return 0;
5382 /*****************************************************************************
5383 * PrinterProperties [WINSPOOL.@]
5385 * Displays a dialog to set the properties of the printer.
5387 * RETURNS
5388 * nonzero on success or zero on failure
5390 * BUGS
5391 * implemented as stub only
5393 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5394 HANDLE hPrinter /* [in] handle to printer object */
5396 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5397 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5398 return FALSE;
5401 /*****************************************************************************
5402 * EnumJobsA [WINSPOOL.@]
5405 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5406 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5407 LPDWORD pcReturned)
5409 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5410 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5412 if(pcbNeeded) *pcbNeeded = 0;
5413 if(pcReturned) *pcReturned = 0;
5414 return FALSE;
5418 /*****************************************************************************
5419 * EnumJobsW [WINSPOOL.@]
5422 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5423 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5424 LPDWORD pcReturned)
5426 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5427 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5429 if(pcbNeeded) *pcbNeeded = 0;
5430 if(pcReturned) *pcReturned = 0;
5431 return FALSE;
5434 /*****************************************************************************
5435 * WINSPOOL_EnumPrinterDrivers [internal]
5437 * Delivers information about all printer drivers installed on the
5438 * localhost or a given server
5440 * RETURNS
5441 * nonzero on success or zero on failure. If the buffer for the returned
5442 * information is too small the function will return an error
5444 * BUGS
5445 * - only implemented for localhost, foreign hosts will return an error
5447 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5448 DWORD Level, LPBYTE pDriverInfo,
5449 DWORD driver_index,
5450 DWORD cbBuf, LPDWORD pcbNeeded,
5451 LPDWORD pcFound, DWORD data_offset)
5453 { HKEY hkeyDrivers;
5454 DWORD i, size = 0;
5455 const printenv_t * env;
5457 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5458 debugstr_w(pName), debugstr_w(pEnvironment),
5459 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5461 env = validate_envW(pEnvironment);
5462 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5464 *pcFound = 0;
5466 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5467 if(!hkeyDrivers) {
5468 ERR("Can't open Drivers key\n");
5469 return FALSE;
5472 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5473 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5474 RegCloseKey(hkeyDrivers);
5475 ERR("Can't query Drivers key\n");
5476 return FALSE;
5478 TRACE("Found %d Drivers\n", *pcFound);
5480 /* get size of single struct
5481 * unicode and ascii structure have the same size
5483 size = di_sizeof[Level];
5485 if (data_offset == 0)
5486 data_offset = size * (*pcFound);
5487 *pcbNeeded = data_offset;
5489 for( i = 0; i < *pcFound; i++) {
5490 WCHAR DriverNameW[255];
5491 PBYTE table_ptr = NULL;
5492 PBYTE data_ptr = NULL;
5493 DWORD needed = 0;
5495 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5496 != ERROR_SUCCESS) {
5497 ERR("Can't enum key number %d\n", i);
5498 RegCloseKey(hkeyDrivers);
5499 return FALSE;
5502 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5503 table_ptr = pDriverInfo + (driver_index + i) * size;
5504 if (pDriverInfo && *pcbNeeded <= cbBuf)
5505 data_ptr = pDriverInfo + *pcbNeeded;
5507 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5508 env, Level, table_ptr, data_ptr,
5509 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5510 &needed)) {
5511 RegCloseKey(hkeyDrivers);
5512 return FALSE;
5515 *pcbNeeded += needed;
5518 RegCloseKey(hkeyDrivers);
5520 if(cbBuf < *pcbNeeded){
5521 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5522 return FALSE;
5525 return TRUE;
5528 /*****************************************************************************
5529 * EnumPrinterDriversW [WINSPOOL.@]
5531 * see function EnumPrinterDrivers for RETURNS, BUGS
5533 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5534 LPBYTE pDriverInfo, DWORD cbBuf,
5535 LPDWORD pcbNeeded, LPDWORD pcReturned)
5537 static const WCHAR allW[] = {'a','l','l',0};
5538 BOOL ret;
5539 DWORD found;
5541 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5543 SetLastError(RPC_X_NULL_REF_POINTER);
5544 return FALSE;
5547 /* check for local drivers */
5548 if((pName) && (pName[0])) {
5549 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5550 SetLastError(ERROR_ACCESS_DENIED);
5551 return FALSE;
5554 /* check input parameter */
5555 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5556 SetLastError(ERROR_INVALID_LEVEL);
5557 return FALSE;
5560 if(pDriverInfo && cbBuf > 0)
5561 memset( pDriverInfo, 0, cbBuf);
5563 /* Exception: pull all printers */
5564 if (pEnvironment && !strcmpW(pEnvironment, allW))
5566 DWORD i, needed, bufsize = cbBuf;
5567 DWORD total_found = 0;
5568 DWORD data_offset;
5570 /* Precompute the overall total; we need this to know
5571 where pointers end and data begins (i.e. data_offset) */
5572 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5574 needed = found = 0;
5575 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5576 NULL, 0, 0, &needed, &found, 0);
5577 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5578 total_found += found;
5581 data_offset = di_sizeof[Level] * total_found;
5583 *pcReturned = 0;
5584 *pcbNeeded = 0;
5585 total_found = 0;
5586 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5588 needed = found = 0;
5589 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5590 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5591 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5592 else if (ret)
5593 *pcReturned += found;
5594 *pcbNeeded = needed;
5595 data_offset = needed;
5596 total_found += found;
5598 return ret;
5601 /* Normal behavior */
5602 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5603 0, cbBuf, pcbNeeded, &found, 0);
5604 if (ret)
5605 *pcReturned = found;
5607 return ret;
5610 /*****************************************************************************
5611 * EnumPrinterDriversA [WINSPOOL.@]
5613 * see function EnumPrinterDrivers for RETURNS, BUGS
5615 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5616 LPBYTE pDriverInfo, DWORD cbBuf,
5617 LPDWORD pcbNeeded, LPDWORD pcReturned)
5619 BOOL ret;
5620 UNICODE_STRING pNameW, pEnvironmentW;
5621 PWSTR pwstrNameW, pwstrEnvironmentW;
5622 LPBYTE buf = NULL;
5624 if (cbBuf)
5625 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5627 pwstrNameW = asciitounicode(&pNameW, pName);
5628 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5630 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5631 buf, cbBuf, pcbNeeded, pcReturned);
5632 if (ret)
5633 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5635 HeapFree(GetProcessHeap(), 0, buf);
5637 RtlFreeUnicodeString(&pNameW);
5638 RtlFreeUnicodeString(&pEnvironmentW);
5640 return ret;
5643 /******************************************************************************
5644 * EnumPortsA (WINSPOOL.@)
5646 * See EnumPortsW.
5649 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5650 LPDWORD pcbNeeded, LPDWORD pcReturned)
5652 BOOL res;
5653 LPBYTE bufferW = NULL;
5654 LPWSTR nameW = NULL;
5655 DWORD needed = 0;
5656 DWORD numentries = 0;
5657 INT len;
5659 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5660 cbBuf, pcbNeeded, pcReturned);
5662 /* convert servername to unicode */
5663 if (pName) {
5664 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5665 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5666 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5668 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5669 needed = cbBuf * sizeof(WCHAR);
5670 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5671 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5673 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5674 if (pcbNeeded) needed = *pcbNeeded;
5675 /* HeapReAlloc return NULL, when bufferW was NULL */
5676 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5677 HeapAlloc(GetProcessHeap(), 0, needed);
5679 /* Try again with the large Buffer */
5680 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5682 needed = pcbNeeded ? *pcbNeeded : 0;
5683 numentries = pcReturned ? *pcReturned : 0;
5686 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5687 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5689 if (res) {
5690 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5691 DWORD entrysize = 0;
5692 DWORD index;
5693 LPSTR ptr;
5694 LPPORT_INFO_2W pi2w;
5695 LPPORT_INFO_2A pi2a;
5697 needed = 0;
5698 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5700 /* First pass: calculate the size for all Entries */
5701 pi2w = (LPPORT_INFO_2W) bufferW;
5702 pi2a = (LPPORT_INFO_2A) pPorts;
5703 index = 0;
5704 while (index < numentries) {
5705 index++;
5706 needed += entrysize; /* PORT_INFO_?A */
5707 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5709 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5710 NULL, 0, NULL, NULL);
5711 if (Level > 1) {
5712 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5713 NULL, 0, NULL, NULL);
5714 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5715 NULL, 0, NULL, NULL);
5717 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5718 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5719 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5722 /* check for errors and quit on failure */
5723 if (cbBuf < needed) {
5724 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5725 res = FALSE;
5726 goto cleanup;
5728 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5729 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5730 cbBuf -= len ; /* free Bytes in the user-Buffer */
5731 pi2w = (LPPORT_INFO_2W) bufferW;
5732 pi2a = (LPPORT_INFO_2A) pPorts;
5733 index = 0;
5734 /* Second Pass: Fill the User Buffer (if we have one) */
5735 while ((index < numentries) && pPorts) {
5736 index++;
5737 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5738 pi2a->pPortName = ptr;
5739 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5740 ptr, cbBuf , NULL, NULL);
5741 ptr += len;
5742 cbBuf -= len;
5743 if (Level > 1) {
5744 pi2a->pMonitorName = ptr;
5745 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5746 ptr, cbBuf, NULL, NULL);
5747 ptr += len;
5748 cbBuf -= len;
5750 pi2a->pDescription = ptr;
5751 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5752 ptr, cbBuf, NULL, NULL);
5753 ptr += len;
5754 cbBuf -= len;
5756 pi2a->fPortType = pi2w->fPortType;
5757 pi2a->Reserved = 0; /* documented: "must be zero" */
5760 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5761 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5762 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5766 cleanup:
5767 if (pcbNeeded) *pcbNeeded = needed;
5768 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5770 HeapFree(GetProcessHeap(), 0, nameW);
5771 HeapFree(GetProcessHeap(), 0, bufferW);
5773 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5774 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5776 return (res);
5780 /******************************************************************************
5781 * EnumPortsW (WINSPOOL.@)
5783 * Enumerate available Ports
5785 * PARAMS
5786 * pName [I] Servername or NULL (local Computer)
5787 * Level [I] Structure-Level (1 or 2)
5788 * pPorts [O] PTR to Buffer that receives the Result
5789 * cbBuf [I] Size of Buffer at pPorts
5790 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5791 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5793 * RETURNS
5794 * Success: TRUE
5795 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5798 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5801 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5802 cbBuf, pcbNeeded, pcReturned);
5804 if ((backend == NULL) && !load_backend()) return FALSE;
5806 /* Level is not checked in win9x */
5807 if (!Level || (Level > 2)) {
5808 WARN("level (%d) is ignored in win9x\n", Level);
5809 SetLastError(ERROR_INVALID_LEVEL);
5810 return FALSE;
5812 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5813 SetLastError(RPC_X_NULL_REF_POINTER);
5814 return FALSE;
5817 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5820 /******************************************************************************
5821 * GetDefaultPrinterW (WINSPOOL.@)
5823 * FIXME
5824 * This function must read the value from data 'device' of key
5825 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5827 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5829 BOOL retval = TRUE;
5830 DWORD insize, len;
5831 WCHAR *buffer, *ptr;
5833 if (!namesize)
5835 SetLastError(ERROR_INVALID_PARAMETER);
5836 return FALSE;
5839 /* make the buffer big enough for the stuff from the profile/registry,
5840 * the content must fit into the local buffer to compute the correct
5841 * size even if the extern buffer is too small or not given.
5842 * (20 for ,driver,port) */
5843 insize = *namesize;
5844 len = max(100, (insize + 20));
5845 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5847 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5849 SetLastError (ERROR_FILE_NOT_FOUND);
5850 retval = FALSE;
5851 goto end;
5853 TRACE("%s\n", debugstr_w(buffer));
5855 if ((ptr = strchrW(buffer, ',')) == NULL)
5857 SetLastError(ERROR_INVALID_NAME);
5858 retval = FALSE;
5859 goto end;
5862 *ptr = 0;
5863 *namesize = strlenW(buffer) + 1;
5864 if(!name || (*namesize > insize))
5866 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5867 retval = FALSE;
5868 goto end;
5870 strcpyW(name, buffer);
5872 end:
5873 HeapFree( GetProcessHeap(), 0, buffer);
5874 return retval;
5878 /******************************************************************************
5879 * GetDefaultPrinterA (WINSPOOL.@)
5881 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5883 BOOL retval = TRUE;
5884 DWORD insize = 0;
5885 WCHAR *bufferW = NULL;
5887 if (!namesize)
5889 SetLastError(ERROR_INVALID_PARAMETER);
5890 return FALSE;
5893 if(name && *namesize) {
5894 insize = *namesize;
5895 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5898 if(!GetDefaultPrinterW( bufferW, namesize)) {
5899 retval = FALSE;
5900 goto end;
5903 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5904 NULL, NULL);
5905 if (!*namesize)
5907 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5908 retval = FALSE;
5910 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5912 end:
5913 HeapFree( GetProcessHeap(), 0, bufferW);
5914 return retval;
5918 /******************************************************************************
5919 * SetDefaultPrinterW (WINSPOOL.204)
5921 * Set the Name of the Default Printer
5923 * PARAMS
5924 * pszPrinter [I] Name of the Printer or NULL
5926 * RETURNS
5927 * Success: True
5928 * Failure: FALSE
5930 * NOTES
5931 * When the Parameter is NULL or points to an Empty String and
5932 * a Default Printer was already present, then this Function changes nothing.
5933 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5934 * the First enumerated local Printer is used.
5937 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5939 WCHAR default_printer[MAX_PATH];
5940 LPWSTR buffer = NULL;
5941 HKEY hreg;
5942 DWORD size;
5943 DWORD namelen;
5944 LONG lres;
5946 TRACE("(%s)\n", debugstr_w(pszPrinter));
5947 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5949 default_printer[0] = '\0';
5950 size = sizeof(default_printer)/sizeof(WCHAR);
5952 /* if we have a default Printer, do nothing. */
5953 if (GetDefaultPrinterW(default_printer, &size))
5954 return TRUE;
5956 pszPrinter = NULL;
5957 /* we have no default Printer: search local Printers and use the first */
5958 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5960 default_printer[0] = '\0';
5961 size = sizeof(default_printer)/sizeof(WCHAR);
5962 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5964 pszPrinter = default_printer;
5965 TRACE("using %s\n", debugstr_w(pszPrinter));
5967 RegCloseKey(hreg);
5970 if (pszPrinter == NULL) {
5971 TRACE("no local printer found\n");
5972 SetLastError(ERROR_FILE_NOT_FOUND);
5973 return FALSE;
5977 /* "pszPrinter" is never empty or NULL here. */
5978 namelen = lstrlenW(pszPrinter);
5979 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5980 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5981 if (!buffer ||
5982 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5983 HeapFree(GetProcessHeap(), 0, buffer);
5984 SetLastError(ERROR_FILE_NOT_FOUND);
5985 return FALSE;
5988 /* read the devices entry for the printer (driver,port) to build the string for the
5989 default device entry (printer,driver,port) */
5990 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5991 buffer[namelen] = ',';
5992 namelen++; /* move index to the start of the driver */
5994 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5995 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5996 if (!lres) {
5997 TRACE("set device to %s\n", debugstr_w(buffer));
5999 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
6000 TRACE("failed to set the device entry: %d\n", GetLastError());
6001 lres = ERROR_INVALID_PRINTER_NAME;
6004 /* remove the next section, when INIFileMapping is implemented */
6006 HKEY hdev;
6007 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
6008 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6009 RegCloseKey(hdev);
6013 else
6015 if (lres != ERROR_FILE_NOT_FOUND)
6016 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6018 SetLastError(ERROR_INVALID_PRINTER_NAME);
6021 RegCloseKey(hreg);
6022 HeapFree(GetProcessHeap(), 0, buffer);
6023 return (lres == ERROR_SUCCESS);
6026 /******************************************************************************
6027 * SetDefaultPrinterA (WINSPOOL.202)
6029 * See SetDefaultPrinterW.
6032 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6034 LPWSTR bufferW = NULL;
6035 BOOL res;
6037 TRACE("(%s)\n", debugstr_a(pszPrinter));
6038 if(pszPrinter) {
6039 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6040 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6041 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6043 res = SetDefaultPrinterW(bufferW);
6044 HeapFree(GetProcessHeap(), 0, bufferW);
6045 return res;
6048 /******************************************************************************
6049 * SetPrinterDataExA (WINSPOOL.@)
6051 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6052 LPCSTR pValueName, DWORD Type,
6053 LPBYTE pData, DWORD cbData)
6055 HKEY hkeyPrinter, hkeySubkey;
6056 DWORD ret;
6058 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6059 debugstr_a(pValueName), Type, pData, cbData);
6061 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6062 != ERROR_SUCCESS)
6063 return ret;
6065 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6066 != ERROR_SUCCESS) {
6067 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6068 RegCloseKey(hkeyPrinter);
6069 return ret;
6071 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6072 RegCloseKey(hkeySubkey);
6073 RegCloseKey(hkeyPrinter);
6074 return ret;
6077 /******************************************************************************
6078 * SetPrinterDataExW (WINSPOOL.@)
6080 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6081 LPCWSTR pValueName, DWORD Type,
6082 LPBYTE pData, DWORD cbData)
6084 HKEY hkeyPrinter, hkeySubkey;
6085 DWORD ret;
6087 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6088 debugstr_w(pValueName), Type, pData, cbData);
6090 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6091 != ERROR_SUCCESS)
6092 return ret;
6094 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6095 != ERROR_SUCCESS) {
6096 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6097 RegCloseKey(hkeyPrinter);
6098 return ret;
6100 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6101 RegCloseKey(hkeySubkey);
6102 RegCloseKey(hkeyPrinter);
6103 return ret;
6106 /******************************************************************************
6107 * SetPrinterDataA (WINSPOOL.@)
6109 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6110 LPBYTE pData, DWORD cbData)
6112 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6113 pData, cbData);
6116 /******************************************************************************
6117 * SetPrinterDataW (WINSPOOL.@)
6119 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6120 LPBYTE pData, DWORD cbData)
6122 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6123 pData, cbData);
6126 /******************************************************************************
6127 * GetPrinterDataExA (WINSPOOL.@)
6129 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6130 LPCSTR pValueName, LPDWORD pType,
6131 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6133 opened_printer_t *printer;
6134 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6135 DWORD ret;
6137 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6138 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6140 printer = get_opened_printer(hPrinter);
6141 if(!printer) return ERROR_INVALID_HANDLE;
6143 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6144 if (ret) return ret;
6146 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6148 if (printer->name) {
6150 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6151 if (ret) {
6152 RegCloseKey(hkeyPrinters);
6153 return ret;
6155 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6156 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6157 RegCloseKey(hkeyPrinter);
6158 RegCloseKey(hkeyPrinters);
6159 return ret;
6162 *pcbNeeded = nSize;
6163 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6164 0, pType, pData, pcbNeeded);
6166 if (!ret && !pData) ret = ERROR_MORE_DATA;
6168 RegCloseKey(hkeySubkey);
6169 RegCloseKey(hkeyPrinter);
6170 RegCloseKey(hkeyPrinters);
6172 TRACE("--> %d\n", ret);
6173 return ret;
6176 /******************************************************************************
6177 * GetPrinterDataExW (WINSPOOL.@)
6179 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6180 LPCWSTR pValueName, LPDWORD pType,
6181 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6183 opened_printer_t *printer;
6184 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6185 DWORD ret;
6187 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6188 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6190 printer = get_opened_printer(hPrinter);
6191 if(!printer) return ERROR_INVALID_HANDLE;
6193 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6194 if (ret) return ret;
6196 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6198 if (printer->name) {
6200 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6201 if (ret) {
6202 RegCloseKey(hkeyPrinters);
6203 return ret;
6205 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6206 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6207 RegCloseKey(hkeyPrinter);
6208 RegCloseKey(hkeyPrinters);
6209 return ret;
6212 *pcbNeeded = nSize;
6213 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6214 0, pType, pData, pcbNeeded);
6216 if (!ret && !pData) ret = ERROR_MORE_DATA;
6218 RegCloseKey(hkeySubkey);
6219 RegCloseKey(hkeyPrinter);
6220 RegCloseKey(hkeyPrinters);
6222 TRACE("--> %d\n", ret);
6223 return ret;
6226 /******************************************************************************
6227 * GetPrinterDataA (WINSPOOL.@)
6229 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6230 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6232 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6233 pData, nSize, pcbNeeded);
6236 /******************************************************************************
6237 * GetPrinterDataW (WINSPOOL.@)
6239 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6240 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6242 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6243 pData, nSize, pcbNeeded);
6246 /*******************************************************************************
6247 * EnumPrinterDataExW [WINSPOOL.@]
6249 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6250 LPBYTE pEnumValues, DWORD cbEnumValues,
6251 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6253 HKEY hkPrinter, hkSubKey;
6254 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6255 cbValueNameLen, cbMaxValueLen, cbValueLen,
6256 cbBufSize, dwType;
6257 LPWSTR lpValueName;
6258 HANDLE hHeap;
6259 PBYTE lpValue;
6260 PPRINTER_ENUM_VALUESW ppev;
6262 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6264 if (pKeyName == NULL || *pKeyName == 0)
6265 return ERROR_INVALID_PARAMETER;
6267 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6268 if (ret != ERROR_SUCCESS)
6270 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6271 hPrinter, ret);
6272 return ret;
6275 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6276 if (ret != ERROR_SUCCESS)
6278 r = RegCloseKey (hkPrinter);
6279 if (r != ERROR_SUCCESS)
6280 WARN ("RegCloseKey returned %i\n", r);
6281 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6282 debugstr_w (pKeyName), ret);
6283 return ret;
6286 ret = RegCloseKey (hkPrinter);
6287 if (ret != ERROR_SUCCESS)
6289 ERR ("RegCloseKey returned %i\n", ret);
6290 r = RegCloseKey (hkSubKey);
6291 if (r != ERROR_SUCCESS)
6292 WARN ("RegCloseKey returned %i\n", r);
6293 return ret;
6296 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6297 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6298 if (ret != ERROR_SUCCESS)
6300 r = RegCloseKey (hkSubKey);
6301 if (r != ERROR_SUCCESS)
6302 WARN ("RegCloseKey returned %i\n", r);
6303 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6304 return ret;
6307 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6308 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6310 if (cValues == 0) /* empty key */
6312 r = RegCloseKey (hkSubKey);
6313 if (r != ERROR_SUCCESS)
6314 WARN ("RegCloseKey returned %i\n", r);
6315 *pcbEnumValues = *pnEnumValues = 0;
6316 return ERROR_SUCCESS;
6319 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6321 hHeap = GetProcessHeap ();
6322 if (hHeap == NULL)
6324 ERR ("GetProcessHeap failed\n");
6325 r = RegCloseKey (hkSubKey);
6326 if (r != ERROR_SUCCESS)
6327 WARN ("RegCloseKey returned %i\n", r);
6328 return ERROR_OUTOFMEMORY;
6331 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6332 if (lpValueName == NULL)
6334 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6335 r = RegCloseKey (hkSubKey);
6336 if (r != ERROR_SUCCESS)
6337 WARN ("RegCloseKey returned %i\n", r);
6338 return ERROR_OUTOFMEMORY;
6341 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6342 if (lpValue == NULL)
6344 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6345 if (HeapFree (hHeap, 0, lpValueName) == 0)
6346 WARN ("HeapFree failed with code %i\n", GetLastError ());
6347 r = RegCloseKey (hkSubKey);
6348 if (r != ERROR_SUCCESS)
6349 WARN ("RegCloseKey returned %i\n", r);
6350 return ERROR_OUTOFMEMORY;
6353 TRACE ("pass 1: calculating buffer required for all names and values\n");
6355 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6357 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6359 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6361 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6362 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6363 NULL, NULL, lpValue, &cbValueLen);
6364 if (ret != ERROR_SUCCESS)
6366 if (HeapFree (hHeap, 0, lpValue) == 0)
6367 WARN ("HeapFree failed with code %i\n", GetLastError ());
6368 if (HeapFree (hHeap, 0, lpValueName) == 0)
6369 WARN ("HeapFree failed with code %i\n", GetLastError ());
6370 r = RegCloseKey (hkSubKey);
6371 if (r != ERROR_SUCCESS)
6372 WARN ("RegCloseKey returned %i\n", r);
6373 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6374 return ret;
6377 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6378 debugstr_w (lpValueName), dwIndex,
6379 cbValueNameLen + 1, cbValueLen);
6381 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6382 cbBufSize += cbValueLen;
6385 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6387 *pcbEnumValues = cbBufSize;
6388 *pnEnumValues = cValues;
6390 if (cbEnumValues < cbBufSize) /* buffer too small */
6392 if (HeapFree (hHeap, 0, lpValue) == 0)
6393 WARN ("HeapFree failed with code %i\n", GetLastError ());
6394 if (HeapFree (hHeap, 0, lpValueName) == 0)
6395 WARN ("HeapFree failed with code %i\n", GetLastError ());
6396 r = RegCloseKey (hkSubKey);
6397 if (r != ERROR_SUCCESS)
6398 WARN ("RegCloseKey returned %i\n", r);
6399 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6400 return ERROR_MORE_DATA;
6403 TRACE ("pass 2: copying all names and values to buffer\n");
6405 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6406 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6408 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6410 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6411 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6412 NULL, &dwType, lpValue, &cbValueLen);
6413 if (ret != ERROR_SUCCESS)
6415 if (HeapFree (hHeap, 0, lpValue) == 0)
6416 WARN ("HeapFree failed with code %i\n", GetLastError ());
6417 if (HeapFree (hHeap, 0, lpValueName) == 0)
6418 WARN ("HeapFree failed with code %i\n", GetLastError ());
6419 r = RegCloseKey (hkSubKey);
6420 if (r != ERROR_SUCCESS)
6421 WARN ("RegCloseKey returned %i\n", r);
6422 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6423 return ret;
6426 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6427 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6428 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6429 pEnumValues += cbValueNameLen;
6431 /* return # of *bytes* (including trailing \0), not # of chars */
6432 ppev[dwIndex].cbValueName = cbValueNameLen;
6434 ppev[dwIndex].dwType = dwType;
6436 memcpy (pEnumValues, lpValue, cbValueLen);
6437 ppev[dwIndex].pData = pEnumValues;
6438 pEnumValues += cbValueLen;
6440 ppev[dwIndex].cbData = cbValueLen;
6442 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6443 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6446 if (HeapFree (hHeap, 0, lpValue) == 0)
6448 ret = GetLastError ();
6449 ERR ("HeapFree failed with code %i\n", ret);
6450 if (HeapFree (hHeap, 0, lpValueName) == 0)
6451 WARN ("HeapFree failed with code %i\n", GetLastError ());
6452 r = RegCloseKey (hkSubKey);
6453 if (r != ERROR_SUCCESS)
6454 WARN ("RegCloseKey returned %i\n", r);
6455 return ret;
6458 if (HeapFree (hHeap, 0, lpValueName) == 0)
6460 ret = GetLastError ();
6461 ERR ("HeapFree failed with code %i\n", ret);
6462 r = RegCloseKey (hkSubKey);
6463 if (r != ERROR_SUCCESS)
6464 WARN ("RegCloseKey returned %i\n", r);
6465 return ret;
6468 ret = RegCloseKey (hkSubKey);
6469 if (ret != ERROR_SUCCESS)
6471 ERR ("RegCloseKey returned %i\n", ret);
6472 return ret;
6475 return ERROR_SUCCESS;
6478 /*******************************************************************************
6479 * EnumPrinterDataExA [WINSPOOL.@]
6481 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6482 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6483 * what Windows 2000 SP1 does.
6486 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6487 LPBYTE pEnumValues, DWORD cbEnumValues,
6488 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6490 INT len;
6491 LPWSTR pKeyNameW;
6492 DWORD ret, dwIndex, dwBufSize;
6493 HANDLE hHeap;
6494 LPSTR pBuffer;
6496 TRACE ("%p %s\n", hPrinter, pKeyName);
6498 if (pKeyName == NULL || *pKeyName == 0)
6499 return ERROR_INVALID_PARAMETER;
6501 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6502 if (len == 0)
6504 ret = GetLastError ();
6505 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6506 return ret;
6509 hHeap = GetProcessHeap ();
6510 if (hHeap == NULL)
6512 ERR ("GetProcessHeap failed\n");
6513 return ERROR_OUTOFMEMORY;
6516 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6517 if (pKeyNameW == NULL)
6519 ERR ("Failed to allocate %i bytes from process heap\n",
6520 (LONG)(len * sizeof (WCHAR)));
6521 return ERROR_OUTOFMEMORY;
6524 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6526 ret = GetLastError ();
6527 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6528 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6529 WARN ("HeapFree failed with code %i\n", GetLastError ());
6530 return ret;
6533 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6534 pcbEnumValues, pnEnumValues);
6535 if (ret != ERROR_SUCCESS)
6537 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6538 WARN ("HeapFree failed with code %i\n", GetLastError ());
6539 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6540 return ret;
6543 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6545 ret = GetLastError ();
6546 ERR ("HeapFree failed with code %i\n", ret);
6547 return ret;
6550 if (*pnEnumValues == 0) /* empty key */
6551 return ERROR_SUCCESS;
6553 dwBufSize = 0;
6554 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6556 PPRINTER_ENUM_VALUESW ppev =
6557 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6559 if (dwBufSize < ppev->cbValueName)
6560 dwBufSize = ppev->cbValueName;
6562 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6563 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6564 dwBufSize = ppev->cbData;
6567 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6569 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6570 if (pBuffer == NULL)
6572 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6573 return ERROR_OUTOFMEMORY;
6576 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6578 PPRINTER_ENUM_VALUESW ppev =
6579 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6581 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6582 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6583 NULL);
6584 if (len == 0)
6586 ret = GetLastError ();
6587 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6588 if (HeapFree (hHeap, 0, pBuffer) == 0)
6589 WARN ("HeapFree failed with code %i\n", GetLastError ());
6590 return ret;
6593 memcpy (ppev->pValueName, pBuffer, len);
6595 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6597 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6598 ppev->dwType != REG_MULTI_SZ)
6599 continue;
6601 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6602 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6603 if (len == 0)
6605 ret = GetLastError ();
6606 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6607 if (HeapFree (hHeap, 0, pBuffer) == 0)
6608 WARN ("HeapFree failed with code %i\n", GetLastError ());
6609 return ret;
6612 memcpy (ppev->pData, pBuffer, len);
6614 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6615 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6618 if (HeapFree (hHeap, 0, pBuffer) == 0)
6620 ret = GetLastError ();
6621 ERR ("HeapFree failed with code %i\n", ret);
6622 return ret;
6625 return ERROR_SUCCESS;
6628 /******************************************************************************
6629 * AbortPrinter (WINSPOOL.@)
6631 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6633 FIXME("(%p), stub!\n", hPrinter);
6634 return TRUE;
6637 /******************************************************************************
6638 * AddPortA (WINSPOOL.@)
6640 * See AddPortW.
6643 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6645 LPWSTR nameW = NULL;
6646 LPWSTR monitorW = NULL;
6647 DWORD len;
6648 BOOL res;
6650 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6652 if (pName) {
6653 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6654 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6655 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6658 if (pMonitorName) {
6659 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6660 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6661 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6663 res = AddPortW(nameW, hWnd, monitorW);
6664 HeapFree(GetProcessHeap(), 0, nameW);
6665 HeapFree(GetProcessHeap(), 0, monitorW);
6666 return res;
6669 /******************************************************************************
6670 * AddPortW (WINSPOOL.@)
6672 * Add a Port for a specific Monitor
6674 * PARAMS
6675 * pName [I] Servername or NULL (local Computer)
6676 * hWnd [I] Handle to parent Window for the Dialog-Box
6677 * pMonitorName [I] Name of the Monitor that manage the Port
6679 * RETURNS
6680 * Success: TRUE
6681 * Failure: FALSE
6684 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6686 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6688 if ((backend == NULL) && !load_backend()) return FALSE;
6690 if (!pMonitorName) {
6691 SetLastError(RPC_X_NULL_REF_POINTER);
6692 return FALSE;
6695 return backend->fpAddPort(pName, hWnd, pMonitorName);
6698 /******************************************************************************
6699 * AddPortExA (WINSPOOL.@)
6701 * See AddPortExW.
6704 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6706 PORT_INFO_2W pi2W;
6707 PORT_INFO_2A * pi2A;
6708 LPWSTR nameW = NULL;
6709 LPWSTR monitorW = NULL;
6710 DWORD len;
6711 BOOL res;
6713 pi2A = (PORT_INFO_2A *) pBuffer;
6715 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6716 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6718 if ((level < 1) || (level > 2)) {
6719 SetLastError(ERROR_INVALID_LEVEL);
6720 return FALSE;
6723 if (!pi2A) {
6724 SetLastError(ERROR_INVALID_PARAMETER);
6725 return FALSE;
6728 if (pName) {
6729 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6730 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6731 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6734 if (pMonitorName) {
6735 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6736 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6737 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6740 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6742 if (pi2A->pPortName) {
6743 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6744 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6745 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6748 if (level > 1) {
6749 if (pi2A->pMonitorName) {
6750 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6751 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6752 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6755 if (pi2A->pDescription) {
6756 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6757 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6758 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6760 pi2W.fPortType = pi2A->fPortType;
6761 pi2W.Reserved = pi2A->Reserved;
6764 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6766 HeapFree(GetProcessHeap(), 0, nameW);
6767 HeapFree(GetProcessHeap(), 0, monitorW);
6768 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6769 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6770 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6771 return res;
6775 /******************************************************************************
6776 * AddPortExW (WINSPOOL.@)
6778 * Add a Port for a specific Monitor, without presenting a user interface
6780 * PARAMS
6781 * pName [I] Servername or NULL (local Computer)
6782 * level [I] Structure-Level (1 or 2) for pBuffer
6783 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6784 * pMonitorName [I] Name of the Monitor that manage the Port
6786 * RETURNS
6787 * Success: TRUE
6788 * Failure: FALSE
6791 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6793 PORT_INFO_2W * pi2;
6795 pi2 = (PORT_INFO_2W *) pBuffer;
6797 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6798 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6799 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6800 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6802 if ((backend == NULL) && !load_backend()) return FALSE;
6804 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6805 SetLastError(ERROR_INVALID_PARAMETER);
6806 return FALSE;
6809 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6812 /******************************************************************************
6813 * AddPrinterConnectionA (WINSPOOL.@)
6815 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6817 FIXME("%s\n", debugstr_a(pName));
6818 return FALSE;
6821 /******************************************************************************
6822 * AddPrinterConnectionW (WINSPOOL.@)
6824 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6826 FIXME("%s\n", debugstr_w(pName));
6827 return FALSE;
6830 /******************************************************************************
6831 * AddPrinterDriverExW (WINSPOOL.@)
6833 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6835 * PARAMS
6836 * pName [I] Servername or NULL (local Computer)
6837 * level [I] Level for the supplied DRIVER_INFO_*W struct
6838 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6839 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6841 * RESULTS
6842 * Success: TRUE
6843 * Failure: FALSE
6846 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6848 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6850 if ((backend == NULL) && !load_backend()) return FALSE;
6852 if (level < 2 || level == 5 || level == 7 || level > 8) {
6853 SetLastError(ERROR_INVALID_LEVEL);
6854 return FALSE;
6857 if (!pDriverInfo) {
6858 SetLastError(ERROR_INVALID_PARAMETER);
6859 return FALSE;
6862 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6865 /******************************************************************************
6866 * AddPrinterDriverExA (WINSPOOL.@)
6868 * See AddPrinterDriverExW.
6871 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6873 DRIVER_INFO_8A *diA;
6874 DRIVER_INFO_8W diW;
6875 LPWSTR nameW = NULL;
6876 DWORD lenA;
6877 DWORD len;
6878 BOOL res = FALSE;
6880 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6882 diA = (DRIVER_INFO_8A *) pDriverInfo;
6883 ZeroMemory(&diW, sizeof(diW));
6885 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6886 SetLastError(ERROR_INVALID_LEVEL);
6887 return FALSE;
6890 if (diA == NULL) {
6891 SetLastError(ERROR_INVALID_PARAMETER);
6892 return FALSE;
6895 /* convert servername to unicode */
6896 if (pName) {
6897 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6898 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6899 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6902 /* common fields */
6903 diW.cVersion = diA->cVersion;
6905 if (diA->pName) {
6906 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6907 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6908 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6911 if (diA->pEnvironment) {
6912 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6913 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6914 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6917 if (diA->pDriverPath) {
6918 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6919 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6920 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6923 if (diA->pDataFile) {
6924 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6925 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6926 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6929 if (diA->pConfigFile) {
6930 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6931 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6932 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6935 if ((Level > 2) && diA->pDependentFiles) {
6936 lenA = multi_sz_lenA(diA->pDependentFiles);
6937 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6938 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6939 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6942 if ((Level > 2) && diA->pMonitorName) {
6943 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6944 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6945 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6948 if ((Level > 3) && diA->pDefaultDataType) {
6949 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6950 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6951 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6954 if ((Level > 3) && diA->pszzPreviousNames) {
6955 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6956 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6957 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6958 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6961 if ((Level > 5) && diA->pszMfgName) {
6962 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6963 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6964 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6967 if ((Level > 5) && diA->pszOEMUrl) {
6968 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6969 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6970 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6973 if ((Level > 5) && diA->pszHardwareID) {
6974 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6975 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6976 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6979 if ((Level > 5) && diA->pszProvider) {
6980 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6981 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6982 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6985 if (Level > 7) {
6986 FIXME("level %u is incomplete\n", Level);
6989 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6990 TRACE("got %u with %u\n", res, GetLastError());
6991 HeapFree(GetProcessHeap(), 0, nameW);
6992 HeapFree(GetProcessHeap(), 0, diW.pName);
6993 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6994 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6995 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6996 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6997 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6998 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6999 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
7000 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
7001 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
7002 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
7003 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
7004 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
7006 TRACE("=> %u with %u\n", res, GetLastError());
7007 return res;
7010 /******************************************************************************
7011 * ConfigurePortA (WINSPOOL.@)
7013 * See ConfigurePortW.
7016 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7018 LPWSTR nameW = NULL;
7019 LPWSTR portW = NULL;
7020 INT len;
7021 DWORD res;
7023 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7025 /* convert servername to unicode */
7026 if (pName) {
7027 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7028 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7029 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7032 /* convert portname to unicode */
7033 if (pPortName) {
7034 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7035 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7036 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7039 res = ConfigurePortW(nameW, hWnd, portW);
7040 HeapFree(GetProcessHeap(), 0, nameW);
7041 HeapFree(GetProcessHeap(), 0, portW);
7042 return res;
7045 /******************************************************************************
7046 * ConfigurePortW (WINSPOOL.@)
7048 * Display the Configuration-Dialog for a specific Port
7050 * PARAMS
7051 * pName [I] Servername or NULL (local Computer)
7052 * hWnd [I] Handle to parent Window for the Dialog-Box
7053 * pPortName [I] Name of the Port, that should be configured
7055 * RETURNS
7056 * Success: TRUE
7057 * Failure: FALSE
7060 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7063 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7065 if ((backend == NULL) && !load_backend()) return FALSE;
7067 if (!pPortName) {
7068 SetLastError(RPC_X_NULL_REF_POINTER);
7069 return FALSE;
7072 return backend->fpConfigurePort(pName, hWnd, pPortName);
7075 /******************************************************************************
7076 * ConnectToPrinterDlg (WINSPOOL.@)
7078 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7080 FIXME("%p %x\n", hWnd, Flags);
7081 return NULL;
7084 /******************************************************************************
7085 * DeletePrinterConnectionA (WINSPOOL.@)
7087 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7089 FIXME("%s\n", debugstr_a(pName));
7090 return TRUE;
7093 /******************************************************************************
7094 * DeletePrinterConnectionW (WINSPOOL.@)
7096 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7098 FIXME("%s\n", debugstr_w(pName));
7099 return TRUE;
7102 /******************************************************************************
7103 * DeletePrinterDriverExW (WINSPOOL.@)
7105 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7106 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7108 HKEY hkey_drivers;
7109 BOOL ret = FALSE;
7111 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7112 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7114 if(pName && pName[0])
7116 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7117 SetLastError(ERROR_INVALID_PARAMETER);
7118 return FALSE;
7121 if(dwDeleteFlag)
7123 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7124 SetLastError(ERROR_INVALID_PARAMETER);
7125 return FALSE;
7128 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7130 if(!hkey_drivers)
7132 ERR("Can't open drivers key\n");
7133 return FALSE;
7136 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7137 ret = TRUE;
7139 RegCloseKey(hkey_drivers);
7141 return ret;
7144 /******************************************************************************
7145 * DeletePrinterDriverExA (WINSPOOL.@)
7147 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7148 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7150 UNICODE_STRING NameW, EnvW, DriverW;
7151 BOOL ret;
7153 asciitounicode(&NameW, pName);
7154 asciitounicode(&EnvW, pEnvironment);
7155 asciitounicode(&DriverW, pDriverName);
7157 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7159 RtlFreeUnicodeString(&DriverW);
7160 RtlFreeUnicodeString(&EnvW);
7161 RtlFreeUnicodeString(&NameW);
7163 return ret;
7166 /******************************************************************************
7167 * DeletePrinterDataExW (WINSPOOL.@)
7169 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7170 LPCWSTR pValueName)
7172 FIXME("%p %s %s\n", hPrinter,
7173 debugstr_w(pKeyName), debugstr_w(pValueName));
7174 return ERROR_INVALID_PARAMETER;
7177 /******************************************************************************
7178 * DeletePrinterDataExA (WINSPOOL.@)
7180 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7181 LPCSTR pValueName)
7183 FIXME("%p %s %s\n", hPrinter,
7184 debugstr_a(pKeyName), debugstr_a(pValueName));
7185 return ERROR_INVALID_PARAMETER;
7188 /******************************************************************************
7189 * DeletePrintProcessorA (WINSPOOL.@)
7191 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7193 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7194 debugstr_a(pPrintProcessorName));
7195 return TRUE;
7198 /******************************************************************************
7199 * DeletePrintProcessorW (WINSPOOL.@)
7201 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7203 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7204 debugstr_w(pPrintProcessorName));
7205 return TRUE;
7208 /******************************************************************************
7209 * DeletePrintProvidorA (WINSPOOL.@)
7211 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7213 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7214 debugstr_a(pPrintProviderName));
7215 return TRUE;
7218 /******************************************************************************
7219 * DeletePrintProvidorW (WINSPOOL.@)
7221 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7223 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7224 debugstr_w(pPrintProviderName));
7225 return TRUE;
7228 /******************************************************************************
7229 * EnumFormsA (WINSPOOL.@)
7231 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7232 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7234 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7235 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7236 return FALSE;
7239 /******************************************************************************
7240 * EnumFormsW (WINSPOOL.@)
7242 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7243 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7245 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7246 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7247 return FALSE;
7250 /*****************************************************************************
7251 * EnumMonitorsA [WINSPOOL.@]
7253 * See EnumMonitorsW.
7256 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7257 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7259 BOOL res;
7260 LPBYTE bufferW = NULL;
7261 LPWSTR nameW = NULL;
7262 DWORD needed = 0;
7263 DWORD numentries = 0;
7264 INT len;
7266 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7267 cbBuf, pcbNeeded, pcReturned);
7269 /* convert servername to unicode */
7270 if (pName) {
7271 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7272 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7273 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7275 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7276 needed = cbBuf * sizeof(WCHAR);
7277 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7278 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7280 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7281 if (pcbNeeded) needed = *pcbNeeded;
7282 /* HeapReAlloc return NULL, when bufferW was NULL */
7283 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7284 HeapAlloc(GetProcessHeap(), 0, needed);
7286 /* Try again with the large Buffer */
7287 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7289 numentries = pcReturned ? *pcReturned : 0;
7290 needed = 0;
7292 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7293 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7295 if (res) {
7296 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7297 DWORD entrysize = 0;
7298 DWORD index;
7299 LPSTR ptr;
7300 LPMONITOR_INFO_2W mi2w;
7301 LPMONITOR_INFO_2A mi2a;
7303 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7304 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7306 /* First pass: calculate the size for all Entries */
7307 mi2w = (LPMONITOR_INFO_2W) bufferW;
7308 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7309 index = 0;
7310 while (index < numentries) {
7311 index++;
7312 needed += entrysize; /* MONITOR_INFO_?A */
7313 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7315 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7316 NULL, 0, NULL, NULL);
7317 if (Level > 1) {
7318 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7319 NULL, 0, NULL, NULL);
7320 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7321 NULL, 0, NULL, NULL);
7323 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7324 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7325 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7328 /* check for errors and quit on failure */
7329 if (cbBuf < needed) {
7330 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7331 res = FALSE;
7332 goto emA_cleanup;
7334 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7335 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7336 cbBuf -= len ; /* free Bytes in the user-Buffer */
7337 mi2w = (LPMONITOR_INFO_2W) bufferW;
7338 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7339 index = 0;
7340 /* Second Pass: Fill the User Buffer (if we have one) */
7341 while ((index < numentries) && pMonitors) {
7342 index++;
7343 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7344 mi2a->pName = ptr;
7345 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7346 ptr, cbBuf , NULL, NULL);
7347 ptr += len;
7348 cbBuf -= len;
7349 if (Level > 1) {
7350 mi2a->pEnvironment = ptr;
7351 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7352 ptr, cbBuf, NULL, NULL);
7353 ptr += len;
7354 cbBuf -= len;
7356 mi2a->pDLLName = ptr;
7357 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7358 ptr, cbBuf, NULL, NULL);
7359 ptr += len;
7360 cbBuf -= len;
7362 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7363 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7364 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7367 emA_cleanup:
7368 if (pcbNeeded) *pcbNeeded = needed;
7369 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7371 HeapFree(GetProcessHeap(), 0, nameW);
7372 HeapFree(GetProcessHeap(), 0, bufferW);
7374 TRACE("returning %d with %d (%d byte for %d entries)\n",
7375 (res), GetLastError(), needed, numentries);
7377 return (res);
7381 /*****************************************************************************
7382 * EnumMonitorsW [WINSPOOL.@]
7384 * Enumerate available Port-Monitors
7386 * PARAMS
7387 * pName [I] Servername or NULL (local Computer)
7388 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7389 * pMonitors [O] PTR to Buffer that receives the Result
7390 * cbBuf [I] Size of Buffer at pMonitors
7391 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7392 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7394 * RETURNS
7395 * Success: TRUE
7396 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7399 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7400 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7403 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7404 cbBuf, pcbNeeded, pcReturned);
7406 if ((backend == NULL) && !load_backend()) return FALSE;
7408 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7409 SetLastError(RPC_X_NULL_REF_POINTER);
7410 return FALSE;
7413 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7416 /******************************************************************************
7417 * SpoolerInit (WINSPOOL.@)
7419 * Initialize the Spooler
7421 * RETURNS
7422 * Success: TRUE
7423 * Failure: FALSE
7425 * NOTES
7426 * The function fails on windows, when the spooler service is not running
7429 BOOL WINAPI SpoolerInit(void)
7432 if ((backend == NULL) && !load_backend()) return FALSE;
7433 return TRUE;
7436 /******************************************************************************
7437 * XcvDataW (WINSPOOL.@)
7439 * Execute commands in the Printmonitor DLL
7441 * PARAMS
7442 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7443 * pszDataName [i] Name of the command to execute
7444 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7445 * cbInputData [i] Size in Bytes of Buffer at pInputData
7446 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7447 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7448 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7449 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7451 * RETURNS
7452 * Success: TRUE
7453 * Failure: FALSE
7455 * NOTES
7456 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7457 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7459 * Minimal List of commands, that a Printmonitor DLL should support:
7461 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7462 *| "AddPort" : Add a Port
7463 *| "DeletePort": Delete a Port
7465 * Many Printmonitors support additional commands. Examples for localspl.dll:
7466 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7467 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7470 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7471 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7472 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7474 opened_printer_t *printer;
7476 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7477 pInputData, cbInputData, pOutputData,
7478 cbOutputData, pcbOutputNeeded, pdwStatus);
7480 if ((backend == NULL) && !load_backend()) return FALSE;
7482 printer = get_opened_printer(hXcv);
7483 if (!printer || (!printer->backend_printer)) {
7484 SetLastError(ERROR_INVALID_HANDLE);
7485 return FALSE;
7488 if (!pcbOutputNeeded) {
7489 SetLastError(ERROR_INVALID_PARAMETER);
7490 return FALSE;
7493 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7494 SetLastError(RPC_X_NULL_REF_POINTER);
7495 return FALSE;
7498 *pcbOutputNeeded = 0;
7500 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7501 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7505 /*****************************************************************************
7506 * EnumPrinterDataA [WINSPOOL.@]
7509 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7510 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7511 DWORD cbData, LPDWORD pcbData )
7513 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7514 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7515 return ERROR_NO_MORE_ITEMS;
7518 /*****************************************************************************
7519 * EnumPrinterDataW [WINSPOOL.@]
7522 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7523 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7524 DWORD cbData, LPDWORD pcbData )
7526 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7527 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7528 return ERROR_NO_MORE_ITEMS;
7531 /*****************************************************************************
7532 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7535 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7536 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7537 LPDWORD pcbNeeded, LPDWORD pcReturned)
7539 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7540 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7541 pcbNeeded, pcReturned);
7542 return FALSE;
7545 /*****************************************************************************
7546 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7549 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7550 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7551 LPDWORD pcbNeeded, LPDWORD pcReturned)
7553 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7554 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7555 pcbNeeded, pcReturned);
7556 return FALSE;
7559 /*****************************************************************************
7560 * EnumPrintProcessorsA [WINSPOOL.@]
7562 * See EnumPrintProcessorsW.
7565 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7566 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7568 BOOL res;
7569 LPBYTE bufferW = NULL;
7570 LPWSTR nameW = NULL;
7571 LPWSTR envW = NULL;
7572 DWORD needed = 0;
7573 DWORD numentries = 0;
7574 INT len;
7576 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7577 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7579 /* convert names to unicode */
7580 if (pName) {
7581 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7582 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7583 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7585 if (pEnvironment) {
7586 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7587 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7588 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7591 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7592 needed = cbBuf * sizeof(WCHAR);
7593 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7594 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7596 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7597 if (pcbNeeded) needed = *pcbNeeded;
7598 /* HeapReAlloc return NULL, when bufferW was NULL */
7599 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7600 HeapAlloc(GetProcessHeap(), 0, needed);
7602 /* Try again with the large Buffer */
7603 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7605 numentries = pcReturned ? *pcReturned : 0;
7606 needed = 0;
7608 if (res) {
7609 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7610 DWORD index;
7611 LPSTR ptr;
7612 PPRINTPROCESSOR_INFO_1W ppiw;
7613 PPRINTPROCESSOR_INFO_1A ppia;
7615 /* First pass: calculate the size for all Entries */
7616 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7617 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7618 index = 0;
7619 while (index < numentries) {
7620 index++;
7621 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7622 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7624 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7625 NULL, 0, NULL, NULL);
7627 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7628 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7631 /* check for errors and quit on failure */
7632 if (cbBuf < needed) {
7633 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7634 res = FALSE;
7635 goto epp_cleanup;
7638 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7639 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7640 cbBuf -= len ; /* free Bytes in the user-Buffer */
7641 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7642 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7643 index = 0;
7644 /* Second Pass: Fill the User Buffer (if we have one) */
7645 while ((index < numentries) && pPPInfo) {
7646 index++;
7647 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7648 ppia->pName = ptr;
7649 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7650 ptr, cbBuf , NULL, NULL);
7651 ptr += len;
7652 cbBuf -= len;
7654 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7655 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7659 epp_cleanup:
7660 if (pcbNeeded) *pcbNeeded = needed;
7661 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7663 HeapFree(GetProcessHeap(), 0, nameW);
7664 HeapFree(GetProcessHeap(), 0, envW);
7665 HeapFree(GetProcessHeap(), 0, bufferW);
7667 TRACE("returning %d with %d (%d byte for %d entries)\n",
7668 (res), GetLastError(), needed, numentries);
7670 return (res);
7673 /*****************************************************************************
7674 * EnumPrintProcessorsW [WINSPOOL.@]
7676 * Enumerate available Print Processors
7678 * PARAMS
7679 * pName [I] Servername or NULL (local Computer)
7680 * pEnvironment [I] Printing-Environment or NULL (Default)
7681 * Level [I] Structure-Level (Only 1 is allowed)
7682 * pPPInfo [O] PTR to Buffer that receives the Result
7683 * cbBuf [I] Size of Buffer at pPPInfo
7684 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7685 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7687 * RETURNS
7688 * Success: TRUE
7689 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7692 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7693 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7696 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7697 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7699 if ((backend == NULL) && !load_backend()) return FALSE;
7701 if (!pcbNeeded || !pcReturned) {
7702 SetLastError(RPC_X_NULL_REF_POINTER);
7703 return FALSE;
7706 if (!pPPInfo && (cbBuf > 0)) {
7707 SetLastError(ERROR_INVALID_USER_BUFFER);
7708 return FALSE;
7711 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7712 cbBuf, pcbNeeded, pcReturned);
7715 /*****************************************************************************
7716 * ExtDeviceMode [WINSPOOL.@]
7719 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7720 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7721 DWORD fMode)
7723 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7724 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7725 debugstr_a(pProfile), fMode);
7726 return -1;
7729 /*****************************************************************************
7730 * FindClosePrinterChangeNotification [WINSPOOL.@]
7733 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7735 FIXME("Stub: %p\n", hChange);
7736 return TRUE;
7739 /*****************************************************************************
7740 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7743 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7744 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7746 FIXME("Stub: %p %x %x %p\n",
7747 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7748 return INVALID_HANDLE_VALUE;
7751 /*****************************************************************************
7752 * FindNextPrinterChangeNotification [WINSPOOL.@]
7755 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7756 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7758 FIXME("Stub: %p %p %p %p\n",
7759 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7760 return FALSE;
7763 /*****************************************************************************
7764 * FreePrinterNotifyInfo [WINSPOOL.@]
7767 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7769 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7770 return TRUE;
7773 /*****************************************************************************
7774 * string_to_buf
7776 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7777 * ansi depending on the unicode parameter.
7779 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7781 if(!str)
7783 *size = 0;
7784 return TRUE;
7787 if(unicode)
7789 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7790 if(*size <= cb)
7792 memcpy(ptr, str, *size);
7793 return TRUE;
7795 return FALSE;
7797 else
7799 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7800 if(*size <= cb)
7802 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7803 return TRUE;
7805 return FALSE;
7809 /*****************************************************************************
7810 * get_job_info_1
7812 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7813 LPDWORD pcbNeeded, BOOL unicode)
7815 DWORD size, left = cbBuf;
7816 BOOL space = (cbBuf > 0);
7817 LPBYTE ptr = buf;
7819 *pcbNeeded = 0;
7821 if(space)
7823 ji1->JobId = job->job_id;
7826 string_to_buf(job->document_title, ptr, left, &size, unicode);
7827 if(space && size <= left)
7829 ji1->pDocument = (LPWSTR)ptr;
7830 ptr += size;
7831 left -= size;
7833 else
7834 space = FALSE;
7835 *pcbNeeded += size;
7837 if (job->printer_name)
7839 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7840 if(space && size <= left)
7842 ji1->pPrinterName = (LPWSTR)ptr;
7843 ptr += size;
7844 left -= size;
7846 else
7847 space = FALSE;
7848 *pcbNeeded += size;
7851 return space;
7854 /*****************************************************************************
7855 * get_job_info_2
7857 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7858 LPDWORD pcbNeeded, BOOL unicode)
7860 DWORD size, left = cbBuf;
7861 DWORD shift;
7862 BOOL space = (cbBuf > 0);
7863 LPBYTE ptr = buf;
7864 LPDEVMODEA dmA = NULL;
7865 LPDEVMODEW devmode;
7867 *pcbNeeded = 0;
7869 if(space)
7871 ji2->JobId = job->job_id;
7874 string_to_buf(job->document_title, ptr, left, &size, unicode);
7875 if(space && size <= left)
7877 ji2->pDocument = (LPWSTR)ptr;
7878 ptr += size;
7879 left -= size;
7881 else
7882 space = FALSE;
7883 *pcbNeeded += size;
7885 if (job->printer_name)
7887 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7888 if(space && size <= left)
7890 ji2->pPrinterName = (LPWSTR)ptr;
7891 ptr += size;
7892 left -= size;
7894 else
7895 space = FALSE;
7896 *pcbNeeded += size;
7899 if (job->devmode)
7901 if (!unicode)
7903 dmA = DEVMODEdupWtoA(job->devmode);
7904 devmode = (LPDEVMODEW) dmA;
7905 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7907 else
7909 devmode = job->devmode;
7910 size = devmode->dmSize + devmode->dmDriverExtra;
7913 if (!devmode)
7914 FIXME("Can't convert DEVMODE W to A\n");
7915 else
7917 /* align DEVMODE to a DWORD boundary */
7918 shift = (4 - (*pcbNeeded & 3)) & 3;
7919 size += shift;
7921 if (size <= left)
7923 ptr += shift;
7924 memcpy(ptr, devmode, size-shift);
7925 ji2->pDevMode = (LPDEVMODEW)ptr;
7926 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7927 ptr += size-shift;
7928 left -= size;
7930 else
7931 space = FALSE;
7932 *pcbNeeded +=size;
7936 return space;
7939 /*****************************************************************************
7940 * get_job_info
7942 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7943 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7945 BOOL ret = FALSE;
7946 DWORD needed = 0, size;
7947 job_t *job;
7948 LPBYTE ptr = pJob;
7950 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7952 EnterCriticalSection(&printer_handles_cs);
7953 job = get_job(hPrinter, JobId);
7954 if(!job)
7955 goto end;
7957 switch(Level)
7959 case 1:
7960 size = sizeof(JOB_INFO_1W);
7961 if(cbBuf >= size)
7963 cbBuf -= size;
7964 ptr += size;
7965 memset(pJob, 0, size);
7967 else
7968 cbBuf = 0;
7969 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7970 needed += size;
7971 break;
7973 case 2:
7974 size = sizeof(JOB_INFO_2W);
7975 if(cbBuf >= size)
7977 cbBuf -= size;
7978 ptr += size;
7979 memset(pJob, 0, size);
7981 else
7982 cbBuf = 0;
7983 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7984 needed += size;
7985 break;
7987 case 3:
7988 size = sizeof(JOB_INFO_3);
7989 if(cbBuf >= size)
7991 cbBuf -= size;
7992 memset(pJob, 0, size);
7993 ret = TRUE;
7995 else
7996 cbBuf = 0;
7997 needed = size;
7998 break;
8000 default:
8001 SetLastError(ERROR_INVALID_LEVEL);
8002 goto end;
8004 if(pcbNeeded)
8005 *pcbNeeded = needed;
8006 end:
8007 LeaveCriticalSection(&printer_handles_cs);
8008 return ret;
8011 /*****************************************************************************
8012 * GetJobA [WINSPOOL.@]
8015 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8016 DWORD cbBuf, LPDWORD pcbNeeded)
8018 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8021 /*****************************************************************************
8022 * GetJobW [WINSPOOL.@]
8025 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8026 DWORD cbBuf, LPDWORD pcbNeeded)
8028 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8031 /*****************************************************************************
8032 * schedule_pipe
8034 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8036 #ifdef HAVE_FORK
8037 char *unixname, *cmdA;
8038 DWORD len;
8039 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8040 BOOL ret = FALSE;
8041 char buf[1024];
8042 pid_t pid, wret;
8043 int status;
8045 if(!(unixname = wine_get_unix_file_name(filename)))
8046 return FALSE;
8048 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8049 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8050 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8052 TRACE("printing with: %s\n", cmdA);
8054 if((file_fd = open(unixname, O_RDONLY)) == -1)
8055 goto end;
8057 if (pipe(fds))
8059 ERR("pipe() failed!\n");
8060 goto end;
8063 if ((pid = fork()) == 0)
8065 close(0);
8066 dup2(fds[0], 0);
8067 close(fds[1]);
8069 /* reset signals that we previously set to SIG_IGN */
8070 signal(SIGPIPE, SIG_DFL);
8072 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8073 _exit(1);
8075 else if (pid == -1)
8077 ERR("fork() failed!\n");
8078 goto end;
8081 close(fds[0]);
8082 fds[0] = -1;
8083 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8084 write(fds[1], buf, no_read);
8086 close(fds[1]);
8087 fds[1] = -1;
8089 /* reap child */
8090 do {
8091 wret = waitpid(pid, &status, 0);
8092 } while (wret < 0 && errno == EINTR);
8093 if (wret < 0)
8095 ERR("waitpid() failed!\n");
8096 goto end;
8098 if (!WIFEXITED(status) || WEXITSTATUS(status))
8100 ERR("child process failed! %d\n", status);
8101 goto end;
8104 ret = TRUE;
8106 end:
8107 if(file_fd != -1) close(file_fd);
8108 if(fds[0] != -1) close(fds[0]);
8109 if(fds[1] != -1) close(fds[1]);
8111 HeapFree(GetProcessHeap(), 0, cmdA);
8112 HeapFree(GetProcessHeap(), 0, unixname);
8113 return ret;
8114 #else
8115 return FALSE;
8116 #endif
8119 /*****************************************************************************
8120 * schedule_lpr
8122 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8124 WCHAR *cmd;
8125 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8126 BOOL r;
8128 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8129 sprintfW(cmd, fmtW, printer_name);
8131 r = schedule_pipe(cmd, filename);
8133 HeapFree(GetProcessHeap(), 0, cmd);
8134 return r;
8137 #ifdef SONAME_LIBCUPS
8138 /*****************************************************************************
8139 * get_cups_jobs_ticket_options
8141 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8142 * The CUPS scheduler only looks for these in Print-File requests, and since
8143 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8144 * parsed.
8146 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8148 FILE *fp = fopen( file, "r" );
8149 char buf[257]; /* DSC max of 256 + '\0' */
8150 const char *ps_adobe = "%!PS-Adobe-";
8151 const char *cups_job = "%cupsJobTicket:";
8153 if (!fp) return num_options;
8154 if (!fgets( buf, sizeof(buf), fp )) goto end;
8155 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8156 while (fgets( buf, sizeof(buf), fp ))
8158 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8159 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8162 end:
8163 fclose( fp );
8164 return num_options;
8167 static int get_cups_default_options( const char *printer, int num_options, cups_option_t **options )
8169 cups_dest_t *dest;
8170 int i;
8172 if (!pcupsGetNamedDest) return num_options;
8174 dest = pcupsGetNamedDest( NULL, printer, NULL );
8175 if (!dest) return num_options;
8177 for (i = 0; i < dest->num_options; i++)
8179 if (!pcupsGetOption( dest->options[i].name, num_options, *options ))
8180 num_options = pcupsAddOption( dest->options[i].name, dest->options[i].value,
8181 num_options, options );
8184 pcupsFreeDests( 1, dest );
8185 return num_options;
8187 #endif
8189 /*****************************************************************************
8190 * schedule_cups
8192 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8194 #ifdef SONAME_LIBCUPS
8195 if(pcupsPrintFile)
8197 char *unixname, *queue, *unix_doc_title;
8198 DWORD len;
8199 BOOL ret;
8200 int num_options = 0, i;
8201 cups_option_t *options = NULL;
8203 if(!(unixname = wine_get_unix_file_name(filename)))
8204 return FALSE;
8206 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8207 queue = HeapAlloc(GetProcessHeap(), 0, len);
8208 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8210 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8211 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8212 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8214 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8215 num_options = get_cups_default_options( queue, num_options, &options );
8217 TRACE( "printing via cups with options:\n" );
8218 for (i = 0; i < num_options; i++)
8219 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8221 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8223 pcupsFreeOptions( num_options, options );
8225 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8226 HeapFree(GetProcessHeap(), 0, queue);
8227 HeapFree(GetProcessHeap(), 0, unixname);
8228 return ret;
8230 else
8231 #endif
8233 return schedule_lpr(printer_name, filename);
8237 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8239 LPWSTR filename;
8241 switch(msg)
8243 case WM_INITDIALOG:
8244 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8245 return TRUE;
8247 case WM_COMMAND:
8248 if(HIWORD(wparam) == BN_CLICKED)
8250 if(LOWORD(wparam) == IDOK)
8252 HANDLE hf;
8253 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8254 LPWSTR *output;
8256 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8257 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8259 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8261 WCHAR caption[200], message[200];
8262 int mb_ret;
8264 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8265 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8266 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8267 if(mb_ret == IDCANCEL)
8269 HeapFree(GetProcessHeap(), 0, filename);
8270 return TRUE;
8273 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8274 if(hf == INVALID_HANDLE_VALUE)
8276 WCHAR caption[200], message[200];
8278 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8279 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8280 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8281 HeapFree(GetProcessHeap(), 0, filename);
8282 return TRUE;
8284 CloseHandle(hf);
8285 DeleteFileW(filename);
8286 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8287 *output = filename;
8288 EndDialog(hwnd, IDOK);
8289 return TRUE;
8291 if(LOWORD(wparam) == IDCANCEL)
8293 EndDialog(hwnd, IDCANCEL);
8294 return TRUE;
8297 return FALSE;
8299 return FALSE;
8302 /*****************************************************************************
8303 * get_filename
8305 static BOOL get_filename(LPWSTR *filename)
8307 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8308 file_dlg_proc, (LPARAM)filename) == IDOK;
8311 /*****************************************************************************
8312 * schedule_file
8314 static BOOL schedule_file(LPCWSTR filename)
8316 LPWSTR output = NULL;
8318 if(get_filename(&output))
8320 BOOL r;
8321 TRACE("copy to %s\n", debugstr_w(output));
8322 r = CopyFileW(filename, output, FALSE);
8323 HeapFree(GetProcessHeap(), 0, output);
8324 return r;
8326 return FALSE;
8329 /*****************************************************************************
8330 * schedule_unixfile
8332 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8334 int in_fd, out_fd, no_read;
8335 char buf[1024];
8336 BOOL ret = FALSE;
8337 char *unixname, *outputA;
8338 DWORD len;
8340 if(!(unixname = wine_get_unix_file_name(filename)))
8341 return FALSE;
8343 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8344 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8345 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8347 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8348 in_fd = open(unixname, O_RDONLY);
8349 if(out_fd == -1 || in_fd == -1)
8350 goto end;
8352 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8353 write(out_fd, buf, no_read);
8355 ret = TRUE;
8356 end:
8357 if(in_fd != -1) close(in_fd);
8358 if(out_fd != -1) close(out_fd);
8359 HeapFree(GetProcessHeap(), 0, outputA);
8360 HeapFree(GetProcessHeap(), 0, unixname);
8361 return ret;
8364 /*****************************************************************************
8365 * ScheduleJob [WINSPOOL.@]
8368 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8370 opened_printer_t *printer;
8371 BOOL ret = FALSE;
8372 struct list *cursor, *cursor2;
8374 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8375 EnterCriticalSection(&printer_handles_cs);
8376 printer = get_opened_printer(hPrinter);
8377 if(!printer)
8378 goto end;
8380 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8382 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8383 HANDLE hf;
8385 if(job->job_id != dwJobID) continue;
8387 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8388 if(hf != INVALID_HANDLE_VALUE)
8390 PRINTER_INFO_5W *pi5 = NULL;
8391 LPWSTR portname = job->portname;
8392 DWORD needed;
8393 HKEY hkey;
8394 WCHAR output[1024];
8395 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8396 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8398 if (!portname)
8400 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8401 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8402 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8403 portname = pi5->pPortName;
8405 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8406 debugstr_w(portname));
8408 output[0] = 0;
8410 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8411 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8413 DWORD type, count = sizeof(output);
8414 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8415 RegCloseKey(hkey);
8417 if(output[0] == '|')
8419 ret = schedule_pipe(output + 1, job->filename);
8421 else if(output[0])
8423 ret = schedule_unixfile(output, job->filename);
8425 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8427 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8429 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8431 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8433 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8435 ret = schedule_file(job->filename);
8437 else
8439 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8441 HeapFree(GetProcessHeap(), 0, pi5);
8442 CloseHandle(hf);
8443 DeleteFileW(job->filename);
8445 list_remove(cursor);
8446 HeapFree(GetProcessHeap(), 0, job->document_title);
8447 HeapFree(GetProcessHeap(), 0, job->printer_name);
8448 HeapFree(GetProcessHeap(), 0, job->portname);
8449 HeapFree(GetProcessHeap(), 0, job->filename);
8450 HeapFree(GetProcessHeap(), 0, job->devmode);
8451 HeapFree(GetProcessHeap(), 0, job);
8452 break;
8454 end:
8455 LeaveCriticalSection(&printer_handles_cs);
8456 return ret;
8459 /*****************************************************************************
8460 * StartDocDlgA [WINSPOOL.@]
8462 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8464 UNICODE_STRING usBuffer;
8465 DOCINFOW docW;
8466 LPWSTR retW;
8467 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8468 LPSTR ret = NULL;
8470 docW.cbSize = sizeof(docW);
8471 if (doc->lpszDocName)
8473 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8474 if (!(docW.lpszDocName = docnameW)) return NULL;
8476 if (doc->lpszOutput)
8478 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8479 if (!(docW.lpszOutput = outputW)) return NULL;
8481 if (doc->lpszDatatype)
8483 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8484 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8486 docW.fwType = doc->fwType;
8488 retW = StartDocDlgW(hPrinter, &docW);
8490 if(retW)
8492 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8493 ret = HeapAlloc(GetProcessHeap(), 0, len);
8494 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8495 HeapFree(GetProcessHeap(), 0, retW);
8498 HeapFree(GetProcessHeap(), 0, datatypeW);
8499 HeapFree(GetProcessHeap(), 0, outputW);
8500 HeapFree(GetProcessHeap(), 0, docnameW);
8502 return ret;
8505 /*****************************************************************************
8506 * StartDocDlgW [WINSPOOL.@]
8508 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8509 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8510 * port is "FILE:". Also returns the full path if passed a relative path.
8512 * The caller should free the returned string from the process heap.
8514 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8516 LPWSTR ret = NULL;
8517 DWORD len, attr;
8519 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8521 PRINTER_INFO_5W *pi5;
8522 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8523 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8524 return NULL;
8525 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8526 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8527 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8529 HeapFree(GetProcessHeap(), 0, pi5);
8530 return NULL;
8532 HeapFree(GetProcessHeap(), 0, pi5);
8535 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8537 LPWSTR name;
8539 if (get_filename(&name))
8541 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8543 HeapFree(GetProcessHeap(), 0, name);
8544 return NULL;
8546 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8547 GetFullPathNameW(name, len, ret, NULL);
8548 HeapFree(GetProcessHeap(), 0, name);
8550 return ret;
8553 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8554 return NULL;
8556 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8557 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8559 attr = GetFileAttributesW(ret);
8560 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8562 HeapFree(GetProcessHeap(), 0, ret);
8563 ret = NULL;
8565 return ret;
8568 /*****************************************************************************
8569 * UploadPrinterDriverPackageA [WINSPOOL.@]
8571 HRESULT WINAPI UploadPrinterDriverPackageA( LPCSTR server, LPCSTR path, LPCSTR env,
8572 DWORD flags, HWND hwnd, LPSTR dst, PULONG dstlen )
8574 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server), debugstr_a(path), debugstr_a(env),
8575 flags, hwnd, dst, dstlen);
8576 return E_NOTIMPL;
8579 /*****************************************************************************
8580 * UploadPrinterDriverPackageW [WINSPOOL.@]
8582 HRESULT WINAPI UploadPrinterDriverPackageW( LPCWSTR server, LPCWSTR path, LPCWSTR env,
8583 DWORD flags, HWND hwnd, LPWSTR dst, PULONG dstlen )
8585 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server), debugstr_w(path), debugstr_w(env),
8586 flags, hwnd, dst, dstlen);
8587 return E_NOTIMPL;