ntoskrnl.exe: Implement ObReferenceObjectByName but only for loaded drivers.
[wine.git] / dlls / winspool.drv / info.c
blob4dea5310e36b50f5583c9f8cda475d26cbc5a40d
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
47 #ifdef HAVE_CUPS_PPD_H
48 # include <cups/ppd.h>
49 #endif
51 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
52 #define GetCurrentProcess GetCurrentProcess_Mac
53 #define GetCurrentThread GetCurrentThread_Mac
54 #define LoadResource LoadResource_Mac
55 #define AnimatePalette AnimatePalette_Mac
56 #define EqualRgn EqualRgn_Mac
57 #define FillRgn FillRgn_Mac
58 #define FrameRgn FrameRgn_Mac
59 #define GetPixel GetPixel_Mac
60 #define InvertRgn InvertRgn_Mac
61 #define LineTo LineTo_Mac
62 #define OffsetRgn OffsetRgn_Mac
63 #define PaintRgn PaintRgn_Mac
64 #define Polygon Polygon_Mac
65 #define ResizePalette ResizePalette_Mac
66 #define SetRectRgn SetRectRgn_Mac
67 #define EqualRect EqualRect_Mac
68 #define FillRect FillRect_Mac
69 #define FrameRect FrameRect_Mac
70 #define GetCursor GetCursor_Mac
71 #define InvertRect InvertRect_Mac
72 #define OffsetRect OffsetRect_Mac
73 #define PtInRect PtInRect_Mac
74 #define SetCursor SetCursor_Mac
75 #define SetRect SetRect_Mac
76 #define ShowCursor ShowCursor_Mac
77 #define UnionRect UnionRect_Mac
78 #include <ApplicationServices/ApplicationServices.h>
79 #undef GetCurrentProcess
80 #undef GetCurrentThread
81 #undef LoadResource
82 #undef AnimatePalette
83 #undef EqualRgn
84 #undef FillRgn
85 #undef FrameRgn
86 #undef GetPixel
87 #undef InvertRgn
88 #undef LineTo
89 #undef OffsetRgn
90 #undef PaintRgn
91 #undef Polygon
92 #undef ResizePalette
93 #undef SetRectRgn
94 #undef EqualRect
95 #undef FillRect
96 #undef FrameRect
97 #undef GetCursor
98 #undef InvertRect
99 #undef OffsetRect
100 #undef PtInRect
101 #undef SetCursor
102 #undef SetRect
103 #undef ShowCursor
104 #undef UnionRect
105 #undef DPRINTF
106 #endif
108 #include "wine/library.h"
109 #include "windef.h"
110 #include "winbase.h"
111 #include "winuser.h"
112 #include "winerror.h"
113 #include "winreg.h"
114 #include "wingdi.h"
115 #include "winspool.h"
116 #include "winternl.h"
117 #include "wine/windef16.h"
118 #include "wine/unicode.h"
119 #include "wine/debug.h"
120 #include "wine/list.h"
121 #include "winnls.h"
123 #include "ddk/winsplp.h"
124 #include "wspool.h"
126 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
128 /* ############################### */
130 static CRITICAL_SECTION printer_handles_cs;
131 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
133 0, 0, &printer_handles_cs,
134 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
135 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
137 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
139 /* ############################### */
141 typedef struct {
142 DWORD job_id;
143 HANDLE hf;
144 } started_doc_t;
146 typedef struct {
147 struct list jobs;
148 LONG ref;
149 } jobqueue_t;
151 typedef struct {
152 LPWSTR name;
153 LPWSTR printername;
154 HANDLE backend_printer;
155 jobqueue_t *queue;
156 started_doc_t *doc;
157 DEVMODEW *devmode;
158 } opened_printer_t;
160 typedef struct {
161 struct list entry;
162 DWORD job_id;
163 WCHAR *filename;
164 WCHAR *portname;
165 WCHAR *document_title;
166 WCHAR *printer_name;
167 LPDEVMODEW devmode;
168 } job_t;
171 typedef struct {
172 LPCWSTR envname;
173 LPCWSTR subdir;
174 DWORD driverversion;
175 LPCWSTR versionregpath;
176 LPCWSTR versionsubdir;
177 } printenv_t;
179 /* ############################### */
181 static opened_printer_t **printer_handles;
182 static UINT nb_printer_handles;
183 static LONG next_job_id = 1;
185 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
186 WORD fwCapability, LPSTR lpszOutput,
187 LPDEVMODEA lpdm );
188 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
189 LPSTR lpszDevice, LPSTR lpszPort,
190 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
191 DWORD fwMode );
193 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
194 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
195 'c','o','n','t','r','o','l','\\',
196 'P','r','i','n','t','\\',
197 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
198 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
200 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
201 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
202 'C','o','n','t','r','o','l','\\',
203 'P','r','i','n','t','\\',
204 'P','r','i','n','t','e','r','s',0};
206 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
207 'M','i','c','r','o','s','o','f','t','\\',
208 'W','i','n','d','o','w','s',' ','N','T','\\',
209 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
210 'W','i','n','d','o','w','s',0};
212 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
213 'M','i','c','r','o','s','o','f','t','\\',
214 'W','i','n','d','o','w','s',' ','N','T','\\',
215 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
216 'D','e','v','i','c','e','s',0};
218 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
219 'M','i','c','r','o','s','o','f','t','\\',
220 'W','i','n','d','o','w','s',' ','N','T','\\',
221 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
222 'P','r','i','n','t','e','r','P','o','r','t','s',0};
224 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
225 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
226 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
227 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
228 static const WCHAR subdir_x64W[] = {'x','6','4',0};
229 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
230 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
231 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
232 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
233 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
235 static const WCHAR AttributesW[] = {'A','t','t','r','i','b','u','t','e','s',0};
236 static const WCHAR backslashW[] = {'\\',0};
237 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
238 'i','o','n',' ','F','i','l','e',0};
239 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
240 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
241 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
242 static const WCHAR Default_PriorityW[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
243 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
244 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
245 static const WCHAR dnsTimeoutW[] = {'d','n','s','T','i','m','e','o','u','t',0};
246 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
247 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
248 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
249 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
250 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
251 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
252 static const WCHAR NameW[] = {'N','a','m','e',0};
253 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
254 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
255 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
256 static const WCHAR PortW[] = {'P','o','r','t',0};
257 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
258 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
259 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
260 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
261 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
262 static const WCHAR PriorityW[] = {'P','r','i','o','r','i','t','y',0};
263 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
264 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
265 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
266 static const WCHAR StartTimeW[] = {'S','t','a','r','t','T','i','m','e',0};
267 static const WCHAR StatusW[] = {'S','t','a','t','u','s',0};
268 static const WCHAR txTimeoutW[] = {'t','x','T','i','m','e','o','u','t',0};
269 static const WCHAR UntilTimeW[] = {'U','n','t','i','l','T','i','m','e',0};
270 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
271 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
272 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
273 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
274 static WCHAR rawW[] = {'R','A','W',0};
275 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
276 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
277 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
278 static const WCHAR commaW[] = {',',0};
279 static WCHAR emptyStringW[] = {0};
281 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
283 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
284 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
285 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
287 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
288 'D','o','c','u','m','e','n','t',0};
290 static const WCHAR PPD_Overrides[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
291 static const WCHAR DefaultPageSize[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
293 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
294 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
295 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
296 0, sizeof(DRIVER_INFO_8W)};
299 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
300 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
301 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
302 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
303 sizeof(PRINTER_INFO_9W)};
305 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
306 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
307 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
309 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
311 /******************************************************************
312 * validate the user-supplied printing-environment [internal]
314 * PARAMS
315 * env [I] PTR to Environment-String or NULL
317 * RETURNS
318 * Failure: NULL
319 * Success: PTR to printenv_t
321 * NOTES
322 * An empty string is handled the same way as NULL.
323 * SetLastError(ERROR_INVALID_ENVIRONMENT) is called on Failure
327 static const printenv_t * validate_envW(LPCWSTR env)
329 const printenv_t *result = NULL;
330 unsigned int i;
332 TRACE("testing %s\n", debugstr_w(env));
333 if (env && env[0])
335 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
337 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
339 result = all_printenv[i];
340 break;
344 if (result == NULL) {
345 FIXME("unsupported Environment: %s\n", debugstr_w(env));
346 SetLastError(ERROR_INVALID_ENVIRONMENT);
348 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
350 else
352 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
354 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
356 return result;
360 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
361 if passed a NULL string. This returns NULLs to the result.
363 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
365 if ( (src) )
367 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
368 return usBufferPtr->Buffer;
370 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
371 return NULL;
374 static LPWSTR strdupW(LPCWSTR p)
376 LPWSTR ret;
377 DWORD len;
379 if(!p) return NULL;
380 len = (strlenW(p) + 1) * sizeof(WCHAR);
381 ret = HeapAlloc(GetProcessHeap(), 0, len);
382 memcpy(ret, p, len);
383 return ret;
386 static LPSTR strdupWtoA( LPCWSTR str )
388 LPSTR ret;
389 INT len;
391 if (!str) return NULL;
392 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
393 ret = HeapAlloc( GetProcessHeap(), 0, len );
394 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
395 return ret;
398 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
400 DEVMODEW *ret;
402 if (!dm) return NULL;
403 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
404 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
405 return ret;
408 /***********************************************************
409 * DEVMODEdupWtoA
410 * Creates an ansi copy of supplied devmode
412 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
414 LPDEVMODEA dmA;
415 DWORD size;
417 if (!dmW) return NULL;
418 size = dmW->dmSize - CCHDEVICENAME -
419 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
421 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
422 if (!dmA) return NULL;
424 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
425 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
427 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
429 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
430 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
432 else
434 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
435 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
436 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
437 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
439 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
442 dmA->dmSize = size;
443 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
444 return dmA;
448 /******************************************************************
449 * verify, that the filename is a local file
452 static inline BOOL is_local_file(LPWSTR name)
454 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
457 /* ################################ */
459 static int multi_sz_lenA(const char *str)
461 const char *ptr = str;
462 if(!str) return 0;
465 ptr += lstrlenA(ptr) + 1;
466 } while(*ptr);
468 return ptr - str + 1;
471 /*****************************************************************************
472 * get_dword_from_reg
474 * Return DWORD associated with name from hkey.
476 static DWORD get_dword_from_reg( HKEY hkey, const WCHAR *name )
478 DWORD sz = sizeof(DWORD), type, value = 0;
479 LONG ret;
481 ret = RegQueryValueExW( hkey, name, 0, &type, (LPBYTE)&value, &sz );
483 if (ret != ERROR_SUCCESS)
485 WARN( "Got ret = %d on name %s\n", ret, debugstr_w(name) );
486 return 0;
488 if (type != REG_DWORD)
490 ERR( "Got type %d\n", type );
491 return 0;
493 return value;
496 static inline DWORD set_reg_DWORD( HKEY hkey, const WCHAR *keyname, const DWORD value )
498 return RegSetValueExW( hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value) );
501 /******************************************************************
502 * get_opened_printer
503 * Get the pointer to the opened printer referred by the handle
505 static opened_printer_t *get_opened_printer(HANDLE hprn)
507 UINT_PTR idx = (UINT_PTR)hprn;
508 opened_printer_t *ret = NULL;
510 EnterCriticalSection(&printer_handles_cs);
512 if ((idx > 0) && (idx <= nb_printer_handles)) {
513 ret = printer_handles[idx - 1];
515 LeaveCriticalSection(&printer_handles_cs);
516 return ret;
519 /******************************************************************
520 * get_opened_printer_name
521 * Get the pointer to the opened printer name referred by the handle
523 static LPCWSTR get_opened_printer_name(HANDLE hprn)
525 opened_printer_t *printer = get_opened_printer(hprn);
526 if(!printer) return NULL;
527 return printer->name;
530 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
532 HKEY printers;
533 DWORD err;
535 *key = NULL;
536 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
537 if (err) return err;
539 err = RegOpenKeyW( printers, name, key );
540 if (err) err = ERROR_INVALID_PRINTER_NAME;
541 RegCloseKey( printers );
542 return err;
545 /******************************************************************
546 * WINSPOOL_GetOpenedPrinterRegKey
549 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
551 LPCWSTR name = get_opened_printer_name(hPrinter);
553 if(!name) return ERROR_INVALID_HANDLE;
554 return open_printer_reg_key( name, phkey );
557 static void
558 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
559 char qbuf[200];
561 /* If forcing, or no profile string entry for device yet, set the entry
563 * The always change entry if not WINEPS yet is discussable.
565 if (force ||
566 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
567 !strcmp(qbuf,"*") ||
568 !strstr(qbuf,"WINEPS.DRV")
570 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
571 HKEY hkey;
573 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
574 WriteProfileStringA("windows","device",buf);
575 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
576 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
577 RegCloseKey(hkey);
579 HeapFree(GetProcessHeap(),0,buf);
583 static BOOL add_printer_driver(const WCHAR *name, WCHAR *ppd)
585 DRIVER_INFO_3W di3;
587 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
588 di3.cVersion = 3;
589 di3.pName = (WCHAR*)name;
590 di3.pEnvironment = envname_x86W;
591 di3.pDriverPath = driver_nt;
592 di3.pDataFile = ppd;
593 di3.pConfigFile = driver_nt;
594 di3.pDefaultDataType = rawW;
596 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
597 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
599 di3.cVersion = 0;
600 di3.pEnvironment = envname_win40W;
601 di3.pDriverPath = driver_9x;
602 di3.pConfigFile = driver_9x;
603 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
604 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
606 return TRUE;
609 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
610 return FALSE;
613 static inline char *expand_env_string( char *str, DWORD type )
615 if (type == REG_EXPAND_SZ)
617 char *tmp;
618 DWORD needed = ExpandEnvironmentStringsA( str, NULL, 0 );
619 tmp = HeapAlloc( GetProcessHeap(), 0, needed );
620 if (tmp)
622 ExpandEnvironmentStringsA( str, tmp, needed );
623 HeapFree( GetProcessHeap(), 0, str );
624 return tmp;
627 return str;
630 static char *get_fallback_ppd_name( const char *printer_name )
632 static const WCHAR ppds_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
633 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
634 HKEY hkey;
635 DWORD needed, type;
636 char *ret = NULL;
638 if (RegOpenKeyW( HKEY_CURRENT_USER, ppds_key, &hkey ) == ERROR_SUCCESS )
640 const char *value_name = NULL;
642 if (RegQueryValueExA( hkey, printer_name, 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
643 value_name = printer_name;
644 else if (RegQueryValueExA( hkey, "generic", 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
645 value_name = "generic";
647 if (value_name)
649 ret = HeapAlloc( GetProcessHeap(), 0, needed );
650 if (!ret) return NULL;
651 RegQueryValueExA( hkey, value_name, 0, &type, (BYTE *)ret, &needed );
653 RegCloseKey( hkey );
654 if (ret) return expand_env_string( ret, type );
656 return NULL;
659 static BOOL copy_file( const char *src, const char *dst )
661 int fds[2] = {-1, -1}, num;
662 char buf[1024];
663 BOOL ret = FALSE;
665 fds[0] = open( src, O_RDONLY );
666 fds[1] = open( dst, O_CREAT | O_TRUNC | O_WRONLY, 0666 );
667 if (fds[0] == -1 || fds[1] == -1) goto fail;
669 while ((num = read( fds[0], buf, sizeof(buf) )) != 0)
671 if (num == -1) goto fail;
672 if (write( fds[1], buf, num ) != num) goto fail;
674 ret = TRUE;
676 fail:
677 if (fds[1] != -1) close( fds[1] );
678 if (fds[0] != -1) close( fds[0] );
679 return ret;
682 static BOOL get_internal_fallback_ppd( const WCHAR *ppd )
684 static const WCHAR typeW[] = {'P','P','D','F','I','L','E',0};
686 char *ptr, *end;
687 DWORD size, written;
688 HANDLE file;
689 BOOL ret;
690 HRSRC res = FindResourceW( WINSPOOL_hInstance, MAKEINTRESOURCEW(1), typeW );
692 if (!res || !(ptr = LoadResource( WINSPOOL_hInstance, res ))) return FALSE;
693 size = SizeofResource( WINSPOOL_hInstance, res );
694 end = memchr( ptr, 0, size ); /* resource file may contain additional nulls */
695 if (end) size = end - ptr;
696 file = CreateFileW( ppd, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0 );
697 if (file == INVALID_HANDLE_VALUE) return FALSE;
698 ret = WriteFile( file, ptr, size, &written, NULL ) && written == size;
699 CloseHandle( file );
700 if (ret) TRACE( "using internal fallback for %s\n", debugstr_w( ppd ));
701 else DeleteFileW( ppd );
702 return ret;
705 static BOOL get_fallback_ppd( const char *printer_name, const WCHAR *ppd )
707 char *dst, *src = get_fallback_ppd_name( printer_name );
708 BOOL ret = FALSE;
710 if (!src) return get_internal_fallback_ppd( ppd );
712 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name), debugstr_w(ppd), debugstr_a(src) );
714 if (!(dst = wine_get_unix_file_name( ppd ))) goto fail;
716 if (symlink( src, dst ) == -1)
717 if (errno != ENOSYS || !copy_file( src, dst ))
718 goto fail;
720 ret = TRUE;
721 fail:
722 HeapFree( GetProcessHeap(), 0, dst );
723 HeapFree( GetProcessHeap(), 0, src );
724 return ret;
727 static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
729 static const WCHAR dot_ppd[] = {'.','p','p','d',0};
730 int len = (strlenW( dir ) + strlenW( file_name )) * sizeof(WCHAR) + sizeof(dot_ppd);
731 WCHAR *ppd = HeapAlloc( GetProcessHeap(), 0, len );
733 if (!ppd) return NULL;
734 strcpyW( ppd, dir );
735 strcatW( ppd, file_name );
736 strcatW( ppd, dot_ppd );
738 return ppd;
741 static WCHAR *get_ppd_dir( void )
743 static const WCHAR wine_ppds[] = {'w','i','n','e','_','p','p','d','s','\\',0};
744 DWORD len;
745 WCHAR *dir, tmp_path[MAX_PATH];
746 BOOL res;
748 len = GetTempPathW( sizeof(tmp_path) / sizeof(tmp_path[0]), tmp_path );
749 if (!len) return NULL;
750 dir = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
751 if (!dir) return NULL;
753 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
754 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
755 res = CreateDirectoryW( dir, NULL );
756 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
758 HeapFree( GetProcessHeap(), 0, dir );
759 dir = NULL;
761 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
762 return dir;
765 static void unlink_ppd( const WCHAR *ppd )
767 char *unix_name = wine_get_unix_file_name( ppd );
768 unlink( unix_name );
769 HeapFree( GetProcessHeap(), 0, unix_name );
772 #ifdef SONAME_LIBCUPS
774 static void *cupshandle;
776 #define CUPS_FUNCS \
777 DO_FUNC(cupsAddOption); \
778 DO_FUNC(cupsFreeDests); \
779 DO_FUNC(cupsFreeOptions); \
780 DO_FUNC(cupsGetDests); \
781 DO_FUNC(cupsGetOption); \
782 DO_FUNC(cupsGetPPD); \
783 DO_FUNC(cupsParseOptions); \
784 DO_FUNC(cupsPrintFile)
785 #define CUPS_OPT_FUNCS \
786 DO_FUNC(cupsGetNamedDest); \
787 DO_FUNC(cupsGetPPD3); \
788 DO_FUNC(cupsLastErrorString)
790 #define DO_FUNC(f) static typeof(f) *p##f
791 CUPS_FUNCS;
792 #undef DO_FUNC
793 static cups_dest_t * (*pcupsGetNamedDest)(http_t *, const char *, const char *);
794 static http_status_t (*pcupsGetPPD3)(http_t *, const char *, time_t *, char *, size_t);
795 static const char * (*pcupsLastErrorString)(void);
797 static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name,
798 time_t *modtime, char *buffer,
799 size_t bufsize )
801 const char *ppd;
803 if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
805 if (!pcupsGetPPD) return HTTP_NOT_FOUND;
807 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
809 *modtime = 0;
810 ppd = pcupsGetPPD( name );
812 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
814 if (!ppd) return HTTP_NOT_FOUND;
816 if (rename( ppd, buffer ) == -1)
818 BOOL res = copy_file( ppd, buffer );
819 unlink( ppd );
820 if (!res) return HTTP_NOT_FOUND;
822 return HTTP_OK;
825 static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
827 time_t modtime = 0;
828 http_status_t http_status;
829 char *unix_name = wine_get_unix_file_name( ppd );
831 TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
833 if (!unix_name) return FALSE;
835 http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
836 unix_name, strlen( unix_name ) + 1 );
838 if (http_status != HTTP_OK) unlink( unix_name );
839 HeapFree( GetProcessHeap(), 0, unix_name );
841 if (http_status == HTTP_OK) return TRUE;
843 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
844 debugstr_a(printer_name), http_status );
845 return get_fallback_ppd( printer_name, ppd );
848 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
850 const char *value;
851 WCHAR *ret;
852 int len;
854 value = pcupsGetOption( name, num_options, options );
855 if (!value) return NULL;
857 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
858 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
859 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
861 return ret;
864 static cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
866 WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
867 cups_ptype_t ret = 0;
869 if (type && *type)
871 ret = (cups_ptype_t)strtoulW( type, &end, 10 );
872 if (*end) ret = 0;
874 HeapFree( GetProcessHeap(), 0, type );
875 return ret;
878 static void load_cups(void)
880 cupshandle = wine_dlopen( SONAME_LIBCUPS, RTLD_NOW, NULL, 0 );
881 if (!cupshandle) return;
883 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
885 #define DO_FUNC(x) \
886 p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); \
887 if (!p##x) \
889 ERR("failed to load symbol %s\n", #x); \
890 cupshandle = NULL; \
891 return; \
893 CUPS_FUNCS;
894 #undef DO_FUNC
895 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 )
896 CUPS_OPT_FUNCS;
897 #undef DO_FUNC
900 static BOOL CUPS_LoadPrinters(void)
902 int i, nrofdests;
903 BOOL hadprinter = FALSE, haddefault = FALSE;
904 cups_dest_t *dests;
905 PRINTER_INFO_2W pi2;
906 WCHAR *port, *ppd_dir = NULL, *ppd;
907 HKEY hkeyPrinter, hkeyPrinters;
908 WCHAR nameW[MAX_PATH];
909 HANDLE added_printer;
910 cups_ptype_t printer_type;
912 if (!cupshandle) return FALSE;
914 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
915 ERROR_SUCCESS) {
916 ERR("Can't create Printers key\n");
917 return FALSE;
920 nrofdests = pcupsGetDests(&dests);
921 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
922 for (i=0;i<nrofdests;i++) {
923 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
924 printer_type = get_cups_printer_type( dests + i );
926 TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
928 if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
930 TRACE( "skipping scanner-only device\n" );
931 continue;
934 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
935 lstrcpyW(port, CUPS_Port);
936 lstrcatW(port, nameW);
938 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
939 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
940 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
941 and continue */
942 TRACE("Printer already exists\n");
943 /* overwrite old LPR:* port */
944 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
945 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
946 /* flag that the PPD file should be checked for an update */
947 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
948 RegCloseKey(hkeyPrinter);
949 } else {
950 BOOL added_driver = FALSE;
952 if (!ppd_dir && !(ppd_dir = get_ppd_dir()))
954 HeapFree( GetProcessHeap(), 0, port );
955 break;
957 ppd = get_ppd_filename( ppd_dir, nameW );
958 if (get_cups_ppd( dests[i].name, ppd ))
960 added_driver = add_printer_driver( nameW, ppd );
961 unlink_ppd( ppd );
963 HeapFree( GetProcessHeap(), 0, ppd );
964 if (!added_driver)
966 HeapFree( GetProcessHeap(), 0, port );
967 continue;
970 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
971 pi2.pPrinterName = nameW;
972 pi2.pDatatype = rawW;
973 pi2.pPrintProcessor = WinPrintW;
974 pi2.pDriverName = nameW;
975 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
976 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
977 pi2.pPortName = port;
978 pi2.pParameters = emptyStringW;
979 pi2.pShareName = emptyStringW;
980 pi2.pSepFile = emptyStringW;
982 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
983 if (added_printer) ClosePrinter( added_printer );
984 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
985 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
987 HeapFree( GetProcessHeap(), 0, pi2.pComment );
988 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
990 HeapFree( GetProcessHeap(), 0, port );
992 hadprinter = TRUE;
993 if (dests[i].is_default) {
994 SetDefaultPrinterW(nameW);
995 haddefault = TRUE;
999 if (ppd_dir)
1001 RemoveDirectoryW( ppd_dir );
1002 HeapFree( GetProcessHeap(), 0, ppd_dir );
1005 if (hadprinter && !haddefault) {
1006 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
1007 SetDefaultPrinterW(nameW);
1009 pcupsFreeDests(nrofdests, dests);
1010 RegCloseKey(hkeyPrinters);
1011 return TRUE;
1014 #endif
1016 static char *get_queue_name( HANDLE printer, BOOL *cups )
1018 WCHAR *port, *name = NULL;
1019 DWORD err, needed, type;
1020 char *ret = NULL;
1021 HKEY key;
1023 *cups = FALSE;
1025 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1026 if (err) return NULL;
1027 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1028 if (err) goto end;
1029 port = HeapAlloc( GetProcessHeap(), 0, needed );
1030 if (!port) goto end;
1031 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1033 if (!strncmpW( port, CUPS_Port, sizeof(CUPS_Port) / sizeof(WCHAR) -1 ))
1035 name = port + sizeof(CUPS_Port) / sizeof(WCHAR) - 1;
1036 *cups = TRUE;
1038 else if (!strncmpW( port, LPR_Port, sizeof(LPR_Port) / sizeof(WCHAR) -1 ))
1039 name = port + sizeof(LPR_Port) / sizeof(WCHAR) - 1;
1040 if (name)
1042 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1043 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1044 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1046 HeapFree( GetProcessHeap(), 0, port );
1047 end:
1048 RegCloseKey( key );
1049 return ret;
1053 static void set_ppd_overrides( HANDLE printer )
1055 WCHAR *wstr = NULL;
1056 int size = 0;
1057 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1058 OSStatus status;
1059 PMPrintSession session = NULL;
1060 PMPageFormat format = NULL;
1061 PMPaper paper;
1062 CFStringRef paper_name;
1063 CFRange range;
1065 status = PMCreateSession( &session );
1066 if (status) goto end;
1068 status = PMCreatePageFormat( &format );
1069 if (status) goto end;
1071 status = PMSessionDefaultPageFormat( session, format );
1072 if (status) goto end;
1074 status = PMGetPageFormatPaper( format, &paper );
1075 if (status) goto end;
1077 status = PMPaperGetPPDPaperName( paper, &paper_name );
1078 if (status) goto end;
1080 range.location = 0;
1081 range.length = CFStringGetLength( paper_name );
1082 size = (range.length + 1) * sizeof(WCHAR);
1084 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1085 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1086 wstr[range.length] = 0;
1088 end:
1089 if (format) PMRelease( format );
1090 if (session) PMRelease( session );
1091 #endif
1093 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1094 HeapFree( GetProcessHeap(), 0, wstr );
1097 static BOOL update_driver( HANDLE printer )
1099 BOOL ret, is_cups;
1100 const WCHAR *name = get_opened_printer_name( printer );
1101 WCHAR *ppd_dir, *ppd;
1102 char *queue_name;
1104 if (!name) return FALSE;
1105 queue_name = get_queue_name( printer, &is_cups );
1106 if (!queue_name) return FALSE;
1108 if (!(ppd_dir = get_ppd_dir()))
1110 HeapFree( GetProcessHeap(), 0, queue_name );
1111 return FALSE;
1113 ppd = get_ppd_filename( ppd_dir, name );
1115 #ifdef SONAME_LIBCUPS
1116 if (is_cups)
1117 ret = get_cups_ppd( queue_name, ppd );
1118 else
1119 #endif
1120 ret = get_fallback_ppd( queue_name, ppd );
1122 if (ret)
1124 TRACE( "updating driver %s\n", debugstr_w( name ) );
1125 ret = add_printer_driver( name, ppd );
1126 unlink_ppd( ppd );
1128 HeapFree( GetProcessHeap(), 0, ppd_dir );
1129 HeapFree( GetProcessHeap(), 0, ppd );
1130 HeapFree( GetProcessHeap(), 0, queue_name );
1132 set_ppd_overrides( printer );
1134 /* call into the driver to update the devmode */
1135 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1137 return ret;
1140 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1142 PRINTER_INFO_2A pinfo2a;
1143 const char *r;
1144 size_t name_len;
1145 char *e,*s,*name,*prettyname,*devname;
1146 BOOL ret = FALSE, set_default = FALSE;
1147 char *port = NULL, *env_default;
1148 HKEY hkeyPrinter, hkeyPrinters = NULL;
1149 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1150 HANDLE added_printer;
1152 while (isspace(*pent)) pent++;
1153 r = strchr(pent,':');
1154 if (r)
1155 name_len = r - pent;
1156 else
1157 name_len = strlen(pent);
1158 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1159 memcpy(name, pent, name_len);
1160 name[name_len] = '\0';
1161 if (r)
1162 pent = r;
1163 else
1164 pent = "";
1166 TRACE("name=%s entry=%s\n",name, pent);
1168 if(ispunct(*name)) { /* a tc entry, not a real printer */
1169 TRACE("skipping tc entry\n");
1170 goto end;
1173 if(strstr(pent,":server")) { /* server only version so skip */
1174 TRACE("skipping server entry\n");
1175 goto end;
1178 /* Determine whether this is a postscript printer. */
1180 ret = TRUE;
1181 env_default = getenv("PRINTER");
1182 prettyname = name;
1183 /* Get longest name, usually the one at the right for later display. */
1184 while((s=strchr(prettyname,'|'))) {
1185 *s = '\0';
1186 e = s;
1187 while(isspace(*--e)) *e = '\0';
1188 TRACE("\t%s\n", debugstr_a(prettyname));
1189 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1190 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1193 e = prettyname + strlen(prettyname);
1194 while(isspace(*--e)) *e = '\0';
1195 TRACE("\t%s\n", debugstr_a(prettyname));
1196 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1198 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1199 * if it is too long, we use it as comment below. */
1200 devname = prettyname;
1201 if (strlen(devname)>=CCHDEVICENAME-1)
1202 devname = name;
1203 if (strlen(devname)>=CCHDEVICENAME-1) {
1204 ret = FALSE;
1205 goto end;
1208 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1209 sprintf(port,"LPR:%s",name);
1211 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1212 ERROR_SUCCESS) {
1213 ERR("Can't create Printers key\n");
1214 ret = FALSE;
1215 goto end;
1218 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
1220 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1221 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1222 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1223 and continue */
1224 TRACE("Printer already exists\n");
1225 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1226 /* flag that the PPD file should be checked for an update */
1227 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1228 RegCloseKey(hkeyPrinter);
1229 } else {
1230 static CHAR data_type[] = "RAW",
1231 print_proc[] = "WinPrint",
1232 comment[] = "WINEPS Printer using LPR",
1233 params[] = "<parameters?>",
1234 share_name[] = "<share name?>",
1235 sep_file[] = "<sep file?>";
1236 BOOL added_driver = FALSE;
1238 if (!ppd_dir && !(ppd_dir = get_ppd_dir())) goto end;
1239 ppd = get_ppd_filename( ppd_dir, devnameW );
1240 if (get_fallback_ppd( devname, ppd ))
1242 added_driver = add_printer_driver( devnameW, ppd );
1243 unlink_ppd( ppd );
1245 HeapFree( GetProcessHeap(), 0, ppd );
1246 if (!added_driver) goto end;
1248 memset(&pinfo2a,0,sizeof(pinfo2a));
1249 pinfo2a.pPrinterName = devname;
1250 pinfo2a.pDatatype = data_type;
1251 pinfo2a.pPrintProcessor = print_proc;
1252 pinfo2a.pDriverName = devname;
1253 pinfo2a.pComment = comment;
1254 pinfo2a.pLocation = prettyname;
1255 pinfo2a.pPortName = port;
1256 pinfo2a.pParameters = params;
1257 pinfo2a.pShareName = share_name;
1258 pinfo2a.pSepFile = sep_file;
1260 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1261 if (added_printer) ClosePrinter( added_printer );
1262 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1263 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1266 if (isfirst || set_default)
1267 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1269 end:
1270 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1271 if (ppd_dir)
1273 RemoveDirectoryW( ppd_dir );
1274 HeapFree( GetProcessHeap(), 0, ppd_dir );
1276 HeapFree(GetProcessHeap(), 0, port);
1277 HeapFree(GetProcessHeap(), 0, name);
1278 return ret;
1281 static BOOL
1282 PRINTCAP_LoadPrinters(void) {
1283 BOOL hadprinter = FALSE;
1284 char buf[200];
1285 FILE *f;
1286 char *pent = NULL;
1287 BOOL had_bash = FALSE;
1289 f = fopen("/etc/printcap","r");
1290 if (!f)
1291 return FALSE;
1293 while(fgets(buf,sizeof(buf),f)) {
1294 char *start, *end;
1296 end=strchr(buf,'\n');
1297 if (end) *end='\0';
1299 start = buf;
1300 while(isspace(*start)) start++;
1301 if(*start == '#' || *start == '\0')
1302 continue;
1304 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1305 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1306 HeapFree(GetProcessHeap(),0,pent);
1307 pent = NULL;
1310 if (end && *--end == '\\') {
1311 *end = '\0';
1312 had_bash = TRUE;
1313 } else
1314 had_bash = FALSE;
1316 if (pent) {
1317 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1318 strcat(pent,start);
1319 } else {
1320 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1321 strcpy(pent,start);
1325 if(pent) {
1326 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1327 HeapFree(GetProcessHeap(),0,pent);
1329 fclose(f);
1330 return hadprinter;
1333 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1335 if (value)
1336 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1337 (lstrlenW(value) + 1) * sizeof(WCHAR));
1338 else
1339 return ERROR_FILE_NOT_FOUND;
1342 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1344 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1345 DWORD ret = ERROR_FILE_NOT_FOUND;
1347 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1348 and we support these drivers. NT writes DEVMODEW so somehow
1349 we'll need to distinguish between these when we support NT
1350 drivers */
1352 if (dmA)
1354 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1355 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1356 HeapFree( GetProcessHeap(), 0, dmA );
1359 return ret;
1362 /******************************************************************
1363 * get_servername_from_name (internal)
1365 * for an external server, a copy of the serverpart from the full name is returned
1368 static LPWSTR get_servername_from_name(LPCWSTR name)
1370 LPWSTR server;
1371 LPWSTR ptr;
1372 WCHAR buffer[MAX_PATH];
1373 DWORD len;
1375 if (name == NULL) return NULL;
1376 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1378 server = strdupW(&name[2]); /* skip over both backslash */
1379 if (server == NULL) return NULL;
1381 /* strip '\' and the printername */
1382 ptr = strchrW(server, '\\');
1383 if (ptr) ptr[0] = '\0';
1385 TRACE("found %s\n", debugstr_w(server));
1387 len = sizeof(buffer)/sizeof(buffer[0]);
1388 if (GetComputerNameW(buffer, &len)) {
1389 if (lstrcmpW(buffer, server) == 0) {
1390 /* The requested Servername is our computername */
1391 HeapFree(GetProcessHeap(), 0, server);
1392 return NULL;
1395 return server;
1398 /******************************************************************
1399 * get_basename_from_name (internal)
1401 * skip over the serverpart from the full name
1404 static LPCWSTR get_basename_from_name(LPCWSTR name)
1406 if (name == NULL) return NULL;
1407 if ((name[0] == '\\') && (name[1] == '\\')) {
1408 /* skip over the servername and search for the following '\' */
1409 name = strchrW(&name[2], '\\');
1410 if ((name) && (name[1])) {
1411 /* found a separator ('\') followed by a name:
1412 skip over the separator and return the rest */
1413 name++;
1415 else
1417 /* no basename present (we found only a servername) */
1418 return NULL;
1421 return name;
1424 static void free_printer_entry( opened_printer_t *printer )
1426 /* the queue is shared, so don't free that here */
1427 HeapFree( GetProcessHeap(), 0, printer->printername );
1428 HeapFree( GetProcessHeap(), 0, printer->name );
1429 HeapFree( GetProcessHeap(), 0, printer->devmode );
1430 HeapFree( GetProcessHeap(), 0, printer );
1433 /******************************************************************
1434 * get_opened_printer_entry
1435 * Get the first place empty in the opened printer table
1437 * ToDo:
1438 * - pDefault is ignored
1440 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1442 UINT_PTR handle = nb_printer_handles, i;
1443 jobqueue_t *queue = NULL;
1444 opened_printer_t *printer = NULL;
1445 LPWSTR servername;
1446 LPCWSTR printername;
1448 if ((backend == NULL) && !load_backend()) return NULL;
1450 servername = get_servername_from_name(name);
1451 if (servername) {
1452 FIXME("server %s not supported\n", debugstr_w(servername));
1453 HeapFree(GetProcessHeap(), 0, servername);
1454 SetLastError(ERROR_INVALID_PRINTER_NAME);
1455 return NULL;
1458 printername = get_basename_from_name(name);
1459 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1461 /* an empty printername is invalid */
1462 if (printername && (!printername[0])) {
1463 SetLastError(ERROR_INVALID_PARAMETER);
1464 return NULL;
1467 EnterCriticalSection(&printer_handles_cs);
1469 for (i = 0; i < nb_printer_handles; i++)
1471 if (!printer_handles[i])
1473 if(handle == nb_printer_handles)
1474 handle = i;
1476 else
1478 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1479 queue = printer_handles[i]->queue;
1483 if (handle >= nb_printer_handles)
1485 opened_printer_t **new_array;
1486 if (printer_handles)
1487 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1488 (nb_printer_handles + 16) * sizeof(*new_array) );
1489 else
1490 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1491 (nb_printer_handles + 16) * sizeof(*new_array) );
1493 if (!new_array)
1495 handle = 0;
1496 goto end;
1498 printer_handles = new_array;
1499 nb_printer_handles += 16;
1502 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1504 handle = 0;
1505 goto end;
1508 /* get a printer handle from the backend */
1509 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1510 handle = 0;
1511 goto end;
1514 /* clone the base name. This is NULL for the printserver */
1515 printer->printername = strdupW(printername);
1517 /* clone the full name */
1518 printer->name = strdupW(name);
1519 if (name && (!printer->name)) {
1520 handle = 0;
1521 goto end;
1524 if (pDefault && pDefault->pDevMode)
1525 printer->devmode = dup_devmode( pDefault->pDevMode );
1527 if(queue)
1528 printer->queue = queue;
1529 else
1531 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1532 if (!printer->queue) {
1533 handle = 0;
1534 goto end;
1536 list_init(&printer->queue->jobs);
1537 printer->queue->ref = 0;
1539 InterlockedIncrement(&printer->queue->ref);
1541 printer_handles[handle] = printer;
1542 handle++;
1543 end:
1544 LeaveCriticalSection(&printer_handles_cs);
1545 if (!handle && printer) {
1546 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1547 free_printer_entry( printer );
1550 return (HANDLE)handle;
1553 static void old_printer_check( BOOL delete_phase )
1555 PRINTER_INFO_5W* pi;
1556 DWORD needed, type, num, delete, i, size;
1557 const DWORD one = 1;
1558 HKEY key;
1559 HANDLE hprn;
1561 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1562 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1564 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1565 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1566 for (i = 0; i < num; i++)
1568 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1569 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1570 continue;
1572 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1574 if (!delete_phase)
1576 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1577 RegCloseKey( key );
1579 else
1581 delete = 0;
1582 size = sizeof( delete );
1583 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1584 RegCloseKey( key );
1585 if (delete)
1587 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1588 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1590 DeletePrinter( hprn );
1591 ClosePrinter( hprn );
1593 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1597 HeapFree(GetProcessHeap(), 0, pi);
1600 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1601 'M','U','T','E','X','_','_','\0'};
1602 static HANDLE init_mutex;
1604 void WINSPOOL_LoadSystemPrinters(void)
1606 HKEY hkey, hkeyPrinters;
1607 DWORD needed, num, i;
1608 WCHAR PrinterName[256];
1609 BOOL done = FALSE;
1611 #ifdef SONAME_LIBCUPS
1612 load_cups();
1613 #endif
1615 /* FIXME: The init code should be moved to spoolsv.exe */
1616 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1617 if (!init_mutex)
1619 ERR( "Failed to create mutex\n" );
1620 return;
1622 if (GetLastError() == ERROR_ALREADY_EXISTS)
1624 WaitForSingleObject( init_mutex, INFINITE );
1625 ReleaseMutex( init_mutex );
1626 TRACE( "Init already done\n" );
1627 return;
1630 /* This ensures that all printer entries have a valid Name value. If causes
1631 problems later if they don't. If one is found to be missed we create one
1632 and set it equal to the name of the key */
1633 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1634 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1635 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1636 for(i = 0; i < num; i++) {
1637 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1638 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1639 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1640 set_reg_szW(hkey, NameW, PrinterName);
1642 RegCloseKey(hkey);
1647 RegCloseKey(hkeyPrinters);
1650 old_printer_check( FALSE );
1652 #ifdef SONAME_LIBCUPS
1653 done = CUPS_LoadPrinters();
1654 #endif
1656 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1657 PRINTCAP_LoadPrinters();
1659 old_printer_check( TRUE );
1661 ReleaseMutex( init_mutex );
1662 return;
1665 /******************************************************************
1666 * get_job
1668 * Get the pointer to the specified job.
1669 * Should hold the printer_handles_cs before calling.
1671 static job_t *get_job(HANDLE hprn, DWORD JobId)
1673 opened_printer_t *printer = get_opened_printer(hprn);
1674 job_t *job;
1676 if(!printer) return NULL;
1677 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1679 if(job->job_id == JobId)
1680 return job;
1682 return NULL;
1685 /***********************************************************
1686 * DEVMODEcpyAtoW
1688 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1690 BOOL Formname;
1691 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1692 DWORD size;
1694 Formname = (dmA->dmSize > off_formname);
1695 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1696 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1697 dmW->dmDeviceName, CCHDEVICENAME);
1698 if(!Formname) {
1699 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1700 dmA->dmSize - CCHDEVICENAME);
1701 } else {
1702 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1703 off_formname - CCHDEVICENAME);
1704 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1705 dmW->dmFormName, CCHFORMNAME);
1706 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1707 (off_formname + CCHFORMNAME));
1709 dmW->dmSize = size;
1710 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1711 dmA->dmDriverExtra);
1712 return dmW;
1715 /******************************************************************
1716 * convert_printerinfo_W_to_A [internal]
1719 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1720 DWORD level, DWORD outlen, DWORD numentries)
1722 DWORD id = 0;
1723 LPSTR ptr;
1724 INT len;
1726 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1728 len = pi_sizeof[level] * numentries;
1729 ptr = (LPSTR) out + len;
1730 outlen -= len;
1732 /* copy the numbers of all PRINTER_INFO_* first */
1733 memcpy(out, pPrintersW, len);
1735 while (id < numentries) {
1736 switch (level) {
1737 case 1:
1739 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1740 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1742 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1743 if (piW->pDescription) {
1744 piA->pDescription = ptr;
1745 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1746 ptr, outlen, NULL, NULL);
1747 ptr += len;
1748 outlen -= len;
1750 if (piW->pName) {
1751 piA->pName = ptr;
1752 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1753 ptr, outlen, NULL, NULL);
1754 ptr += len;
1755 outlen -= len;
1757 if (piW->pComment) {
1758 piA->pComment = ptr;
1759 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1760 ptr, outlen, NULL, NULL);
1761 ptr += len;
1762 outlen -= len;
1764 break;
1767 case 2:
1769 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1770 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1771 LPDEVMODEA dmA;
1773 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1774 if (piW->pServerName) {
1775 piA->pServerName = ptr;
1776 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1777 ptr, outlen, NULL, NULL);
1778 ptr += len;
1779 outlen -= len;
1781 if (piW->pPrinterName) {
1782 piA->pPrinterName = ptr;
1783 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1784 ptr, outlen, NULL, NULL);
1785 ptr += len;
1786 outlen -= len;
1788 if (piW->pShareName) {
1789 piA->pShareName = ptr;
1790 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1791 ptr, outlen, NULL, NULL);
1792 ptr += len;
1793 outlen -= len;
1795 if (piW->pPortName) {
1796 piA->pPortName = ptr;
1797 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1798 ptr, outlen, NULL, NULL);
1799 ptr += len;
1800 outlen -= len;
1802 if (piW->pDriverName) {
1803 piA->pDriverName = ptr;
1804 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1805 ptr, outlen, NULL, NULL);
1806 ptr += len;
1807 outlen -= len;
1809 if (piW->pComment) {
1810 piA->pComment = ptr;
1811 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1812 ptr, outlen, NULL, NULL);
1813 ptr += len;
1814 outlen -= len;
1816 if (piW->pLocation) {
1817 piA->pLocation = ptr;
1818 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1819 ptr, outlen, NULL, NULL);
1820 ptr += len;
1821 outlen -= len;
1824 dmA = DEVMODEdupWtoA(piW->pDevMode);
1825 if (dmA) {
1826 /* align DEVMODEA to a DWORD boundary */
1827 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1828 ptr += len;
1829 outlen -= len;
1831 piA->pDevMode = (LPDEVMODEA) ptr;
1832 len = dmA->dmSize + dmA->dmDriverExtra;
1833 memcpy(ptr, dmA, len);
1834 HeapFree(GetProcessHeap(), 0, dmA);
1836 ptr += len;
1837 outlen -= len;
1840 if (piW->pSepFile) {
1841 piA->pSepFile = ptr;
1842 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1843 ptr, outlen, NULL, NULL);
1844 ptr += len;
1845 outlen -= len;
1847 if (piW->pPrintProcessor) {
1848 piA->pPrintProcessor = ptr;
1849 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1850 ptr, outlen, NULL, NULL);
1851 ptr += len;
1852 outlen -= len;
1854 if (piW->pDatatype) {
1855 piA->pDatatype = ptr;
1856 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1857 ptr, outlen, NULL, NULL);
1858 ptr += len;
1859 outlen -= len;
1861 if (piW->pParameters) {
1862 piA->pParameters = ptr;
1863 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1864 ptr, outlen, NULL, NULL);
1865 ptr += len;
1866 outlen -= len;
1868 if (piW->pSecurityDescriptor) {
1869 piA->pSecurityDescriptor = NULL;
1870 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1872 break;
1875 case 4:
1877 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1878 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1880 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1882 if (piW->pPrinterName) {
1883 piA->pPrinterName = ptr;
1884 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1885 ptr, outlen, NULL, NULL);
1886 ptr += len;
1887 outlen -= len;
1889 if (piW->pServerName) {
1890 piA->pServerName = ptr;
1891 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1892 ptr, outlen, NULL, NULL);
1893 ptr += len;
1894 outlen -= len;
1896 break;
1899 case 5:
1901 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1902 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1904 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1906 if (piW->pPrinterName) {
1907 piA->pPrinterName = ptr;
1908 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1909 ptr, outlen, NULL, NULL);
1910 ptr += len;
1911 outlen -= len;
1913 if (piW->pPortName) {
1914 piA->pPortName = ptr;
1915 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1916 ptr, outlen, NULL, NULL);
1917 ptr += len;
1918 outlen -= len;
1920 break;
1923 case 6: /* 6A and 6W are the same structure */
1924 break;
1926 case 7:
1928 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1929 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1931 TRACE("(%u) #%u\n", level, id);
1932 if (piW->pszObjectGUID) {
1933 piA->pszObjectGUID = ptr;
1934 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1935 ptr, outlen, NULL, NULL);
1936 ptr += len;
1937 outlen -= len;
1939 break;
1942 case 8:
1943 case 9:
1945 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1946 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1947 LPDEVMODEA dmA;
1949 TRACE("(%u) #%u\n", level, id);
1950 dmA = DEVMODEdupWtoA(piW->pDevMode);
1951 if (dmA) {
1952 /* align DEVMODEA to a DWORD boundary */
1953 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1954 ptr += len;
1955 outlen -= len;
1957 piA->pDevMode = (LPDEVMODEA) ptr;
1958 len = dmA->dmSize + dmA->dmDriverExtra;
1959 memcpy(ptr, dmA, len);
1960 HeapFree(GetProcessHeap(), 0, dmA);
1962 ptr += len;
1963 outlen -= len;
1966 break;
1969 default:
1970 FIXME("for level %u\n", level);
1972 pPrintersW += pi_sizeof[level];
1973 out += pi_sizeof[level];
1974 id++;
1978 /******************************************************************
1979 * convert_driverinfo_W_to_A [internal]
1982 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1983 DWORD level, DWORD outlen, DWORD numentries)
1985 DWORD id = 0;
1986 LPSTR ptr;
1987 INT len;
1989 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1991 len = di_sizeof[level] * numentries;
1992 ptr = (LPSTR) out + len;
1993 outlen -= len;
1995 /* copy the numbers of all PRINTER_INFO_* first */
1996 memcpy(out, pDriversW, len);
1998 #define COPY_STRING(fld) \
1999 { if (diW->fld){ \
2000 diA->fld = ptr; \
2001 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
2002 ptr += len; outlen -= len;\
2004 #define COPY_MULTIZ_STRING(fld) \
2005 { LPWSTR p = diW->fld; if (p){ \
2006 diA->fld = ptr; \
2007 do {\
2008 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2009 ptr += len; outlen -= len; p += len;\
2011 while(len > 1 && outlen > 0); \
2014 while (id < numentries)
2016 switch (level)
2018 case 1:
2020 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
2021 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
2023 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2025 COPY_STRING(pName);
2026 break;
2028 case 2:
2030 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2031 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2033 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2035 COPY_STRING(pName);
2036 COPY_STRING(pEnvironment);
2037 COPY_STRING(pDriverPath);
2038 COPY_STRING(pDataFile);
2039 COPY_STRING(pConfigFile);
2040 break;
2042 case 3:
2044 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2045 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2047 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2049 COPY_STRING(pName);
2050 COPY_STRING(pEnvironment);
2051 COPY_STRING(pDriverPath);
2052 COPY_STRING(pDataFile);
2053 COPY_STRING(pConfigFile);
2054 COPY_STRING(pHelpFile);
2055 COPY_MULTIZ_STRING(pDependentFiles);
2056 COPY_STRING(pMonitorName);
2057 COPY_STRING(pDefaultDataType);
2058 break;
2060 case 4:
2062 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2063 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2065 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2067 COPY_STRING(pName);
2068 COPY_STRING(pEnvironment);
2069 COPY_STRING(pDriverPath);
2070 COPY_STRING(pDataFile);
2071 COPY_STRING(pConfigFile);
2072 COPY_STRING(pHelpFile);
2073 COPY_MULTIZ_STRING(pDependentFiles);
2074 COPY_STRING(pMonitorName);
2075 COPY_STRING(pDefaultDataType);
2076 COPY_MULTIZ_STRING(pszzPreviousNames);
2077 break;
2079 case 5:
2081 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2082 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2084 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2086 COPY_STRING(pName);
2087 COPY_STRING(pEnvironment);
2088 COPY_STRING(pDriverPath);
2089 COPY_STRING(pDataFile);
2090 COPY_STRING(pConfigFile);
2091 break;
2093 case 6:
2095 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2096 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2098 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2100 COPY_STRING(pName);
2101 COPY_STRING(pEnvironment);
2102 COPY_STRING(pDriverPath);
2103 COPY_STRING(pDataFile);
2104 COPY_STRING(pConfigFile);
2105 COPY_STRING(pHelpFile);
2106 COPY_MULTIZ_STRING(pDependentFiles);
2107 COPY_STRING(pMonitorName);
2108 COPY_STRING(pDefaultDataType);
2109 COPY_MULTIZ_STRING(pszzPreviousNames);
2110 COPY_STRING(pszMfgName);
2111 COPY_STRING(pszOEMUrl);
2112 COPY_STRING(pszHardwareID);
2113 COPY_STRING(pszProvider);
2114 break;
2116 case 8:
2118 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2119 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2121 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2123 COPY_STRING(pName);
2124 COPY_STRING(pEnvironment);
2125 COPY_STRING(pDriverPath);
2126 COPY_STRING(pDataFile);
2127 COPY_STRING(pConfigFile);
2128 COPY_STRING(pHelpFile);
2129 COPY_MULTIZ_STRING(pDependentFiles);
2130 COPY_STRING(pMonitorName);
2131 COPY_STRING(pDefaultDataType);
2132 COPY_MULTIZ_STRING(pszzPreviousNames);
2133 COPY_STRING(pszMfgName);
2134 COPY_STRING(pszOEMUrl);
2135 COPY_STRING(pszHardwareID);
2136 COPY_STRING(pszProvider);
2137 COPY_STRING(pszPrintProcessor);
2138 COPY_STRING(pszVendorSetup);
2139 COPY_MULTIZ_STRING(pszzColorProfiles);
2140 COPY_STRING(pszInfPath);
2141 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2142 break;
2146 default:
2147 FIXME("for level %u\n", level);
2150 pDriversW += di_sizeof[level];
2151 out += di_sizeof[level];
2152 id++;
2155 #undef COPY_STRING
2156 #undef COPY_MULTIZ_STRING
2160 /***********************************************************
2161 * printer_info_AtoW
2163 static void *printer_info_AtoW( const void *data, DWORD level )
2165 void *ret;
2166 UNICODE_STRING usBuffer;
2168 if (!data) return NULL;
2170 if (level < 1 || level > 9) return NULL;
2172 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2173 if (!ret) return NULL;
2175 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2177 switch (level)
2179 case 2:
2181 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2182 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2184 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2185 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2186 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2187 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2188 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2189 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2190 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2191 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2192 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2193 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2194 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2195 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2196 break;
2199 case 8:
2200 case 9:
2202 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2203 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2205 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2206 break;
2209 default:
2210 FIXME( "Unhandled level %d\n", level );
2211 HeapFree( GetProcessHeap(), 0, ret );
2212 return NULL;
2215 return ret;
2218 /***********************************************************
2219 * free_printer_info
2221 static void free_printer_info( void *data, DWORD level )
2223 if (!data) return;
2225 switch (level)
2227 case 2:
2229 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2231 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2232 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2233 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2234 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2235 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2236 HeapFree( GetProcessHeap(), 0, piW->pComment );
2237 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2238 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2239 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2240 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2241 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2242 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2243 break;
2246 case 8:
2247 case 9:
2249 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2251 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2252 break;
2255 default:
2256 FIXME( "Unhandled level %d\n", level );
2259 HeapFree( GetProcessHeap(), 0, data );
2260 return;
2263 /******************************************************************
2264 * DeviceCapabilities [WINSPOOL.@]
2265 * DeviceCapabilitiesA [WINSPOOL.@]
2268 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2269 LPSTR pOutput, LPDEVMODEA lpdm)
2271 INT ret;
2273 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice), debugstr_a(pPort), cap, pOutput, lpdm);
2275 if (!GDI_CallDeviceCapabilities16)
2277 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2278 (LPCSTR)104 );
2279 if (!GDI_CallDeviceCapabilities16) return -1;
2281 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2283 /* If DC_PAPERSIZE map POINT16s to POINTs */
2284 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2285 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2286 POINT *pt = (POINT *)pOutput;
2287 INT i;
2288 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2289 for(i = 0; i < ret; i++, pt++)
2291 pt->x = tmp[i].x;
2292 pt->y = tmp[i].y;
2294 HeapFree( GetProcessHeap(), 0, tmp );
2296 return ret;
2300 /*****************************************************************************
2301 * DeviceCapabilitiesW [WINSPOOL.@]
2303 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2306 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2307 WORD fwCapability, LPWSTR pOutput,
2308 const DEVMODEW *pDevMode)
2310 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2311 LPSTR pDeviceA = strdupWtoA(pDevice);
2312 LPSTR pPortA = strdupWtoA(pPort);
2313 INT ret;
2315 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability, pOutput, pDevMode);
2317 if(pOutput && (fwCapability == DC_BINNAMES ||
2318 fwCapability == DC_FILEDEPENDENCIES ||
2319 fwCapability == DC_PAPERNAMES)) {
2320 /* These need A -> W translation */
2321 INT size = 0, i;
2322 LPSTR pOutputA;
2323 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2324 dmA);
2325 if(ret == -1)
2326 return ret;
2327 switch(fwCapability) {
2328 case DC_BINNAMES:
2329 size = 24;
2330 break;
2331 case DC_PAPERNAMES:
2332 case DC_FILEDEPENDENCIES:
2333 size = 64;
2334 break;
2336 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2337 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2338 dmA);
2339 for(i = 0; i < ret; i++)
2340 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2341 pOutput + (i * size), size);
2342 HeapFree(GetProcessHeap(), 0, pOutputA);
2343 } else {
2344 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2345 (LPSTR)pOutput, dmA);
2347 HeapFree(GetProcessHeap(),0,pPortA);
2348 HeapFree(GetProcessHeap(),0,pDeviceA);
2349 HeapFree(GetProcessHeap(),0,dmA);
2350 return ret;
2353 /******************************************************************
2354 * DocumentPropertiesA [WINSPOOL.@]
2356 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2358 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2359 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2360 LPDEVMODEA pDevModeInput,DWORD fMode )
2362 LPSTR lpName = pDeviceName, dupname = NULL;
2363 static CHAR port[] = "LPT1:";
2364 LONG ret;
2366 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2367 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2370 if(!pDeviceName || !*pDeviceName) {
2371 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2372 if(!lpNameW) {
2373 ERR("no name from hPrinter?\n");
2374 SetLastError(ERROR_INVALID_HANDLE);
2375 return -1;
2377 lpName = dupname = strdupWtoA(lpNameW);
2380 if (!GDI_CallExtDeviceMode16)
2382 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2383 (LPCSTR)102 );
2384 if (!GDI_CallExtDeviceMode16) {
2385 ERR("No CallExtDeviceMode16?\n");
2386 ret = -1;
2387 goto end;
2390 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2391 pDevModeInput, NULL, fMode);
2393 end:
2394 HeapFree(GetProcessHeap(), 0, dupname);
2395 return ret;
2399 /*****************************************************************************
2400 * DocumentPropertiesW (WINSPOOL.@)
2402 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2404 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2405 LPWSTR pDeviceName,
2406 LPDEVMODEW pDevModeOutput,
2407 LPDEVMODEW pDevModeInput, DWORD fMode)
2410 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2411 LPDEVMODEA pDevModeInputA;
2412 LPDEVMODEA pDevModeOutputA = NULL;
2413 LONG ret;
2415 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2416 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2417 fMode);
2418 if(pDevModeOutput) {
2419 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2420 if(ret < 0) return ret;
2421 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2423 pDevModeInputA = (fMode & DM_IN_BUFFER) ? DEVMODEdupWtoA(pDevModeInput) : NULL;
2424 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2425 pDevModeInputA, fMode);
2426 if(pDevModeOutput) {
2427 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2428 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2430 if(fMode == 0 && ret > 0)
2431 ret += (CCHDEVICENAME + CCHFORMNAME);
2432 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2433 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2434 return ret;
2437 /*****************************************************************************
2438 * IsValidDevmodeA [WINSPOOL.@]
2440 * Validate a DEVMODE structure and fix errors if possible.
2443 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2445 FIXME("(%p,%ld): stub\n", pDevMode, size);
2447 if(!pDevMode)
2448 return FALSE;
2450 return TRUE;
2453 /*****************************************************************************
2454 * IsValidDevmodeW [WINSPOOL.@]
2456 * Validate a DEVMODE structure and fix errors if possible.
2459 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2461 FIXME("(%p,%ld): stub\n", pDevMode, size);
2463 if(!pDevMode)
2464 return FALSE;
2466 return TRUE;
2469 /******************************************************************
2470 * OpenPrinterA [WINSPOOL.@]
2472 * See OpenPrinterW.
2475 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2476 LPPRINTER_DEFAULTSA pDefault)
2478 UNICODE_STRING lpPrinterNameW;
2479 UNICODE_STRING usBuffer;
2480 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2481 PWSTR pwstrPrinterNameW;
2482 BOOL ret;
2484 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName), phPrinter, pDefault);
2486 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2488 if(pDefault) {
2489 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2490 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2491 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2492 pDefaultW = &DefaultW;
2494 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2495 if(pDefault) {
2496 RtlFreeUnicodeString(&usBuffer);
2497 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2499 RtlFreeUnicodeString(&lpPrinterNameW);
2500 return ret;
2503 /******************************************************************
2504 * OpenPrinterW [WINSPOOL.@]
2506 * Open a Printer / Printserver or a Printer-Object
2508 * PARAMS
2509 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2510 * phPrinter [O] The resulting Handle is stored here
2511 * pDefault [I] PTR to Default Printer Settings or NULL
2513 * RETURNS
2514 * Success: TRUE
2515 * Failure: FALSE
2517 * NOTES
2518 * lpPrinterName is one of:
2519 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2520 *| Printer: "PrinterName"
2521 *| Printer-Object: "PrinterName,Job xxx"
2522 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2523 *| XcvPort: "Servername,XcvPort PortName"
2525 * BUGS
2526 *| Printer-Object not supported
2527 *| pDefaults is ignored
2530 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2532 HKEY key;
2534 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2536 if(!phPrinter) {
2537 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2538 SetLastError(ERROR_INVALID_PARAMETER);
2539 return FALSE;
2542 /* Get the unique handle of the printer or Printserver */
2543 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2545 if (*phPrinter && WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key ) == ERROR_SUCCESS)
2547 DWORD deleting = 0, size = sizeof( deleting ), type;
2548 DWORD status;
2549 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2550 WaitForSingleObject( init_mutex, INFINITE );
2551 status = get_dword_from_reg( key, StatusW );
2552 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2553 ReleaseMutex( init_mutex );
2554 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2555 update_driver( *phPrinter );
2556 RegCloseKey( key );
2559 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2560 return (*phPrinter != 0);
2563 /******************************************************************
2564 * AddMonitorA [WINSPOOL.@]
2566 * See AddMonitorW.
2569 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2571 LPWSTR nameW = NULL;
2572 INT len;
2573 BOOL res;
2574 LPMONITOR_INFO_2A mi2a;
2575 MONITOR_INFO_2W mi2w;
2577 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2578 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2579 debugstr_a(mi2a ? mi2a->pName : NULL),
2580 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2581 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2583 if (Level != 2) {
2584 SetLastError(ERROR_INVALID_LEVEL);
2585 return FALSE;
2588 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2589 if (mi2a == NULL) {
2590 return FALSE;
2593 if (pName) {
2594 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2595 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2596 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2599 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2600 if (mi2a->pName) {
2601 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2602 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2603 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2605 if (mi2a->pEnvironment) {
2606 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2607 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2608 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2610 if (mi2a->pDLLName) {
2611 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2612 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2613 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2616 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2618 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2619 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2620 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2622 HeapFree(GetProcessHeap(), 0, nameW);
2623 return (res);
2626 /******************************************************************************
2627 * AddMonitorW [WINSPOOL.@]
2629 * Install a Printmonitor
2631 * PARAMS
2632 * pName [I] Servername or NULL (local Computer)
2633 * Level [I] Structure-Level (Must be 2)
2634 * pMonitors [I] PTR to MONITOR_INFO_2
2636 * RETURNS
2637 * Success: TRUE
2638 * Failure: FALSE
2640 * NOTES
2641 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2644 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2646 LPMONITOR_INFO_2W mi2w;
2648 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2649 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2650 debugstr_w(mi2w ? mi2w->pName : NULL),
2651 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2652 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2654 if ((backend == NULL) && !load_backend()) return FALSE;
2656 if (Level != 2) {
2657 SetLastError(ERROR_INVALID_LEVEL);
2658 return FALSE;
2661 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2662 if (mi2w == NULL) {
2663 return FALSE;
2666 return backend->fpAddMonitor(pName, Level, pMonitors);
2669 /******************************************************************
2670 * DeletePrinterDriverA [WINSPOOL.@]
2673 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2675 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2678 /******************************************************************
2679 * DeletePrinterDriverW [WINSPOOL.@]
2682 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2684 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2687 /******************************************************************
2688 * DeleteMonitorA [WINSPOOL.@]
2690 * See DeleteMonitorW.
2693 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2695 LPWSTR nameW = NULL;
2696 LPWSTR EnvironmentW = NULL;
2697 LPWSTR MonitorNameW = NULL;
2698 BOOL res;
2699 INT len;
2701 if (pName) {
2702 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2703 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2704 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2707 if (pEnvironment) {
2708 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2709 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2710 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2712 if (pMonitorName) {
2713 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2714 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2715 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2718 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2720 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2721 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2722 HeapFree(GetProcessHeap(), 0, nameW);
2723 return (res);
2726 /******************************************************************
2727 * DeleteMonitorW [WINSPOOL.@]
2729 * Delete a specific Printmonitor from a Printing-Environment
2731 * PARAMS
2732 * pName [I] Servername or NULL (local Computer)
2733 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2734 * pMonitorName [I] Name of the Monitor, that should be deleted
2736 * RETURNS
2737 * Success: TRUE
2738 * Failure: FALSE
2740 * NOTES
2741 * pEnvironment is ignored in Windows for the local Computer.
2744 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2747 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2748 debugstr_w(pMonitorName));
2750 if ((backend == NULL) && !load_backend()) return FALSE;
2752 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2756 /******************************************************************
2757 * DeletePortA [WINSPOOL.@]
2759 * See DeletePortW.
2762 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2764 LPWSTR nameW = NULL;
2765 LPWSTR portW = NULL;
2766 INT len;
2767 DWORD res;
2769 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2771 /* convert servername to unicode */
2772 if (pName) {
2773 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2774 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2775 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2778 /* convert portname to unicode */
2779 if (pPortName) {
2780 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2781 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2782 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2785 res = DeletePortW(nameW, hWnd, portW);
2786 HeapFree(GetProcessHeap(), 0, nameW);
2787 HeapFree(GetProcessHeap(), 0, portW);
2788 return res;
2791 /******************************************************************
2792 * DeletePortW [WINSPOOL.@]
2794 * Delete a specific Port
2796 * PARAMS
2797 * pName [I] Servername or NULL (local Computer)
2798 * hWnd [I] Handle to parent Window for the Dialog-Box
2799 * pPortName [I] Name of the Port, that should be deleted
2801 * RETURNS
2802 * Success: TRUE
2803 * Failure: FALSE
2806 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2808 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2810 if ((backend == NULL) && !load_backend()) return FALSE;
2812 if (!pPortName) {
2813 SetLastError(RPC_X_NULL_REF_POINTER);
2814 return FALSE;
2817 return backend->fpDeletePort(pName, hWnd, pPortName);
2820 /******************************************************************************
2821 * WritePrinter [WINSPOOL.@]
2823 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2825 opened_printer_t *printer;
2826 BOOL ret = FALSE;
2828 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2830 EnterCriticalSection(&printer_handles_cs);
2831 printer = get_opened_printer(hPrinter);
2832 if(!printer)
2834 SetLastError(ERROR_INVALID_HANDLE);
2835 goto end;
2838 if(!printer->doc)
2840 SetLastError(ERROR_SPL_NO_STARTDOC);
2841 goto end;
2844 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2845 end:
2846 LeaveCriticalSection(&printer_handles_cs);
2847 return ret;
2850 /*****************************************************************************
2851 * AddFormA [WINSPOOL.@]
2853 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2855 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2856 return TRUE;
2859 /*****************************************************************************
2860 * AddFormW [WINSPOOL.@]
2862 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2864 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2865 return TRUE;
2868 /*****************************************************************************
2869 * AddJobA [WINSPOOL.@]
2871 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2873 BOOL ret;
2874 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2875 DWORD needed;
2877 if(Level != 1) {
2878 SetLastError(ERROR_INVALID_LEVEL);
2879 return FALSE;
2882 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2884 if(ret) {
2885 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2886 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2887 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2888 if(*pcbNeeded > cbBuf) {
2889 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2890 ret = FALSE;
2891 } else {
2892 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2893 addjobA->JobId = addjobW->JobId;
2894 addjobA->Path = (char *)(addjobA + 1);
2895 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2898 return ret;
2901 /*****************************************************************************
2902 * AddJobW [WINSPOOL.@]
2904 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2906 opened_printer_t *printer;
2907 job_t *job;
2908 BOOL ret = FALSE;
2909 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2910 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2911 WCHAR path[MAX_PATH], filename[MAX_PATH];
2912 DWORD len;
2913 ADDJOB_INFO_1W *addjob;
2915 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2917 EnterCriticalSection(&printer_handles_cs);
2919 printer = get_opened_printer(hPrinter);
2921 if(!printer) {
2922 SetLastError(ERROR_INVALID_HANDLE);
2923 goto end;
2926 if(Level != 1) {
2927 SetLastError(ERROR_INVALID_LEVEL);
2928 goto end;
2931 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2932 if(!job)
2933 goto end;
2935 job->job_id = InterlockedIncrement(&next_job_id);
2937 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2938 if(path[len - 1] != '\\')
2939 path[len++] = '\\';
2940 memcpy(path + len, spool_path, sizeof(spool_path));
2941 sprintfW(filename, fmtW, path, job->job_id);
2943 len = strlenW(filename);
2944 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2945 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2946 job->portname = NULL;
2947 job->document_title = strdupW(default_doc_title);
2948 job->printer_name = strdupW(printer->name);
2949 job->devmode = dup_devmode( printer->devmode );
2950 list_add_tail(&printer->queue->jobs, &job->entry);
2952 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2953 if(*pcbNeeded <= cbBuf) {
2954 addjob = (ADDJOB_INFO_1W*)pData;
2955 addjob->JobId = job->job_id;
2956 addjob->Path = (WCHAR *)(addjob + 1);
2957 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2958 ret = TRUE;
2959 } else
2960 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2962 end:
2963 LeaveCriticalSection(&printer_handles_cs);
2964 return ret;
2967 /*****************************************************************************
2968 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2970 * Return the PATH for the Print-Processors
2972 * See GetPrintProcessorDirectoryW.
2976 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2977 DWORD level, LPBYTE Info,
2978 DWORD cbBuf, LPDWORD pcbNeeded)
2980 LPWSTR serverW = NULL;
2981 LPWSTR envW = NULL;
2982 BOOL ret;
2983 INT len;
2985 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2986 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2989 if (server) {
2990 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2991 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2992 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2995 if (env) {
2996 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2997 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2998 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
3001 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
3002 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
3004 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
3005 cbBuf, pcbNeeded);
3007 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
3008 cbBuf, NULL, NULL) > 0;
3011 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3012 HeapFree(GetProcessHeap(), 0, envW);
3013 HeapFree(GetProcessHeap(), 0, serverW);
3014 return ret;
3017 /*****************************************************************************
3018 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3020 * Return the PATH for the Print-Processors
3022 * PARAMS
3023 * server [I] Servername (NT only) or NULL (local Computer)
3024 * env [I] Printing-Environment (see below) or NULL (Default)
3025 * level [I] Structure-Level (must be 1)
3026 * Info [O] PTR to Buffer that receives the Result
3027 * cbBuf [I] Size of Buffer at "Info"
3028 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3029 * required for the Buffer at "Info"
3031 * RETURNS
3032 * Success: TRUE and in pcbNeeded the Bytes used in Info
3033 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3034 * if cbBuf is too small
3036 * Native Values returned in Info on Success:
3037 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3038 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3039 *| win9x(Windows 4.0): "%winsysdir%"
3041 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3043 * BUGS
3044 * Only NULL or "" is supported for server
3047 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3048 DWORD level, LPBYTE Info,
3049 DWORD cbBuf, LPDWORD pcbNeeded)
3052 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3053 Info, cbBuf, pcbNeeded);
3055 if ((backend == NULL) && !load_backend()) return FALSE;
3057 if (level != 1) {
3058 /* (Level != 1) is ignored in win9x */
3059 SetLastError(ERROR_INVALID_LEVEL);
3060 return FALSE;
3063 if (pcbNeeded == NULL) {
3064 /* (pcbNeeded == NULL) is ignored in win9x */
3065 SetLastError(RPC_X_NULL_REF_POINTER);
3066 return FALSE;
3069 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3072 /*****************************************************************************
3073 * WINSPOOL_OpenDriverReg [internal]
3075 * opens the registry for the printer drivers depending on the given input
3076 * variable pEnvironment
3078 * RETURNS:
3079 * the opened hkey on success
3080 * NULL on error
3082 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3084 HKEY retval = NULL;
3085 LPWSTR buffer;
3086 const printenv_t * env;
3088 TRACE("(%s)\n", debugstr_w(pEnvironment));
3090 env = validate_envW(pEnvironment);
3091 if (!env) return NULL;
3093 buffer = HeapAlloc( GetProcessHeap(), 0,
3094 (strlenW(DriversW) + strlenW(env->envname) +
3095 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3096 if(buffer) {
3097 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3098 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3099 HeapFree(GetProcessHeap(), 0, buffer);
3101 return retval;
3104 /*****************************************************************************
3105 * set_devices_and_printerports [internal]
3107 * set the [Devices] and [PrinterPorts] entries for a printer.
3110 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3112 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3113 WCHAR *devline;
3114 HKEY hkey;
3116 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3118 /* FIXME: the driver must change to "winspool" */
3119 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3120 if (devline) {
3121 lstrcpyW(devline, driver_nt);
3122 lstrcatW(devline, commaW);
3123 lstrcatW(devline, pi->pPortName);
3125 TRACE("using %s\n", debugstr_w(devline));
3126 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
3127 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3128 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3129 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3130 RegCloseKey(hkey);
3133 lstrcatW(devline, timeout_15_45);
3134 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
3135 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3136 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3137 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3138 RegCloseKey(hkey);
3140 HeapFree(GetProcessHeap(), 0, devline);
3144 /*****************************************************************************
3145 * AddPrinterW [WINSPOOL.@]
3147 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3149 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3150 LPDEVMODEW dm;
3151 HANDLE retval;
3152 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3153 LONG size;
3155 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3157 if(pName && *pName) {
3158 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3159 SetLastError(ERROR_INVALID_PARAMETER);
3160 return 0;
3162 if(Level != 2) {
3163 ERR("Level = %d, unsupported!\n", Level);
3164 SetLastError(ERROR_INVALID_LEVEL);
3165 return 0;
3167 if(!pPrinter) {
3168 SetLastError(ERROR_INVALID_PARAMETER);
3169 return 0;
3171 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3172 ERROR_SUCCESS) {
3173 ERR("Can't create Printers key\n");
3174 return 0;
3176 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3177 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3178 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3179 RegCloseKey(hkeyPrinter);
3180 RegCloseKey(hkeyPrinters);
3181 return 0;
3183 RegCloseKey(hkeyPrinter);
3185 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3186 if(!hkeyDrivers) {
3187 ERR("Can't create Drivers key\n");
3188 RegCloseKey(hkeyPrinters);
3189 return 0;
3191 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3192 ERROR_SUCCESS) {
3193 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3194 RegCloseKey(hkeyPrinters);
3195 RegCloseKey(hkeyDrivers);
3196 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3197 return 0;
3199 RegCloseKey(hkeyDriver);
3200 RegCloseKey(hkeyDrivers);
3202 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3203 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3204 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3205 RegCloseKey(hkeyPrinters);
3206 return 0;
3209 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3210 ERROR_SUCCESS) {
3211 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3212 SetLastError(ERROR_INVALID_PRINTER_NAME);
3213 RegCloseKey(hkeyPrinters);
3214 return 0;
3217 set_devices_and_printerports(pi);
3219 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3220 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3221 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3222 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3223 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3224 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3225 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3226 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3227 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3228 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3229 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3230 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3231 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3232 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3233 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3234 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3235 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3236 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3238 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3240 if (size < 0)
3242 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3243 size = sizeof(DEVMODEW);
3245 if(pi->pDevMode)
3246 dm = pi->pDevMode;
3247 else
3249 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3250 dm->dmSize = size;
3251 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3253 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3254 HeapFree( GetProcessHeap(), 0, dm );
3255 dm = NULL;
3257 else
3259 /* set devmode to printer name */
3260 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3264 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3265 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3267 RegCloseKey(hkeyPrinter);
3268 RegCloseKey(hkeyPrinters);
3269 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3270 ERR("OpenPrinter failing\n");
3271 return 0;
3273 return retval;
3276 /*****************************************************************************
3277 * AddPrinterA [WINSPOOL.@]
3279 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3281 UNICODE_STRING pNameW;
3282 PWSTR pwstrNameW;
3283 PRINTER_INFO_2W *piW;
3284 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3285 HANDLE ret;
3287 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3288 if(Level != 2) {
3289 ERR("Level = %d, unsupported!\n", Level);
3290 SetLastError(ERROR_INVALID_LEVEL);
3291 return 0;
3293 pwstrNameW = asciitounicode(&pNameW,pName);
3294 piW = printer_info_AtoW( piA, Level );
3296 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3298 free_printer_info( piW, Level );
3299 RtlFreeUnicodeString(&pNameW);
3300 return ret;
3304 /*****************************************************************************
3305 * ClosePrinter [WINSPOOL.@]
3307 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3309 UINT_PTR i = (UINT_PTR)hPrinter;
3310 opened_printer_t *printer = NULL;
3311 BOOL ret = FALSE;
3313 TRACE("(%p)\n", hPrinter);
3315 EnterCriticalSection(&printer_handles_cs);
3317 if ((i > 0) && (i <= nb_printer_handles))
3318 printer = printer_handles[i - 1];
3321 if(printer)
3323 struct list *cursor, *cursor2;
3325 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3327 if (printer->backend_printer) {
3328 backend->fpClosePrinter(printer->backend_printer);
3331 if(printer->doc)
3332 EndDocPrinter(hPrinter);
3334 if(InterlockedDecrement(&printer->queue->ref) == 0)
3336 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3338 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3339 ScheduleJob(hPrinter, job->job_id);
3341 HeapFree(GetProcessHeap(), 0, printer->queue);
3344 free_printer_entry( printer );
3345 printer_handles[i - 1] = NULL;
3346 ret = TRUE;
3348 LeaveCriticalSection(&printer_handles_cs);
3349 return ret;
3352 /*****************************************************************************
3353 * DeleteFormA [WINSPOOL.@]
3355 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3357 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3358 return TRUE;
3361 /*****************************************************************************
3362 * DeleteFormW [WINSPOOL.@]
3364 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3366 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3367 return TRUE;
3370 /*****************************************************************************
3371 * DeletePrinter [WINSPOOL.@]
3373 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3375 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3376 HKEY hkeyPrinters, hkey;
3377 WCHAR def[MAX_PATH];
3378 DWORD size = sizeof( def ) / sizeof( def[0] );
3380 if(!lpNameW) {
3381 SetLastError(ERROR_INVALID_HANDLE);
3382 return FALSE;
3384 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3385 RegDeleteTreeW(hkeyPrinters, lpNameW);
3386 RegCloseKey(hkeyPrinters);
3388 WriteProfileStringW(devicesW, lpNameW, NULL);
3389 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3391 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3392 RegDeleteValueW(hkey, lpNameW);
3393 RegCloseKey(hkey);
3396 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3397 RegDeleteValueW(hkey, lpNameW);
3398 RegCloseKey(hkey);
3401 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3403 WriteProfileStringW( windowsW, deviceW, NULL );
3404 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3406 RegDeleteValueW( hkey, deviceW );
3407 RegCloseKey( hkey );
3409 SetDefaultPrinterW( NULL );
3412 return TRUE;
3415 /*****************************************************************************
3416 * SetPrinterA [WINSPOOL.@]
3418 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3420 BYTE *dataW = data;
3421 BOOL ret;
3423 if (level != 0)
3425 dataW = printer_info_AtoW( data, level );
3426 if (!dataW) return FALSE;
3429 ret = SetPrinterW( printer, level, dataW, command );
3431 if (dataW != data) free_printer_info( dataW, level );
3433 return ret;
3436 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3438 set_reg_szW( key, NameW, pi->pPrinterName );
3439 set_reg_szW( key, Share_NameW, pi->pShareName );
3440 set_reg_szW( key, PortW, pi->pPortName );
3441 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3442 set_reg_szW( key, DescriptionW, pi->pComment );
3443 set_reg_szW( key, LocationW, pi->pLocation );
3445 if (pi->pDevMode)
3446 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3448 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3449 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3450 set_reg_szW( key, DatatypeW, pi->pDatatype );
3451 set_reg_szW( key, ParametersW, pi->pParameters );
3453 set_reg_DWORD( key, AttributesW, pi->Attributes );
3454 set_reg_DWORD( key, PriorityW, pi->Priority );
3455 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3456 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3457 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3460 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3462 if (!pi->pDevMode) return FALSE;
3464 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3465 return TRUE;
3468 /******************************************************************************
3469 * SetPrinterW [WINSPOOL.@]
3471 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3473 HKEY key;
3474 BOOL ret = FALSE;
3476 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3478 if (command != 0) FIXME( "Ignoring command %d\n", command );
3480 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3481 return FALSE;
3483 switch (level)
3485 case 2:
3487 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3488 set_printer_2( key, pi2 );
3489 ret = TRUE;
3490 break;
3493 case 8:
3494 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
3495 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3496 /* fall through */
3497 case 9:
3499 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3500 ret = set_printer_9( key, pi );
3501 break;
3504 default:
3505 FIXME( "Unimplemented level %d\n", level );
3506 SetLastError( ERROR_INVALID_LEVEL );
3509 RegCloseKey( key );
3510 return ret;
3513 /*****************************************************************************
3514 * SetJobA [WINSPOOL.@]
3516 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3517 LPBYTE pJob, DWORD Command)
3519 BOOL ret;
3520 LPBYTE JobW;
3521 UNICODE_STRING usBuffer;
3523 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3525 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3526 are all ignored by SetJob, so we don't bother copying them */
3527 switch(Level)
3529 case 0:
3530 JobW = NULL;
3531 break;
3532 case 1:
3534 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3535 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3537 JobW = (LPBYTE)info1W;
3538 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3539 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3540 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3541 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3542 info1W->Status = info1A->Status;
3543 info1W->Priority = info1A->Priority;
3544 info1W->Position = info1A->Position;
3545 info1W->PagesPrinted = info1A->PagesPrinted;
3546 break;
3548 case 2:
3550 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3551 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3553 JobW = (LPBYTE)info2W;
3554 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3555 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3556 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3557 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3558 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3559 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3560 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3561 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3562 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3563 info2W->Status = info2A->Status;
3564 info2W->Priority = info2A->Priority;
3565 info2W->Position = info2A->Position;
3566 info2W->StartTime = info2A->StartTime;
3567 info2W->UntilTime = info2A->UntilTime;
3568 info2W->PagesPrinted = info2A->PagesPrinted;
3569 break;
3571 case 3:
3572 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3573 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3574 break;
3575 default:
3576 SetLastError(ERROR_INVALID_LEVEL);
3577 return FALSE;
3580 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3582 switch(Level)
3584 case 1:
3586 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3587 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3588 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3589 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3590 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3591 break;
3593 case 2:
3595 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3596 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3597 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3598 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3599 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3600 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3601 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3602 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3603 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3604 break;
3607 HeapFree(GetProcessHeap(), 0, JobW);
3609 return ret;
3612 /*****************************************************************************
3613 * SetJobW [WINSPOOL.@]
3615 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3616 LPBYTE pJob, DWORD Command)
3618 BOOL ret = FALSE;
3619 job_t *job;
3621 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3622 FIXME("Ignoring everything other than document title\n");
3624 EnterCriticalSection(&printer_handles_cs);
3625 job = get_job(hPrinter, JobId);
3626 if(!job)
3627 goto end;
3629 switch(Level)
3631 case 0:
3632 break;
3633 case 1:
3635 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3636 HeapFree(GetProcessHeap(), 0, job->document_title);
3637 job->document_title = strdupW(info1->pDocument);
3638 break;
3640 case 2:
3642 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3643 HeapFree(GetProcessHeap(), 0, job->document_title);
3644 job->document_title = strdupW(info2->pDocument);
3645 HeapFree(GetProcessHeap(), 0, job->devmode);
3646 job->devmode = dup_devmode( info2->pDevMode );
3647 break;
3649 case 3:
3650 break;
3651 default:
3652 SetLastError(ERROR_INVALID_LEVEL);
3653 goto end;
3655 ret = TRUE;
3656 end:
3657 LeaveCriticalSection(&printer_handles_cs);
3658 return ret;
3661 /*****************************************************************************
3662 * EndDocPrinter [WINSPOOL.@]
3664 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3666 opened_printer_t *printer;
3667 BOOL ret = FALSE;
3668 TRACE("(%p)\n", hPrinter);
3670 EnterCriticalSection(&printer_handles_cs);
3672 printer = get_opened_printer(hPrinter);
3673 if(!printer)
3675 SetLastError(ERROR_INVALID_HANDLE);
3676 goto end;
3679 if(!printer->doc)
3681 SetLastError(ERROR_SPL_NO_STARTDOC);
3682 goto end;
3685 CloseHandle(printer->doc->hf);
3686 ScheduleJob(hPrinter, printer->doc->job_id);
3687 HeapFree(GetProcessHeap(), 0, printer->doc);
3688 printer->doc = NULL;
3689 ret = TRUE;
3690 end:
3691 LeaveCriticalSection(&printer_handles_cs);
3692 return ret;
3695 /*****************************************************************************
3696 * EndPagePrinter [WINSPOOL.@]
3698 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3700 FIXME("(%p): stub\n", hPrinter);
3701 return TRUE;
3704 /*****************************************************************************
3705 * StartDocPrinterA [WINSPOOL.@]
3707 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3709 UNICODE_STRING usBuffer;
3710 DOC_INFO_2W doc2W;
3711 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3712 DWORD ret;
3714 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3715 or one (DOC_INFO_3) extra DWORDs */
3717 switch(Level) {
3718 case 2:
3719 doc2W.JobId = doc2->JobId;
3720 /* fall through */
3721 case 3:
3722 doc2W.dwMode = doc2->dwMode;
3723 /* fall through */
3724 case 1:
3725 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3726 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3727 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3728 break;
3730 default:
3731 SetLastError(ERROR_INVALID_LEVEL);
3732 return FALSE;
3735 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3737 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3738 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3739 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3741 return ret;
3744 /*****************************************************************************
3745 * StartDocPrinterW [WINSPOOL.@]
3747 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3749 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3750 opened_printer_t *printer;
3751 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3752 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3753 JOB_INFO_1W job_info;
3754 DWORD needed, ret = 0;
3755 HANDLE hf;
3756 WCHAR *filename;
3757 job_t *job;
3759 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3760 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3761 debugstr_w(doc->pDatatype));
3763 if(Level < 1 || Level > 3)
3765 SetLastError(ERROR_INVALID_LEVEL);
3766 return 0;
3769 EnterCriticalSection(&printer_handles_cs);
3770 printer = get_opened_printer(hPrinter);
3771 if(!printer)
3773 SetLastError(ERROR_INVALID_HANDLE);
3774 goto end;
3777 if(printer->doc)
3779 SetLastError(ERROR_INVALID_PRINTER_STATE);
3780 goto end;
3783 /* Even if we're printing to a file we still add a print job, we'll
3784 just ignore the spool file name */
3786 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3788 ERR("AddJob failed gle %u\n", GetLastError());
3789 goto end;
3792 /* use pOutputFile only, when it is a real filename */
3793 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3794 filename = doc->pOutputFile;
3795 else
3796 filename = addjob->Path;
3798 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3799 if(hf == INVALID_HANDLE_VALUE)
3800 goto end;
3802 memset(&job_info, 0, sizeof(job_info));
3803 job_info.pDocument = doc->pDocName;
3804 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3806 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3807 printer->doc->hf = hf;
3808 ret = printer->doc->job_id = addjob->JobId;
3809 job = get_job(hPrinter, ret);
3810 job->portname = strdupW(doc->pOutputFile);
3812 end:
3813 LeaveCriticalSection(&printer_handles_cs);
3815 return ret;
3818 /*****************************************************************************
3819 * StartPagePrinter [WINSPOOL.@]
3821 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3823 FIXME("(%p): stub\n", hPrinter);
3824 return TRUE;
3827 /*****************************************************************************
3828 * GetFormA [WINSPOOL.@]
3830 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3831 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3833 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3834 Level,pForm,cbBuf,pcbNeeded);
3835 return FALSE;
3838 /*****************************************************************************
3839 * GetFormW [WINSPOOL.@]
3841 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3842 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3844 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3845 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3846 return FALSE;
3849 /*****************************************************************************
3850 * SetFormA [WINSPOOL.@]
3852 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3853 LPBYTE pForm)
3855 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3856 return FALSE;
3859 /*****************************************************************************
3860 * SetFormW [WINSPOOL.@]
3862 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3863 LPBYTE pForm)
3865 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3866 return FALSE;
3869 /*****************************************************************************
3870 * ReadPrinter [WINSPOOL.@]
3872 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3873 LPDWORD pNoBytesRead)
3875 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3876 return FALSE;
3879 /*****************************************************************************
3880 * ResetPrinterA [WINSPOOL.@]
3882 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3884 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3885 return FALSE;
3888 /*****************************************************************************
3889 * ResetPrinterW [WINSPOOL.@]
3891 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3893 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3894 return FALSE;
3897 /*****************************************************************************
3898 * get_filename_from_reg [internal]
3900 * Get ValueName from hkey storing result in out
3901 * when the Value in the registry has only a filename, use driverdir as prefix
3902 * outlen is space left in out
3903 * String is stored either as unicode or ascii
3907 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3908 LPBYTE out, DWORD outlen, LPDWORD needed)
3910 WCHAR filename[MAX_PATH];
3911 DWORD size;
3912 DWORD type;
3913 LONG ret;
3914 LPWSTR buffer = filename;
3915 LPWSTR ptr;
3917 *needed = 0;
3918 size = sizeof(filename);
3919 buffer[0] = '\0';
3920 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3921 if (ret == ERROR_MORE_DATA) {
3922 TRACE("need dynamic buffer: %u\n", size);
3923 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3924 if (!buffer) {
3925 /* No Memory is bad */
3926 return FALSE;
3928 buffer[0] = '\0';
3929 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3932 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3933 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3934 return FALSE;
3937 ptr = buffer;
3938 while (ptr) {
3939 /* do we have a full path ? */
3940 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3941 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3943 if (!ret) {
3944 /* we must build the full Path */
3945 *needed += dirlen;
3946 if ((out) && (outlen > dirlen)) {
3947 lstrcpyW((LPWSTR)out, driverdir);
3948 out += dirlen;
3949 outlen -= dirlen;
3951 else
3952 out = NULL;
3955 /* write the filename */
3956 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3957 if ((out) && (outlen >= size)) {
3958 lstrcpyW((LPWSTR)out, ptr);
3959 out += size;
3960 outlen -= size;
3962 else
3963 out = NULL;
3964 *needed += size;
3965 ptr += lstrlenW(ptr)+1;
3966 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3969 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3971 /* write the multisz-termination */
3972 if (type == REG_MULTI_SZ) {
3973 size = sizeof(WCHAR);
3975 *needed += size;
3976 if (out && (outlen >= size)) {
3977 memset (out, 0, size);
3980 return TRUE;
3983 /*****************************************************************************
3984 * WINSPOOL_GetStringFromReg
3986 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3987 * String is stored as unicode.
3989 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3990 DWORD buflen, DWORD *needed)
3992 DWORD sz = buflen, type;
3993 LONG ret;
3995 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3996 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3997 WARN("Got ret = %d\n", ret);
3998 *needed = 0;
3999 return FALSE;
4001 /* add space for terminating '\0' */
4002 sz += sizeof(WCHAR);
4003 *needed = sz;
4005 if (ptr)
4006 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
4008 return TRUE;
4011 /*****************************************************************************
4012 * WINSPOOL_GetDefaultDevMode
4014 * Get a default DevMode values for wineps.
4016 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr, DWORD buflen, DWORD *needed)
4018 static const WCHAR winepsW[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4020 if (buflen >= sizeof(DEVMODEW))
4022 DEVMODEW *dm = (DEVMODEW *)ptr;
4024 /* the driver will update registry with real values */
4025 memset(dm, 0, sizeof(*dm));
4026 dm->dmSize = sizeof(*dm);
4027 lstrcpyW(dm->dmDeviceName, winepsW);
4029 *needed = sizeof(DEVMODEW);
4032 /*****************************************************************************
4033 * WINSPOOL_GetDevModeFromReg
4035 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4036 * DevMode is stored either as unicode or ascii.
4038 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4039 LPBYTE ptr,
4040 DWORD buflen, DWORD *needed)
4042 DWORD sz = buflen, type;
4043 LONG ret;
4045 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4046 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4047 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4048 if (sz < sizeof(DEVMODEA))
4050 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4051 return FALSE;
4053 /* ensures that dmSize is not erratically bogus if registry is invalid */
4054 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4055 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4056 sz += (CCHDEVICENAME + CCHFORMNAME);
4057 if (ptr && (buflen >= sz)) {
4058 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4059 memcpy(ptr, dmW, sz);
4060 HeapFree(GetProcessHeap(),0,dmW);
4062 *needed = sz;
4063 return TRUE;
4066 /*********************************************************************
4067 * WINSPOOL_GetPrinter_1
4069 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4071 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4072 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4074 DWORD size, left = cbBuf;
4075 BOOL space = (cbBuf > 0);
4076 LPBYTE ptr = buf;
4078 *pcbNeeded = 0;
4080 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4081 if(space && size <= left) {
4082 pi1->pName = (LPWSTR)ptr;
4083 ptr += size;
4084 left -= size;
4085 } else
4086 space = FALSE;
4087 *pcbNeeded += size;
4090 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4091 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4092 if(space && size <= left) {
4093 pi1->pDescription = (LPWSTR)ptr;
4094 ptr += size;
4095 left -= size;
4096 } else
4097 space = FALSE;
4098 *pcbNeeded += size;
4101 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4102 if(space && size <= left) {
4103 pi1->pComment = (LPWSTR)ptr;
4104 ptr += size;
4105 left -= size;
4106 } else
4107 space = FALSE;
4108 *pcbNeeded += size;
4111 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4113 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4114 memset(pi1, 0, sizeof(*pi1));
4116 return space;
4118 /*********************************************************************
4119 * WINSPOOL_GetPrinter_2
4121 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4123 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4124 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4126 DWORD size, left = cbBuf;
4127 BOOL space = (cbBuf > 0);
4128 LPBYTE ptr = buf;
4130 *pcbNeeded = 0;
4132 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4133 if(space && size <= left) {
4134 pi2->pPrinterName = (LPWSTR)ptr;
4135 ptr += size;
4136 left -= size;
4137 } else
4138 space = FALSE;
4139 *pcbNeeded += size;
4141 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4142 if(space && size <= left) {
4143 pi2->pShareName = (LPWSTR)ptr;
4144 ptr += size;
4145 left -= size;
4146 } else
4147 space = FALSE;
4148 *pcbNeeded += size;
4150 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4151 if(space && size <= left) {
4152 pi2->pPortName = (LPWSTR)ptr;
4153 ptr += size;
4154 left -= size;
4155 } else
4156 space = FALSE;
4157 *pcbNeeded += size;
4159 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4160 if(space && size <= left) {
4161 pi2->pDriverName = (LPWSTR)ptr;
4162 ptr += size;
4163 left -= size;
4164 } else
4165 space = FALSE;
4166 *pcbNeeded += size;
4168 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4169 if(space && size <= left) {
4170 pi2->pComment = (LPWSTR)ptr;
4171 ptr += size;
4172 left -= size;
4173 } else
4174 space = FALSE;
4175 *pcbNeeded += size;
4177 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4178 if(space && size <= left) {
4179 pi2->pLocation = (LPWSTR)ptr;
4180 ptr += size;
4181 left -= size;
4182 } else
4183 space = FALSE;
4184 *pcbNeeded += size;
4186 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4187 if(space && size <= left) {
4188 pi2->pDevMode = (LPDEVMODEW)ptr;
4189 ptr += size;
4190 left -= size;
4191 } else
4192 space = FALSE;
4193 *pcbNeeded += size;
4195 else
4197 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4198 if(space && size <= left) {
4199 pi2->pDevMode = (LPDEVMODEW)ptr;
4200 ptr += size;
4201 left -= size;
4202 } else
4203 space = FALSE;
4204 *pcbNeeded += size;
4206 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4207 if(space && size <= left) {
4208 pi2->pSepFile = (LPWSTR)ptr;
4209 ptr += size;
4210 left -= size;
4211 } else
4212 space = FALSE;
4213 *pcbNeeded += size;
4215 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4216 if(space && size <= left) {
4217 pi2->pPrintProcessor = (LPWSTR)ptr;
4218 ptr += size;
4219 left -= size;
4220 } else
4221 space = FALSE;
4222 *pcbNeeded += size;
4224 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4225 if(space && size <= left) {
4226 pi2->pDatatype = (LPWSTR)ptr;
4227 ptr += size;
4228 left -= size;
4229 } else
4230 space = FALSE;
4231 *pcbNeeded += size;
4233 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4234 if(space && size <= left) {
4235 pi2->pParameters = (LPWSTR)ptr;
4236 ptr += size;
4237 left -= size;
4238 } else
4239 space = FALSE;
4240 *pcbNeeded += size;
4242 if(pi2) {
4243 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4244 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4245 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4246 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4247 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4250 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4251 memset(pi2, 0, sizeof(*pi2));
4253 return space;
4256 /*********************************************************************
4257 * WINSPOOL_GetPrinter_4
4259 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4261 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4262 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4264 DWORD size, left = cbBuf;
4265 BOOL space = (cbBuf > 0);
4266 LPBYTE ptr = buf;
4268 *pcbNeeded = 0;
4270 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4271 if(space && size <= left) {
4272 pi4->pPrinterName = (LPWSTR)ptr;
4273 ptr += size;
4274 left -= size;
4275 } else
4276 space = FALSE;
4277 *pcbNeeded += size;
4279 if(pi4) {
4280 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4283 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4284 memset(pi4, 0, sizeof(*pi4));
4286 return space;
4289 /*********************************************************************
4290 * WINSPOOL_GetPrinter_5
4292 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4294 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4295 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4297 DWORD size, left = cbBuf;
4298 BOOL space = (cbBuf > 0);
4299 LPBYTE ptr = buf;
4301 *pcbNeeded = 0;
4303 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4304 if(space && size <= left) {
4305 pi5->pPrinterName = (LPWSTR)ptr;
4306 ptr += size;
4307 left -= size;
4308 } else
4309 space = FALSE;
4310 *pcbNeeded += size;
4312 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4313 if(space && size <= left) {
4314 pi5->pPortName = (LPWSTR)ptr;
4315 ptr += size;
4316 left -= size;
4317 } else
4318 space = FALSE;
4319 *pcbNeeded += size;
4321 if(pi5) {
4322 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4323 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4324 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4327 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4328 memset(pi5, 0, sizeof(*pi5));
4330 return space;
4333 /*********************************************************************
4334 * WINSPOOL_GetPrinter_7
4336 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4338 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4339 DWORD cbBuf, LPDWORD pcbNeeded)
4341 DWORD size, left = cbBuf;
4342 BOOL space = (cbBuf > 0);
4343 LPBYTE ptr = buf;
4345 *pcbNeeded = 0;
4347 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4349 ptr = NULL;
4350 size = sizeof(pi7->pszObjectGUID);
4352 if (space && size <= left) {
4353 pi7->pszObjectGUID = (LPWSTR)ptr;
4354 ptr += size;
4355 left -= size;
4356 } else
4357 space = FALSE;
4358 *pcbNeeded += size;
4359 if (pi7) {
4360 /* We do not have a Directory Service */
4361 pi7->dwAction = DSPRINT_UNPUBLISH;
4364 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4365 memset(pi7, 0, sizeof(*pi7));
4367 return space;
4370 /*********************************************************************
4371 * WINSPOOL_GetPrinter_9
4373 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4375 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4376 DWORD cbBuf, LPDWORD pcbNeeded)
4378 DWORD size;
4379 BOOL space = (cbBuf > 0);
4381 *pcbNeeded = 0;
4383 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4384 if(space && size <= cbBuf) {
4385 pi9->pDevMode = (LPDEVMODEW)buf;
4386 } else
4387 space = FALSE;
4388 *pcbNeeded += size;
4390 else
4392 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4393 if(space && size <= cbBuf) {
4394 pi9->pDevMode = (LPDEVMODEW)buf;
4395 } else
4396 space = FALSE;
4397 *pcbNeeded += size;
4400 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4401 memset(pi9, 0, sizeof(*pi9));
4403 return space;
4406 /*****************************************************************************
4407 * GetPrinterW [WINSPOOL.@]
4409 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4410 DWORD cbBuf, LPDWORD pcbNeeded)
4412 DWORD size, needed = 0, err;
4413 LPBYTE ptr = NULL;
4414 HKEY hkeyPrinter;
4415 BOOL ret;
4417 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4419 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4420 if (err)
4422 SetLastError( err );
4423 return FALSE;
4426 switch(Level) {
4427 case 2:
4429 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4431 size = sizeof(PRINTER_INFO_2W);
4432 if(size <= cbBuf) {
4433 ptr = pPrinter + size;
4434 cbBuf -= size;
4435 memset(pPrinter, 0, size);
4436 } else {
4437 pi2 = NULL;
4438 cbBuf = 0;
4440 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4441 needed += size;
4442 break;
4445 case 4:
4447 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4449 size = sizeof(PRINTER_INFO_4W);
4450 if(size <= cbBuf) {
4451 ptr = pPrinter + size;
4452 cbBuf -= size;
4453 memset(pPrinter, 0, size);
4454 } else {
4455 pi4 = NULL;
4456 cbBuf = 0;
4458 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4459 needed += size;
4460 break;
4464 case 5:
4466 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4468 size = sizeof(PRINTER_INFO_5W);
4469 if(size <= cbBuf) {
4470 ptr = pPrinter + size;
4471 cbBuf -= size;
4472 memset(pPrinter, 0, size);
4473 } else {
4474 pi5 = NULL;
4475 cbBuf = 0;
4478 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4479 needed += size;
4480 break;
4484 case 6:
4486 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4488 size = sizeof(PRINTER_INFO_6);
4489 if (size <= cbBuf) {
4490 /* FIXME: We do not update the status yet */
4491 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4492 ret = TRUE;
4493 } else {
4494 ret = FALSE;
4497 needed += size;
4498 break;
4501 case 7:
4503 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4505 size = sizeof(PRINTER_INFO_7W);
4506 if (size <= cbBuf) {
4507 ptr = pPrinter + size;
4508 cbBuf -= size;
4509 memset(pPrinter, 0, size);
4510 } else {
4511 pi7 = NULL;
4512 cbBuf = 0;
4515 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4516 needed += size;
4517 break;
4521 case 8:
4522 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4523 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4524 /* fall through */
4525 case 9:
4527 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4529 size = sizeof(PRINTER_INFO_9W);
4530 if(size <= cbBuf) {
4531 ptr = pPrinter + size;
4532 cbBuf -= size;
4533 memset(pPrinter, 0, size);
4534 } else {
4535 pi9 = NULL;
4536 cbBuf = 0;
4539 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4540 needed += size;
4541 break;
4545 default:
4546 FIXME("Unimplemented level %d\n", Level);
4547 SetLastError(ERROR_INVALID_LEVEL);
4548 RegCloseKey(hkeyPrinter);
4549 return FALSE;
4552 RegCloseKey(hkeyPrinter);
4554 TRACE("returning %d needed = %d\n", ret, needed);
4555 if(pcbNeeded) *pcbNeeded = needed;
4556 if(!ret)
4557 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4558 return ret;
4561 /*****************************************************************************
4562 * GetPrinterA [WINSPOOL.@]
4564 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4565 DWORD cbBuf, LPDWORD pcbNeeded)
4567 BOOL ret;
4568 LPBYTE buf = NULL;
4570 if (cbBuf)
4571 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4573 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4574 if (ret)
4575 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4576 HeapFree(GetProcessHeap(), 0, buf);
4578 return ret;
4581 /*****************************************************************************
4582 * WINSPOOL_EnumPrintersW
4584 * Implementation of EnumPrintersW
4586 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4587 DWORD dwLevel, LPBYTE lpbPrinters,
4588 DWORD cbBuf, LPDWORD lpdwNeeded,
4589 LPDWORD lpdwReturned)
4592 HKEY hkeyPrinters, hkeyPrinter;
4593 WCHAR PrinterName[255];
4594 DWORD needed = 0, number = 0;
4595 DWORD used, i, left;
4596 PBYTE pi, buf;
4598 if(lpbPrinters)
4599 memset(lpbPrinters, 0, cbBuf);
4600 if(lpdwReturned)
4601 *lpdwReturned = 0;
4602 if(lpdwNeeded)
4603 *lpdwNeeded = 0;
4605 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4606 if(dwType == PRINTER_ENUM_DEFAULT)
4607 return TRUE;
4609 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4610 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4611 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4612 if (!dwType) {
4613 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4614 return TRUE;
4619 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4620 FIXME("dwType = %08x\n", dwType);
4621 SetLastError(ERROR_INVALID_FLAGS);
4622 return FALSE;
4625 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4626 ERROR_SUCCESS) {
4627 ERR("Can't create Printers key\n");
4628 return FALSE;
4631 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4632 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4633 RegCloseKey(hkeyPrinters);
4634 ERR("Can't query Printers key\n");
4635 return FALSE;
4637 TRACE("Found %d printers\n", number);
4639 switch(dwLevel) {
4640 case 1:
4641 used = number * sizeof(PRINTER_INFO_1W);
4642 break;
4643 case 2:
4644 used = number * sizeof(PRINTER_INFO_2W);
4645 break;
4646 case 4:
4647 used = number * sizeof(PRINTER_INFO_4W);
4648 break;
4649 case 5:
4650 used = number * sizeof(PRINTER_INFO_5W);
4651 break;
4653 default:
4654 SetLastError(ERROR_INVALID_LEVEL);
4655 RegCloseKey(hkeyPrinters);
4656 return FALSE;
4658 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4660 for(i = 0; i < number; i++) {
4661 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4662 ERROR_SUCCESS) {
4663 ERR("Can't enum key number %d\n", i);
4664 RegCloseKey(hkeyPrinters);
4665 return FALSE;
4667 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4668 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4669 ERROR_SUCCESS) {
4670 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4671 RegCloseKey(hkeyPrinters);
4672 return FALSE;
4675 if(cbBuf > used) {
4676 buf = lpbPrinters + used;
4677 left = cbBuf - used;
4678 } else {
4679 buf = NULL;
4680 left = 0;
4683 switch(dwLevel) {
4684 case 1:
4685 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4686 left, &needed);
4687 used += needed;
4688 if(pi) pi += sizeof(PRINTER_INFO_1W);
4689 break;
4690 case 2:
4691 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4692 left, &needed);
4693 used += needed;
4694 if(pi) pi += sizeof(PRINTER_INFO_2W);
4695 break;
4696 case 4:
4697 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4698 left, &needed);
4699 used += needed;
4700 if(pi) pi += sizeof(PRINTER_INFO_4W);
4701 break;
4702 case 5:
4703 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4704 left, &needed);
4705 used += needed;
4706 if(pi) pi += sizeof(PRINTER_INFO_5W);
4707 break;
4708 default:
4709 ERR("Shouldn't be here!\n");
4710 RegCloseKey(hkeyPrinter);
4711 RegCloseKey(hkeyPrinters);
4712 return FALSE;
4714 RegCloseKey(hkeyPrinter);
4716 RegCloseKey(hkeyPrinters);
4718 if(lpdwNeeded)
4719 *lpdwNeeded = used;
4721 if(used > cbBuf) {
4722 if(lpbPrinters)
4723 memset(lpbPrinters, 0, cbBuf);
4724 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4725 return FALSE;
4727 if(lpdwReturned)
4728 *lpdwReturned = number;
4729 SetLastError(ERROR_SUCCESS);
4730 return TRUE;
4734 /******************************************************************
4735 * EnumPrintersW [WINSPOOL.@]
4737 * Enumerates the available printers, print servers and print
4738 * providers, depending on the specified flags, name and level.
4740 * RETURNS:
4742 * If level is set to 1:
4743 * Returns an array of PRINTER_INFO_1 data structures in the
4744 * lpbPrinters buffer.
4746 * If level is set to 2:
4747 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4748 * Returns an array of PRINTER_INFO_2 data structures in the
4749 * lpbPrinters buffer. Note that according to MSDN also an
4750 * OpenPrinter should be performed on every remote printer.
4752 * If level is set to 4 (officially WinNT only):
4753 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4754 * Fast: Only the registry is queried to retrieve printer names,
4755 * no connection to the driver is made.
4756 * Returns an array of PRINTER_INFO_4 data structures in the
4757 * lpbPrinters buffer.
4759 * If level is set to 5 (officially WinNT4/Win9x only):
4760 * Fast: Only the registry is queried to retrieve printer names,
4761 * no connection to the driver is made.
4762 * Returns an array of PRINTER_INFO_5 data structures in the
4763 * lpbPrinters buffer.
4765 * If level set to 3 or 6+:
4766 * returns zero (failure!)
4768 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4769 * for information.
4771 * BUGS:
4772 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4773 * - Only levels 2, 4 and 5 are implemented at the moment.
4774 * - 16-bit printer drivers are not enumerated.
4775 * - Returned amount of bytes used/needed does not match the real Windoze
4776 * implementation (as in this implementation, all strings are part
4777 * of the buffer, whereas Win32 keeps them somewhere else)
4778 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4780 * NOTE:
4781 * - In a regular Wine installation, no registry settings for printers
4782 * exist, which makes this function return an empty list.
4784 BOOL WINAPI EnumPrintersW(
4785 DWORD dwType, /* [in] Types of print objects to enumerate */
4786 LPWSTR lpszName, /* [in] name of objects to enumerate */
4787 DWORD dwLevel, /* [in] type of printer info structure */
4788 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4789 DWORD cbBuf, /* [in] max size of buffer in bytes */
4790 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4791 LPDWORD lpdwReturned /* [out] number of entries returned */
4794 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4795 lpdwNeeded, lpdwReturned);
4798 /******************************************************************
4799 * EnumPrintersA [WINSPOOL.@]
4801 * See EnumPrintersW
4804 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4805 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4807 BOOL ret;
4808 UNICODE_STRING pNameU;
4809 LPWSTR pNameW;
4810 LPBYTE pPrintersW;
4812 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4813 pPrinters, cbBuf, pcbNeeded, pcReturned);
4815 pNameW = asciitounicode(&pNameU, pName);
4817 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4818 MS Office need this */
4819 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4821 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4823 RtlFreeUnicodeString(&pNameU);
4824 if (ret) {
4825 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4827 HeapFree(GetProcessHeap(), 0, pPrintersW);
4828 return ret;
4831 /*****************************************************************************
4832 * WINSPOOL_GetDriverInfoFromReg [internal]
4834 * Enters the information from the registry into the DRIVER_INFO struct
4836 * RETURNS
4837 * zero if the printer driver does not exist in the registry
4838 * (only if Level > 1) otherwise nonzero
4840 static BOOL WINSPOOL_GetDriverInfoFromReg(
4841 HKEY hkeyDrivers,
4842 LPWSTR DriverName,
4843 const printenv_t * env,
4844 DWORD Level,
4845 LPBYTE ptr, /* DRIVER_INFO */
4846 LPBYTE pDriverStrings, /* strings buffer */
4847 DWORD cbBuf, /* size of string buffer */
4848 LPDWORD pcbNeeded) /* space needed for str. */
4850 DWORD size, tmp;
4851 HKEY hkeyDriver;
4852 WCHAR driverdir[MAX_PATH];
4853 DWORD dirlen;
4854 LPBYTE strPtr = pDriverStrings;
4855 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4857 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4858 debugstr_w(DriverName), env,
4859 Level, di, pDriverStrings, cbBuf);
4861 if (di) ZeroMemory(di, di_sizeof[Level]);
4863 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4864 if (*pcbNeeded <= cbBuf)
4865 strcpyW((LPWSTR)strPtr, DriverName);
4867 /* pName for level 1 has a different offset! */
4868 if (Level == 1) {
4869 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4870 return TRUE;
4873 /* .cVersion and .pName for level > 1 */
4874 if (di) {
4875 di->cVersion = env->driverversion;
4876 di->pName = (LPWSTR) strPtr;
4877 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4880 /* Reserve Space for the largest subdir and a Backslash*/
4881 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4882 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4883 /* Should never Fail */
4884 return FALSE;
4886 lstrcatW(driverdir, env->versionsubdir);
4887 lstrcatW(driverdir, backslashW);
4889 /* dirlen must not include the terminating zero */
4890 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4892 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4893 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4894 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4895 return FALSE;
4898 /* pEnvironment */
4899 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4901 *pcbNeeded += size;
4902 if (*pcbNeeded <= cbBuf) {
4903 lstrcpyW((LPWSTR)strPtr, env->envname);
4904 if (di) di->pEnvironment = (LPWSTR)strPtr;
4905 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4908 /* .pDriverPath is the Graphics rendering engine.
4909 The full Path is required to avoid a crash in some apps */
4910 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4911 *pcbNeeded += size;
4912 if (*pcbNeeded <= cbBuf)
4913 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4915 if (di) di->pDriverPath = (LPWSTR)strPtr;
4916 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4919 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4920 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4921 *pcbNeeded += size;
4922 if (*pcbNeeded <= cbBuf)
4923 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4925 if (di) di->pDataFile = (LPWSTR)strPtr;
4926 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4929 /* .pConfigFile is the Driver user Interface */
4930 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4931 *pcbNeeded += size;
4932 if (*pcbNeeded <= cbBuf)
4933 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4935 if (di) di->pConfigFile = (LPWSTR)strPtr;
4936 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4939 if (Level == 2 ) {
4940 RegCloseKey(hkeyDriver);
4941 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4942 return TRUE;
4945 if (Level == 5 ) {
4946 RegCloseKey(hkeyDriver);
4947 FIXME("level 5: incomplete\n");
4948 return TRUE;
4951 /* .pHelpFile */
4952 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4953 *pcbNeeded += size;
4954 if (*pcbNeeded <= cbBuf)
4955 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4957 if (di) di->pHelpFile = (LPWSTR)strPtr;
4958 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4961 /* .pDependentFiles */
4962 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4963 *pcbNeeded += size;
4964 if (*pcbNeeded <= cbBuf)
4965 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4967 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4968 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4970 else if (GetVersion() & 0x80000000) {
4971 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4972 size = 2 * sizeof(WCHAR);
4973 *pcbNeeded += size;
4974 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4976 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4977 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4980 /* .pMonitorName is the optional Language Monitor */
4981 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4982 *pcbNeeded += size;
4983 if (*pcbNeeded <= cbBuf)
4984 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4986 if (di) di->pMonitorName = (LPWSTR)strPtr;
4987 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4990 /* .pDefaultDataType */
4991 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4992 *pcbNeeded += size;
4993 if(*pcbNeeded <= cbBuf)
4994 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4996 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4997 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5000 if (Level == 3 ) {
5001 RegCloseKey(hkeyDriver);
5002 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5003 return TRUE;
5006 /* .pszzPreviousNames */
5007 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
5008 *pcbNeeded += size;
5009 if(*pcbNeeded <= cbBuf)
5010 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
5012 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
5013 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5016 if (Level == 4 ) {
5017 RegCloseKey(hkeyDriver);
5018 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5019 return TRUE;
5022 /* support is missing, but not important enough for a FIXME */
5023 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5025 /* .pszMfgName */
5026 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5027 *pcbNeeded += size;
5028 if(*pcbNeeded <= cbBuf)
5029 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5031 if (di) di->pszMfgName = (LPWSTR)strPtr;
5032 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5035 /* .pszOEMUrl */
5036 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5037 *pcbNeeded += size;
5038 if(*pcbNeeded <= cbBuf)
5039 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5041 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5042 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5045 /* .pszHardwareID */
5046 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5047 *pcbNeeded += size;
5048 if(*pcbNeeded <= cbBuf)
5049 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5051 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5052 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5055 /* .pszProvider */
5056 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5057 *pcbNeeded += size;
5058 if(*pcbNeeded <= cbBuf)
5059 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5061 if (di) di->pszProvider = (LPWSTR)strPtr;
5062 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5065 if (Level == 6 ) {
5066 RegCloseKey(hkeyDriver);
5067 return TRUE;
5070 /* support is missing, but not important enough for a FIXME */
5071 TRACE("level 8: incomplete\n");
5073 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5074 RegCloseKey(hkeyDriver);
5075 return TRUE;
5078 /*****************************************************************************
5079 * GetPrinterDriverW [WINSPOOL.@]
5081 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5082 DWORD Level, LPBYTE pDriverInfo,
5083 DWORD cbBuf, LPDWORD pcbNeeded)
5085 LPCWSTR name;
5086 WCHAR DriverName[100];
5087 DWORD ret, type, size, needed = 0;
5088 LPBYTE ptr = NULL;
5089 HKEY hkeyPrinter, hkeyDrivers;
5090 const printenv_t * env;
5092 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5093 Level,pDriverInfo,cbBuf, pcbNeeded);
5095 if (cbBuf > 0)
5096 ZeroMemory(pDriverInfo, cbBuf);
5098 if (!(name = get_opened_printer_name(hPrinter))) {
5099 SetLastError(ERROR_INVALID_HANDLE);
5100 return FALSE;
5103 if (Level < 1 || Level == 7 || Level > 8) {
5104 SetLastError(ERROR_INVALID_LEVEL);
5105 return FALSE;
5108 env = validate_envW(pEnvironment);
5109 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5111 ret = open_printer_reg_key( name, &hkeyPrinter );
5112 if (ret)
5114 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5115 SetLastError( ret );
5116 return FALSE;
5119 size = sizeof(DriverName);
5120 DriverName[0] = 0;
5121 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5122 (LPBYTE)DriverName, &size);
5123 RegCloseKey(hkeyPrinter);
5124 if(ret != ERROR_SUCCESS) {
5125 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5126 return FALSE;
5129 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5130 if(!hkeyDrivers) {
5131 ERR("Can't create Drivers key\n");
5132 return FALSE;
5135 size = di_sizeof[Level];
5136 if ((size <= cbBuf) && pDriverInfo)
5137 ptr = pDriverInfo + size;
5139 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5140 env, Level, pDriverInfo, ptr,
5141 (cbBuf < size) ? 0 : cbBuf - size,
5142 &needed)) {
5143 RegCloseKey(hkeyDrivers);
5144 return FALSE;
5147 RegCloseKey(hkeyDrivers);
5149 if(pcbNeeded) *pcbNeeded = size + needed;
5150 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5151 if(cbBuf >= size + needed) return TRUE;
5152 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5153 return FALSE;
5156 /*****************************************************************************
5157 * GetPrinterDriverA [WINSPOOL.@]
5159 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5160 DWORD Level, LPBYTE pDriverInfo,
5161 DWORD cbBuf, LPDWORD pcbNeeded)
5163 BOOL ret;
5164 UNICODE_STRING pEnvW;
5165 PWSTR pwstrEnvW;
5166 LPBYTE buf = NULL;
5168 if (cbBuf)
5170 ZeroMemory(pDriverInfo, cbBuf);
5171 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5174 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5175 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5176 cbBuf, pcbNeeded);
5177 if (ret)
5178 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5180 HeapFree(GetProcessHeap(), 0, buf);
5182 RtlFreeUnicodeString(&pEnvW);
5183 return ret;
5186 /*****************************************************************************
5187 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5189 * Return the PATH for the Printer-Drivers (UNICODE)
5191 * PARAMS
5192 * pName [I] Servername (NT only) or NULL (local Computer)
5193 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5194 * Level [I] Structure-Level (must be 1)
5195 * pDriverDirectory [O] PTR to Buffer that receives the Result
5196 * cbBuf [I] Size of Buffer at pDriverDirectory
5197 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5198 * required for pDriverDirectory
5200 * RETURNS
5201 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5202 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5203 * if cbBuf is too small
5205 * Native Values returned in pDriverDirectory on Success:
5206 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5207 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5208 *| win9x(Windows 4.0): "%winsysdir%"
5210 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5212 * FIXME
5213 *- Only NULL or "" is supported for pName
5216 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5217 DWORD Level, LPBYTE pDriverDirectory,
5218 DWORD cbBuf, LPDWORD pcbNeeded)
5220 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5221 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5223 if ((backend == NULL) && !load_backend()) return FALSE;
5225 if (Level != 1) {
5226 /* (Level != 1) is ignored in win9x */
5227 SetLastError(ERROR_INVALID_LEVEL);
5228 return FALSE;
5230 if (pcbNeeded == NULL) {
5231 /* (pcbNeeded == NULL) is ignored in win9x */
5232 SetLastError(RPC_X_NULL_REF_POINTER);
5233 return FALSE;
5236 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5237 pDriverDirectory, cbBuf, pcbNeeded);
5242 /*****************************************************************************
5243 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5245 * Return the PATH for the Printer-Drivers (ANSI)
5247 * See GetPrinterDriverDirectoryW.
5249 * NOTES
5250 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5253 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5254 DWORD Level, LPBYTE pDriverDirectory,
5255 DWORD cbBuf, LPDWORD pcbNeeded)
5257 UNICODE_STRING nameW, environmentW;
5258 BOOL ret;
5259 DWORD pcbNeededW;
5260 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5261 WCHAR *driverDirectoryW = NULL;
5263 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5264 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5266 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5268 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5269 else nameW.Buffer = NULL;
5270 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5271 else environmentW.Buffer = NULL;
5273 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5274 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5275 if (ret) {
5276 DWORD needed;
5277 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5278 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5279 if(pcbNeeded)
5280 *pcbNeeded = needed;
5281 ret = needed <= cbBuf;
5282 } else
5283 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5285 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5287 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5288 RtlFreeUnicodeString(&environmentW);
5289 RtlFreeUnicodeString(&nameW);
5291 return ret;
5294 /*****************************************************************************
5295 * AddPrinterDriverA [WINSPOOL.@]
5297 * See AddPrinterDriverW.
5300 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5302 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5303 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5306 /******************************************************************************
5307 * AddPrinterDriverW (WINSPOOL.@)
5309 * Install a Printer Driver
5311 * PARAMS
5312 * pName [I] Servername or NULL (local Computer)
5313 * level [I] Level for the supplied DRIVER_INFO_*W struct
5314 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5316 * RESULTS
5317 * Success: TRUE
5318 * Failure: FALSE
5321 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5323 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5324 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5327 /*****************************************************************************
5328 * AddPrintProcessorA [WINSPOOL.@]
5330 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5331 LPSTR pPrintProcessorName)
5333 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5334 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5335 return FALSE;
5338 /*****************************************************************************
5339 * AddPrintProcessorW [WINSPOOL.@]
5341 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5342 LPWSTR pPrintProcessorName)
5344 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5345 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5346 return TRUE;
5349 /*****************************************************************************
5350 * AddPrintProvidorA [WINSPOOL.@]
5352 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5354 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5355 return FALSE;
5358 /*****************************************************************************
5359 * AddPrintProvidorW [WINSPOOL.@]
5361 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5363 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5364 return FALSE;
5367 /*****************************************************************************
5368 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5370 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5371 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5373 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5374 pDevModeOutput, pDevModeInput);
5375 return 0;
5378 /*****************************************************************************
5379 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5381 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5382 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5384 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5385 pDevModeOutput, pDevModeInput);
5386 return 0;
5389 /*****************************************************************************
5390 * PrinterProperties [WINSPOOL.@]
5392 * Displays a dialog to set the properties of the printer.
5394 * RETURNS
5395 * nonzero on success or zero on failure
5397 * BUGS
5398 * implemented as stub only
5400 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5401 HANDLE hPrinter /* [in] handle to printer object */
5403 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5404 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5405 return FALSE;
5408 /*****************************************************************************
5409 * EnumJobsA [WINSPOOL.@]
5412 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5413 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5414 LPDWORD pcReturned)
5416 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5417 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5419 if(pcbNeeded) *pcbNeeded = 0;
5420 if(pcReturned) *pcReturned = 0;
5421 return FALSE;
5425 /*****************************************************************************
5426 * EnumJobsW [WINSPOOL.@]
5429 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5430 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5431 LPDWORD pcReturned)
5433 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5434 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5436 if(pcbNeeded) *pcbNeeded = 0;
5437 if(pcReturned) *pcReturned = 0;
5438 return FALSE;
5441 /*****************************************************************************
5442 * WINSPOOL_EnumPrinterDrivers [internal]
5444 * Delivers information about all printer drivers installed on the
5445 * localhost or a given server
5447 * RETURNS
5448 * nonzero on success or zero on failure. If the buffer for the returned
5449 * information is too small the function will return an error
5451 * BUGS
5452 * - only implemented for localhost, foreign hosts will return an error
5454 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5455 DWORD Level, LPBYTE pDriverInfo,
5456 DWORD driver_index,
5457 DWORD cbBuf, LPDWORD pcbNeeded,
5458 LPDWORD pcFound, DWORD data_offset)
5460 { HKEY hkeyDrivers;
5461 DWORD i, size = 0;
5462 const printenv_t * env;
5464 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5465 debugstr_w(pName), debugstr_w(pEnvironment),
5466 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5468 env = validate_envW(pEnvironment);
5469 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5471 *pcFound = 0;
5473 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5474 if(!hkeyDrivers) {
5475 ERR("Can't open Drivers key\n");
5476 return FALSE;
5479 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5480 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5481 RegCloseKey(hkeyDrivers);
5482 ERR("Can't query Drivers key\n");
5483 return FALSE;
5485 TRACE("Found %d Drivers\n", *pcFound);
5487 /* get size of single struct
5488 * unicode and ascii structure have the same size
5490 size = di_sizeof[Level];
5492 if (data_offset == 0)
5493 data_offset = size * (*pcFound);
5494 *pcbNeeded = data_offset;
5496 for( i = 0; i < *pcFound; i++) {
5497 WCHAR DriverNameW[255];
5498 PBYTE table_ptr = NULL;
5499 PBYTE data_ptr = NULL;
5500 DWORD needed = 0;
5502 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5503 != ERROR_SUCCESS) {
5504 ERR("Can't enum key number %d\n", i);
5505 RegCloseKey(hkeyDrivers);
5506 return FALSE;
5509 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5510 table_ptr = pDriverInfo + (driver_index + i) * size;
5511 if (pDriverInfo && *pcbNeeded <= cbBuf)
5512 data_ptr = pDriverInfo + *pcbNeeded;
5514 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5515 env, Level, table_ptr, data_ptr,
5516 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5517 &needed)) {
5518 RegCloseKey(hkeyDrivers);
5519 return FALSE;
5522 *pcbNeeded += needed;
5525 RegCloseKey(hkeyDrivers);
5527 if(cbBuf < *pcbNeeded){
5528 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5529 return FALSE;
5532 return TRUE;
5535 /*****************************************************************************
5536 * EnumPrinterDriversW [WINSPOOL.@]
5538 * see function EnumPrinterDrivers for RETURNS, BUGS
5540 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5541 LPBYTE pDriverInfo, DWORD cbBuf,
5542 LPDWORD pcbNeeded, LPDWORD pcReturned)
5544 static const WCHAR allW[] = {'a','l','l',0};
5545 BOOL ret;
5546 DWORD found;
5548 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5550 SetLastError(RPC_X_NULL_REF_POINTER);
5551 return FALSE;
5554 /* check for local drivers */
5555 if((pName) && (pName[0])) {
5556 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5557 SetLastError(ERROR_ACCESS_DENIED);
5558 return FALSE;
5561 /* check input parameter */
5562 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5563 SetLastError(ERROR_INVALID_LEVEL);
5564 return FALSE;
5567 if(pDriverInfo && cbBuf > 0)
5568 memset( pDriverInfo, 0, cbBuf);
5570 /* Exception: pull all printers */
5571 if (pEnvironment && !strcmpW(pEnvironment, allW))
5573 DWORD i, needed, bufsize = cbBuf;
5574 DWORD total_found = 0;
5575 DWORD data_offset;
5577 /* Precompute the overall total; we need this to know
5578 where pointers end and data begins (i.e. data_offset) */
5579 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5581 needed = found = 0;
5582 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5583 NULL, 0, 0, &needed, &found, 0);
5584 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5585 total_found += found;
5588 data_offset = di_sizeof[Level] * total_found;
5590 *pcReturned = 0;
5591 *pcbNeeded = 0;
5592 total_found = 0;
5593 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5595 needed = found = 0;
5596 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5597 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5598 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5599 else if (ret)
5600 *pcReturned += found;
5601 *pcbNeeded = needed;
5602 data_offset = needed;
5603 total_found += found;
5605 return ret;
5608 /* Normal behavior */
5609 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5610 0, cbBuf, pcbNeeded, &found, 0);
5611 if (ret)
5612 *pcReturned = found;
5614 return ret;
5617 /*****************************************************************************
5618 * EnumPrinterDriversA [WINSPOOL.@]
5620 * see function EnumPrinterDrivers for RETURNS, BUGS
5622 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5623 LPBYTE pDriverInfo, DWORD cbBuf,
5624 LPDWORD pcbNeeded, LPDWORD pcReturned)
5626 BOOL ret;
5627 UNICODE_STRING pNameW, pEnvironmentW;
5628 PWSTR pwstrNameW, pwstrEnvironmentW;
5629 LPBYTE buf = NULL;
5631 if (cbBuf)
5632 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5634 pwstrNameW = asciitounicode(&pNameW, pName);
5635 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5637 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5638 buf, cbBuf, pcbNeeded, pcReturned);
5639 if (ret)
5640 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5642 HeapFree(GetProcessHeap(), 0, buf);
5644 RtlFreeUnicodeString(&pNameW);
5645 RtlFreeUnicodeString(&pEnvironmentW);
5647 return ret;
5650 /******************************************************************************
5651 * EnumPortsA (WINSPOOL.@)
5653 * See EnumPortsW.
5656 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5657 LPDWORD pcbNeeded, LPDWORD pcReturned)
5659 BOOL res;
5660 LPBYTE bufferW = NULL;
5661 LPWSTR nameW = NULL;
5662 DWORD needed = 0;
5663 DWORD numentries = 0;
5664 INT len;
5666 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5667 cbBuf, pcbNeeded, pcReturned);
5669 /* convert servername to unicode */
5670 if (pName) {
5671 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5672 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5673 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5675 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5676 needed = cbBuf * sizeof(WCHAR);
5677 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5678 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5680 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5681 if (pcbNeeded) needed = *pcbNeeded;
5682 /* HeapReAlloc return NULL, when bufferW was NULL */
5683 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5684 HeapAlloc(GetProcessHeap(), 0, needed);
5686 /* Try again with the large Buffer */
5687 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5689 needed = pcbNeeded ? *pcbNeeded : 0;
5690 numentries = pcReturned ? *pcReturned : 0;
5693 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5694 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5696 if (res) {
5697 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5698 DWORD entrysize = 0;
5699 DWORD index;
5700 LPSTR ptr;
5701 LPPORT_INFO_2W pi2w;
5702 LPPORT_INFO_2A pi2a;
5704 needed = 0;
5705 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5707 /* First pass: calculate the size for all Entries */
5708 pi2w = (LPPORT_INFO_2W) bufferW;
5709 pi2a = (LPPORT_INFO_2A) pPorts;
5710 index = 0;
5711 while (index < numentries) {
5712 index++;
5713 needed += entrysize; /* PORT_INFO_?A */
5714 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5716 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5717 NULL, 0, NULL, NULL);
5718 if (Level > 1) {
5719 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5720 NULL, 0, NULL, NULL);
5721 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5722 NULL, 0, NULL, NULL);
5724 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5725 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5726 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5729 /* check for errors and quit on failure */
5730 if (cbBuf < needed) {
5731 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5732 res = FALSE;
5733 goto cleanup;
5735 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5736 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5737 cbBuf -= len ; /* free Bytes in the user-Buffer */
5738 pi2w = (LPPORT_INFO_2W) bufferW;
5739 pi2a = (LPPORT_INFO_2A) pPorts;
5740 index = 0;
5741 /* Second Pass: Fill the User Buffer (if we have one) */
5742 while ((index < numentries) && pPorts) {
5743 index++;
5744 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5745 pi2a->pPortName = ptr;
5746 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5747 ptr, cbBuf , NULL, NULL);
5748 ptr += len;
5749 cbBuf -= len;
5750 if (Level > 1) {
5751 pi2a->pMonitorName = ptr;
5752 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5753 ptr, cbBuf, NULL, NULL);
5754 ptr += len;
5755 cbBuf -= len;
5757 pi2a->pDescription = ptr;
5758 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5759 ptr, cbBuf, NULL, NULL);
5760 ptr += len;
5761 cbBuf -= len;
5763 pi2a->fPortType = pi2w->fPortType;
5764 pi2a->Reserved = 0; /* documented: "must be zero" */
5767 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5768 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5769 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5773 cleanup:
5774 if (pcbNeeded) *pcbNeeded = needed;
5775 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5777 HeapFree(GetProcessHeap(), 0, nameW);
5778 HeapFree(GetProcessHeap(), 0, bufferW);
5780 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5781 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5783 return (res);
5787 /******************************************************************************
5788 * EnumPortsW (WINSPOOL.@)
5790 * Enumerate available Ports
5792 * PARAMS
5793 * pName [I] Servername or NULL (local Computer)
5794 * Level [I] Structure-Level (1 or 2)
5795 * pPorts [O] PTR to Buffer that receives the Result
5796 * cbBuf [I] Size of Buffer at pPorts
5797 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5798 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5800 * RETURNS
5801 * Success: TRUE
5802 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5805 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5808 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5809 cbBuf, pcbNeeded, pcReturned);
5811 if ((backend == NULL) && !load_backend()) return FALSE;
5813 /* Level is not checked in win9x */
5814 if (!Level || (Level > 2)) {
5815 WARN("level (%d) is ignored in win9x\n", Level);
5816 SetLastError(ERROR_INVALID_LEVEL);
5817 return FALSE;
5819 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5820 SetLastError(RPC_X_NULL_REF_POINTER);
5821 return FALSE;
5824 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5827 /******************************************************************************
5828 * GetDefaultPrinterW (WINSPOOL.@)
5830 * FIXME
5831 * This function must read the value from data 'device' of key
5832 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5834 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5836 BOOL retval = TRUE;
5837 DWORD insize, len;
5838 WCHAR *buffer, *ptr;
5840 if (!namesize)
5842 SetLastError(ERROR_INVALID_PARAMETER);
5843 return FALSE;
5846 /* make the buffer big enough for the stuff from the profile/registry,
5847 * the content must fit into the local buffer to compute the correct
5848 * size even if the extern buffer is too small or not given.
5849 * (20 for ,driver,port) */
5850 insize = *namesize;
5851 len = max(100, (insize + 20));
5852 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5854 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5856 SetLastError (ERROR_FILE_NOT_FOUND);
5857 retval = FALSE;
5858 goto end;
5860 TRACE("%s\n", debugstr_w(buffer));
5862 if ((ptr = strchrW(buffer, ',')) == NULL)
5864 SetLastError(ERROR_INVALID_NAME);
5865 retval = FALSE;
5866 goto end;
5869 *ptr = 0;
5870 *namesize = strlenW(buffer) + 1;
5871 if(!name || (*namesize > insize))
5873 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5874 retval = FALSE;
5875 goto end;
5877 strcpyW(name, buffer);
5879 end:
5880 HeapFree( GetProcessHeap(), 0, buffer);
5881 return retval;
5885 /******************************************************************************
5886 * GetDefaultPrinterA (WINSPOOL.@)
5888 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5890 BOOL retval = TRUE;
5891 DWORD insize = 0;
5892 WCHAR *bufferW = NULL;
5894 if (!namesize)
5896 SetLastError(ERROR_INVALID_PARAMETER);
5897 return FALSE;
5900 if(name && *namesize) {
5901 insize = *namesize;
5902 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5905 if(!GetDefaultPrinterW( bufferW, namesize)) {
5906 retval = FALSE;
5907 goto end;
5910 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5911 NULL, NULL);
5912 if (!*namesize)
5914 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5915 retval = FALSE;
5917 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5919 end:
5920 HeapFree( GetProcessHeap(), 0, bufferW);
5921 return retval;
5925 /******************************************************************************
5926 * SetDefaultPrinterW (WINSPOOL.204)
5928 * Set the Name of the Default Printer
5930 * PARAMS
5931 * pszPrinter [I] Name of the Printer or NULL
5933 * RETURNS
5934 * Success: True
5935 * Failure: FALSE
5937 * NOTES
5938 * When the Parameter is NULL or points to an Empty String and
5939 * a Default Printer was already present, then this Function changes nothing.
5940 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5941 * the First enumerated local Printer is used.
5944 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5946 WCHAR default_printer[MAX_PATH];
5947 LPWSTR buffer = NULL;
5948 HKEY hreg;
5949 DWORD size;
5950 DWORD namelen;
5951 LONG lres;
5953 TRACE("(%s)\n", debugstr_w(pszPrinter));
5954 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5956 default_printer[0] = '\0';
5957 size = sizeof(default_printer)/sizeof(WCHAR);
5959 /* if we have a default Printer, do nothing. */
5960 if (GetDefaultPrinterW(default_printer, &size))
5961 return TRUE;
5963 pszPrinter = NULL;
5964 /* we have no default Printer: search local Printers and use the first */
5965 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5967 default_printer[0] = '\0';
5968 size = sizeof(default_printer)/sizeof(WCHAR);
5969 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5971 pszPrinter = default_printer;
5972 TRACE("using %s\n", debugstr_w(pszPrinter));
5974 RegCloseKey(hreg);
5977 if (pszPrinter == NULL) {
5978 TRACE("no local printer found\n");
5979 SetLastError(ERROR_FILE_NOT_FOUND);
5980 return FALSE;
5984 /* "pszPrinter" is never empty or NULL here. */
5985 namelen = lstrlenW(pszPrinter);
5986 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5987 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5988 if (!buffer ||
5989 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5990 HeapFree(GetProcessHeap(), 0, buffer);
5991 SetLastError(ERROR_FILE_NOT_FOUND);
5992 return FALSE;
5995 /* read the devices entry for the printer (driver,port) to build the string for the
5996 default device entry (printer,driver,port) */
5997 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5998 buffer[namelen] = ',';
5999 namelen++; /* move index to the start of the driver */
6001 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
6002 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
6003 if (!lres) {
6004 TRACE("set device to %s\n", debugstr_w(buffer));
6006 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
6007 TRACE("failed to set the device entry: %d\n", GetLastError());
6008 lres = ERROR_INVALID_PRINTER_NAME;
6011 /* remove the next section, when INIFileMapping is implemented */
6013 HKEY hdev;
6014 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
6015 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6016 RegCloseKey(hdev);
6020 else
6022 if (lres != ERROR_FILE_NOT_FOUND)
6023 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6025 SetLastError(ERROR_INVALID_PRINTER_NAME);
6028 RegCloseKey(hreg);
6029 HeapFree(GetProcessHeap(), 0, buffer);
6030 return (lres == ERROR_SUCCESS);
6033 /******************************************************************************
6034 * SetDefaultPrinterA (WINSPOOL.202)
6036 * See SetDefaultPrinterW.
6039 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6041 LPWSTR bufferW = NULL;
6042 BOOL res;
6044 TRACE("(%s)\n", debugstr_a(pszPrinter));
6045 if(pszPrinter) {
6046 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6047 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6048 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6050 res = SetDefaultPrinterW(bufferW);
6051 HeapFree(GetProcessHeap(), 0, bufferW);
6052 return res;
6055 /******************************************************************************
6056 * SetPrinterDataExA (WINSPOOL.@)
6058 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6059 LPCSTR pValueName, DWORD Type,
6060 LPBYTE pData, DWORD cbData)
6062 HKEY hkeyPrinter, hkeySubkey;
6063 DWORD ret;
6065 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6066 debugstr_a(pValueName), Type, pData, cbData);
6068 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6069 != ERROR_SUCCESS)
6070 return ret;
6072 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6073 != ERROR_SUCCESS) {
6074 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6075 RegCloseKey(hkeyPrinter);
6076 return ret;
6078 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6079 RegCloseKey(hkeySubkey);
6080 RegCloseKey(hkeyPrinter);
6081 return ret;
6084 /******************************************************************************
6085 * SetPrinterDataExW (WINSPOOL.@)
6087 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6088 LPCWSTR pValueName, DWORD Type,
6089 LPBYTE pData, DWORD cbData)
6091 HKEY hkeyPrinter, hkeySubkey;
6092 DWORD ret;
6094 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6095 debugstr_w(pValueName), Type, pData, cbData);
6097 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6098 != ERROR_SUCCESS)
6099 return ret;
6101 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6102 != ERROR_SUCCESS) {
6103 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6104 RegCloseKey(hkeyPrinter);
6105 return ret;
6107 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6108 RegCloseKey(hkeySubkey);
6109 RegCloseKey(hkeyPrinter);
6110 return ret;
6113 /******************************************************************************
6114 * SetPrinterDataA (WINSPOOL.@)
6116 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6117 LPBYTE pData, DWORD cbData)
6119 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6120 pData, cbData);
6123 /******************************************************************************
6124 * SetPrinterDataW (WINSPOOL.@)
6126 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6127 LPBYTE pData, DWORD cbData)
6129 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6130 pData, cbData);
6133 /******************************************************************************
6134 * GetPrinterDataExA (WINSPOOL.@)
6136 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6137 LPCSTR pValueName, LPDWORD pType,
6138 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6140 opened_printer_t *printer;
6141 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6142 DWORD ret;
6144 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6145 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6147 printer = get_opened_printer(hPrinter);
6148 if(!printer) return ERROR_INVALID_HANDLE;
6150 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6151 if (ret) return ret;
6153 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6155 if (printer->name) {
6157 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6158 if (ret) {
6159 RegCloseKey(hkeyPrinters);
6160 return ret;
6162 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6163 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6164 RegCloseKey(hkeyPrinter);
6165 RegCloseKey(hkeyPrinters);
6166 return ret;
6169 *pcbNeeded = nSize;
6170 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6171 0, pType, pData, pcbNeeded);
6173 if (!ret && !pData) ret = ERROR_MORE_DATA;
6175 RegCloseKey(hkeySubkey);
6176 RegCloseKey(hkeyPrinter);
6177 RegCloseKey(hkeyPrinters);
6179 TRACE("--> %d\n", ret);
6180 return ret;
6183 /******************************************************************************
6184 * GetPrinterDataExW (WINSPOOL.@)
6186 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6187 LPCWSTR pValueName, LPDWORD pType,
6188 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6190 opened_printer_t *printer;
6191 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6192 DWORD ret;
6194 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6195 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6197 printer = get_opened_printer(hPrinter);
6198 if(!printer) return ERROR_INVALID_HANDLE;
6200 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6201 if (ret) return ret;
6203 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6205 if (printer->name) {
6207 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6208 if (ret) {
6209 RegCloseKey(hkeyPrinters);
6210 return ret;
6212 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6213 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6214 RegCloseKey(hkeyPrinter);
6215 RegCloseKey(hkeyPrinters);
6216 return ret;
6219 *pcbNeeded = nSize;
6220 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6221 0, pType, pData, pcbNeeded);
6223 if (!ret && !pData) ret = ERROR_MORE_DATA;
6225 RegCloseKey(hkeySubkey);
6226 RegCloseKey(hkeyPrinter);
6227 RegCloseKey(hkeyPrinters);
6229 TRACE("--> %d\n", ret);
6230 return ret;
6233 /******************************************************************************
6234 * GetPrinterDataA (WINSPOOL.@)
6236 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6237 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6239 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6240 pData, nSize, pcbNeeded);
6243 /******************************************************************************
6244 * GetPrinterDataW (WINSPOOL.@)
6246 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6247 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6249 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6250 pData, nSize, pcbNeeded);
6253 /*******************************************************************************
6254 * EnumPrinterDataExW [WINSPOOL.@]
6256 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6257 LPBYTE pEnumValues, DWORD cbEnumValues,
6258 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6260 HKEY hkPrinter, hkSubKey;
6261 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6262 cbValueNameLen, cbMaxValueLen, cbValueLen,
6263 cbBufSize, dwType;
6264 LPWSTR lpValueName;
6265 HANDLE hHeap;
6266 PBYTE lpValue;
6267 PPRINTER_ENUM_VALUESW ppev;
6269 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6271 if (pKeyName == NULL || *pKeyName == 0)
6272 return ERROR_INVALID_PARAMETER;
6274 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6275 if (ret != ERROR_SUCCESS)
6277 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6278 hPrinter, ret);
6279 return ret;
6282 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6283 if (ret != ERROR_SUCCESS)
6285 r = RegCloseKey (hkPrinter);
6286 if (r != ERROR_SUCCESS)
6287 WARN ("RegCloseKey returned %i\n", r);
6288 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6289 debugstr_w (pKeyName), ret);
6290 return ret;
6293 ret = RegCloseKey (hkPrinter);
6294 if (ret != ERROR_SUCCESS)
6296 ERR ("RegCloseKey returned %i\n", ret);
6297 r = RegCloseKey (hkSubKey);
6298 if (r != ERROR_SUCCESS)
6299 WARN ("RegCloseKey returned %i\n", r);
6300 return ret;
6303 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6304 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6305 if (ret != ERROR_SUCCESS)
6307 r = RegCloseKey (hkSubKey);
6308 if (r != ERROR_SUCCESS)
6309 WARN ("RegCloseKey returned %i\n", r);
6310 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6311 return ret;
6314 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6315 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6317 if (cValues == 0) /* empty key */
6319 r = RegCloseKey (hkSubKey);
6320 if (r != ERROR_SUCCESS)
6321 WARN ("RegCloseKey returned %i\n", r);
6322 *pcbEnumValues = *pnEnumValues = 0;
6323 return ERROR_SUCCESS;
6326 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6328 hHeap = GetProcessHeap ();
6329 if (hHeap == NULL)
6331 ERR ("GetProcessHeap failed\n");
6332 r = RegCloseKey (hkSubKey);
6333 if (r != ERROR_SUCCESS)
6334 WARN ("RegCloseKey returned %i\n", r);
6335 return ERROR_OUTOFMEMORY;
6338 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6339 if (lpValueName == NULL)
6341 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6342 r = RegCloseKey (hkSubKey);
6343 if (r != ERROR_SUCCESS)
6344 WARN ("RegCloseKey returned %i\n", r);
6345 return ERROR_OUTOFMEMORY;
6348 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6349 if (lpValue == NULL)
6351 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6352 if (HeapFree (hHeap, 0, lpValueName) == 0)
6353 WARN ("HeapFree failed with code %i\n", GetLastError ());
6354 r = RegCloseKey (hkSubKey);
6355 if (r != ERROR_SUCCESS)
6356 WARN ("RegCloseKey returned %i\n", r);
6357 return ERROR_OUTOFMEMORY;
6360 TRACE ("pass 1: calculating buffer required for all names and values\n");
6362 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6364 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6366 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6368 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6369 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6370 NULL, NULL, lpValue, &cbValueLen);
6371 if (ret != ERROR_SUCCESS)
6373 if (HeapFree (hHeap, 0, lpValue) == 0)
6374 WARN ("HeapFree failed with code %i\n", GetLastError ());
6375 if (HeapFree (hHeap, 0, lpValueName) == 0)
6376 WARN ("HeapFree failed with code %i\n", GetLastError ());
6377 r = RegCloseKey (hkSubKey);
6378 if (r != ERROR_SUCCESS)
6379 WARN ("RegCloseKey returned %i\n", r);
6380 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6381 return ret;
6384 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6385 debugstr_w (lpValueName), dwIndex,
6386 cbValueNameLen + 1, cbValueLen);
6388 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6389 cbBufSize += cbValueLen;
6392 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6394 *pcbEnumValues = cbBufSize;
6395 *pnEnumValues = cValues;
6397 if (cbEnumValues < cbBufSize) /* buffer too small */
6399 if (HeapFree (hHeap, 0, lpValue) == 0)
6400 WARN ("HeapFree failed with code %i\n", GetLastError ());
6401 if (HeapFree (hHeap, 0, lpValueName) == 0)
6402 WARN ("HeapFree failed with code %i\n", GetLastError ());
6403 r = RegCloseKey (hkSubKey);
6404 if (r != ERROR_SUCCESS)
6405 WARN ("RegCloseKey returned %i\n", r);
6406 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6407 return ERROR_MORE_DATA;
6410 TRACE ("pass 2: copying all names and values to buffer\n");
6412 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6413 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6415 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6417 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6418 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6419 NULL, &dwType, lpValue, &cbValueLen);
6420 if (ret != ERROR_SUCCESS)
6422 if (HeapFree (hHeap, 0, lpValue) == 0)
6423 WARN ("HeapFree failed with code %i\n", GetLastError ());
6424 if (HeapFree (hHeap, 0, lpValueName) == 0)
6425 WARN ("HeapFree failed with code %i\n", GetLastError ());
6426 r = RegCloseKey (hkSubKey);
6427 if (r != ERROR_SUCCESS)
6428 WARN ("RegCloseKey returned %i\n", r);
6429 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6430 return ret;
6433 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6434 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6435 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6436 pEnumValues += cbValueNameLen;
6438 /* return # of *bytes* (including trailing \0), not # of chars */
6439 ppev[dwIndex].cbValueName = cbValueNameLen;
6441 ppev[dwIndex].dwType = dwType;
6443 memcpy (pEnumValues, lpValue, cbValueLen);
6444 ppev[dwIndex].pData = pEnumValues;
6445 pEnumValues += cbValueLen;
6447 ppev[dwIndex].cbData = cbValueLen;
6449 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6450 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6453 if (HeapFree (hHeap, 0, lpValue) == 0)
6455 ret = GetLastError ();
6456 ERR ("HeapFree failed with code %i\n", ret);
6457 if (HeapFree (hHeap, 0, lpValueName) == 0)
6458 WARN ("HeapFree failed with code %i\n", GetLastError ());
6459 r = RegCloseKey (hkSubKey);
6460 if (r != ERROR_SUCCESS)
6461 WARN ("RegCloseKey returned %i\n", r);
6462 return ret;
6465 if (HeapFree (hHeap, 0, lpValueName) == 0)
6467 ret = GetLastError ();
6468 ERR ("HeapFree failed with code %i\n", ret);
6469 r = RegCloseKey (hkSubKey);
6470 if (r != ERROR_SUCCESS)
6471 WARN ("RegCloseKey returned %i\n", r);
6472 return ret;
6475 ret = RegCloseKey (hkSubKey);
6476 if (ret != ERROR_SUCCESS)
6478 ERR ("RegCloseKey returned %i\n", ret);
6479 return ret;
6482 return ERROR_SUCCESS;
6485 /*******************************************************************************
6486 * EnumPrinterDataExA [WINSPOOL.@]
6488 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6489 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6490 * what Windows 2000 SP1 does.
6493 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6494 LPBYTE pEnumValues, DWORD cbEnumValues,
6495 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6497 INT len;
6498 LPWSTR pKeyNameW;
6499 DWORD ret, dwIndex, dwBufSize;
6500 HANDLE hHeap;
6501 LPSTR pBuffer;
6503 TRACE ("%p %s\n", hPrinter, pKeyName);
6505 if (pKeyName == NULL || *pKeyName == 0)
6506 return ERROR_INVALID_PARAMETER;
6508 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6509 if (len == 0)
6511 ret = GetLastError ();
6512 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6513 return ret;
6516 hHeap = GetProcessHeap ();
6517 if (hHeap == NULL)
6519 ERR ("GetProcessHeap failed\n");
6520 return ERROR_OUTOFMEMORY;
6523 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6524 if (pKeyNameW == NULL)
6526 ERR ("Failed to allocate %i bytes from process heap\n",
6527 (LONG)(len * sizeof (WCHAR)));
6528 return ERROR_OUTOFMEMORY;
6531 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6533 ret = GetLastError ();
6534 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6535 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6536 WARN ("HeapFree failed with code %i\n", GetLastError ());
6537 return ret;
6540 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6541 pcbEnumValues, pnEnumValues);
6542 if (ret != ERROR_SUCCESS)
6544 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6545 WARN ("HeapFree failed with code %i\n", GetLastError ());
6546 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6547 return ret;
6550 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6552 ret = GetLastError ();
6553 ERR ("HeapFree failed with code %i\n", ret);
6554 return ret;
6557 if (*pnEnumValues == 0) /* empty key */
6558 return ERROR_SUCCESS;
6560 dwBufSize = 0;
6561 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6563 PPRINTER_ENUM_VALUESW ppev =
6564 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6566 if (dwBufSize < ppev->cbValueName)
6567 dwBufSize = ppev->cbValueName;
6569 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6570 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6571 dwBufSize = ppev->cbData;
6574 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6576 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6577 if (pBuffer == NULL)
6579 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6580 return ERROR_OUTOFMEMORY;
6583 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6585 PPRINTER_ENUM_VALUESW ppev =
6586 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6588 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6589 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6590 NULL);
6591 if (len == 0)
6593 ret = GetLastError ();
6594 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6595 if (HeapFree (hHeap, 0, pBuffer) == 0)
6596 WARN ("HeapFree failed with code %i\n", GetLastError ());
6597 return ret;
6600 memcpy (ppev->pValueName, pBuffer, len);
6602 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6604 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6605 ppev->dwType != REG_MULTI_SZ)
6606 continue;
6608 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6609 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6610 if (len == 0)
6612 ret = GetLastError ();
6613 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6614 if (HeapFree (hHeap, 0, pBuffer) == 0)
6615 WARN ("HeapFree failed with code %i\n", GetLastError ());
6616 return ret;
6619 memcpy (ppev->pData, pBuffer, len);
6621 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6622 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6625 if (HeapFree (hHeap, 0, pBuffer) == 0)
6627 ret = GetLastError ();
6628 ERR ("HeapFree failed with code %i\n", ret);
6629 return ret;
6632 return ERROR_SUCCESS;
6635 /******************************************************************************
6636 * AbortPrinter (WINSPOOL.@)
6638 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6640 FIXME("(%p), stub!\n", hPrinter);
6641 return TRUE;
6644 /******************************************************************************
6645 * AddPortA (WINSPOOL.@)
6647 * See AddPortW.
6650 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6652 LPWSTR nameW = NULL;
6653 LPWSTR monitorW = NULL;
6654 DWORD len;
6655 BOOL res;
6657 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6659 if (pName) {
6660 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6661 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6662 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6665 if (pMonitorName) {
6666 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6667 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6668 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6670 res = AddPortW(nameW, hWnd, monitorW);
6671 HeapFree(GetProcessHeap(), 0, nameW);
6672 HeapFree(GetProcessHeap(), 0, monitorW);
6673 return res;
6676 /******************************************************************************
6677 * AddPortW (WINSPOOL.@)
6679 * Add a Port for a specific Monitor
6681 * PARAMS
6682 * pName [I] Servername or NULL (local Computer)
6683 * hWnd [I] Handle to parent Window for the Dialog-Box
6684 * pMonitorName [I] Name of the Monitor that manage the Port
6686 * RETURNS
6687 * Success: TRUE
6688 * Failure: FALSE
6691 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6693 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6695 if ((backend == NULL) && !load_backend()) return FALSE;
6697 if (!pMonitorName) {
6698 SetLastError(RPC_X_NULL_REF_POINTER);
6699 return FALSE;
6702 return backend->fpAddPort(pName, hWnd, pMonitorName);
6705 /******************************************************************************
6706 * AddPortExA (WINSPOOL.@)
6708 * See AddPortExW.
6711 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6713 PORT_INFO_2W pi2W;
6714 PORT_INFO_2A * pi2A;
6715 LPWSTR nameW = NULL;
6716 LPWSTR monitorW = NULL;
6717 DWORD len;
6718 BOOL res;
6720 pi2A = (PORT_INFO_2A *) pBuffer;
6722 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6723 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6725 if ((level < 1) || (level > 2)) {
6726 SetLastError(ERROR_INVALID_LEVEL);
6727 return FALSE;
6730 if (!pi2A) {
6731 SetLastError(ERROR_INVALID_PARAMETER);
6732 return FALSE;
6735 if (pName) {
6736 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6737 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6738 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6741 if (pMonitorName) {
6742 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6743 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6744 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6747 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6749 if (pi2A->pPortName) {
6750 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6751 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6752 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6755 if (level > 1) {
6756 if (pi2A->pMonitorName) {
6757 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6758 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6759 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6762 if (pi2A->pDescription) {
6763 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6764 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6765 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6767 pi2W.fPortType = pi2A->fPortType;
6768 pi2W.Reserved = pi2A->Reserved;
6771 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6773 HeapFree(GetProcessHeap(), 0, nameW);
6774 HeapFree(GetProcessHeap(), 0, monitorW);
6775 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6776 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6777 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6778 return res;
6782 /******************************************************************************
6783 * AddPortExW (WINSPOOL.@)
6785 * Add a Port for a specific Monitor, without presenting a user interface
6787 * PARAMS
6788 * pName [I] Servername or NULL (local Computer)
6789 * level [I] Structure-Level (1 or 2) for pBuffer
6790 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6791 * pMonitorName [I] Name of the Monitor that manage the Port
6793 * RETURNS
6794 * Success: TRUE
6795 * Failure: FALSE
6798 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6800 PORT_INFO_2W * pi2;
6802 pi2 = (PORT_INFO_2W *) pBuffer;
6804 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6805 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6806 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6807 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6809 if ((backend == NULL) && !load_backend()) return FALSE;
6811 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6812 SetLastError(ERROR_INVALID_PARAMETER);
6813 return FALSE;
6816 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6819 /******************************************************************************
6820 * AddPrinterConnectionA (WINSPOOL.@)
6822 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6824 FIXME("%s\n", debugstr_a(pName));
6825 return FALSE;
6828 /******************************************************************************
6829 * AddPrinterConnectionW (WINSPOOL.@)
6831 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6833 FIXME("%s\n", debugstr_w(pName));
6834 return FALSE;
6837 /******************************************************************************
6838 * AddPrinterDriverExW (WINSPOOL.@)
6840 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6842 * PARAMS
6843 * pName [I] Servername or NULL (local Computer)
6844 * level [I] Level for the supplied DRIVER_INFO_*W struct
6845 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6846 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6848 * RESULTS
6849 * Success: TRUE
6850 * Failure: FALSE
6853 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6855 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6857 if ((backend == NULL) && !load_backend()) return FALSE;
6859 if (level < 2 || level == 5 || level == 7 || level > 8) {
6860 SetLastError(ERROR_INVALID_LEVEL);
6861 return FALSE;
6864 if (!pDriverInfo) {
6865 SetLastError(ERROR_INVALID_PARAMETER);
6866 return FALSE;
6869 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6872 /******************************************************************************
6873 * AddPrinterDriverExA (WINSPOOL.@)
6875 * See AddPrinterDriverExW.
6878 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6880 DRIVER_INFO_8A *diA;
6881 DRIVER_INFO_8W diW;
6882 LPWSTR nameW = NULL;
6883 DWORD lenA;
6884 DWORD len;
6885 BOOL res = FALSE;
6887 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6889 diA = (DRIVER_INFO_8A *) pDriverInfo;
6890 ZeroMemory(&diW, sizeof(diW));
6892 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6893 SetLastError(ERROR_INVALID_LEVEL);
6894 return FALSE;
6897 if (diA == NULL) {
6898 SetLastError(ERROR_INVALID_PARAMETER);
6899 return FALSE;
6902 /* convert servername to unicode */
6903 if (pName) {
6904 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6905 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6906 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6909 /* common fields */
6910 diW.cVersion = diA->cVersion;
6912 if (diA->pName) {
6913 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6914 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6915 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6918 if (diA->pEnvironment) {
6919 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6920 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6921 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6924 if (diA->pDriverPath) {
6925 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6926 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6927 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6930 if (diA->pDataFile) {
6931 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6932 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6933 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6936 if (diA->pConfigFile) {
6937 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6938 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6939 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6942 if ((Level > 2) && diA->pDependentFiles) {
6943 lenA = multi_sz_lenA(diA->pDependentFiles);
6944 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6945 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6946 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6949 if ((Level > 2) && diA->pMonitorName) {
6950 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6951 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6952 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6955 if ((Level > 3) && diA->pDefaultDataType) {
6956 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6957 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6958 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6961 if ((Level > 3) && diA->pszzPreviousNames) {
6962 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6963 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6964 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6965 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6968 if ((Level > 5) && diA->pszMfgName) {
6969 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6970 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6971 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6974 if ((Level > 5) && diA->pszOEMUrl) {
6975 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6976 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6977 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6980 if ((Level > 5) && diA->pszHardwareID) {
6981 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6982 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6983 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6986 if ((Level > 5) && diA->pszProvider) {
6987 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6988 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6989 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6992 if (Level > 7) {
6993 FIXME("level %u is incomplete\n", Level);
6996 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6997 TRACE("got %u with %u\n", res, GetLastError());
6998 HeapFree(GetProcessHeap(), 0, nameW);
6999 HeapFree(GetProcessHeap(), 0, diW.pName);
7000 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
7001 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
7002 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
7003 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
7004 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
7005 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
7006 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
7007 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
7008 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
7009 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
7010 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
7011 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
7013 TRACE("=> %u with %u\n", res, GetLastError());
7014 return res;
7017 /******************************************************************************
7018 * ConfigurePortA (WINSPOOL.@)
7020 * See ConfigurePortW.
7023 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7025 LPWSTR nameW = NULL;
7026 LPWSTR portW = NULL;
7027 INT len;
7028 DWORD res;
7030 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7032 /* convert servername to unicode */
7033 if (pName) {
7034 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7035 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7036 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7039 /* convert portname to unicode */
7040 if (pPortName) {
7041 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7042 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7043 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7046 res = ConfigurePortW(nameW, hWnd, portW);
7047 HeapFree(GetProcessHeap(), 0, nameW);
7048 HeapFree(GetProcessHeap(), 0, portW);
7049 return res;
7052 /******************************************************************************
7053 * ConfigurePortW (WINSPOOL.@)
7055 * Display the Configuration-Dialog for a specific Port
7057 * PARAMS
7058 * pName [I] Servername or NULL (local Computer)
7059 * hWnd [I] Handle to parent Window for the Dialog-Box
7060 * pPortName [I] Name of the Port, that should be configured
7062 * RETURNS
7063 * Success: TRUE
7064 * Failure: FALSE
7067 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7070 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7072 if ((backend == NULL) && !load_backend()) return FALSE;
7074 if (!pPortName) {
7075 SetLastError(RPC_X_NULL_REF_POINTER);
7076 return FALSE;
7079 return backend->fpConfigurePort(pName, hWnd, pPortName);
7082 /******************************************************************************
7083 * ConnectToPrinterDlg (WINSPOOL.@)
7085 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7087 FIXME("%p %x\n", hWnd, Flags);
7088 return NULL;
7091 /******************************************************************************
7092 * DeletePrinterConnectionA (WINSPOOL.@)
7094 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7096 FIXME("%s\n", debugstr_a(pName));
7097 return TRUE;
7100 /******************************************************************************
7101 * DeletePrinterConnectionW (WINSPOOL.@)
7103 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7105 FIXME("%s\n", debugstr_w(pName));
7106 return TRUE;
7109 /******************************************************************************
7110 * DeletePrinterDriverExW (WINSPOOL.@)
7112 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7113 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7115 HKEY hkey_drivers;
7116 BOOL ret = FALSE;
7118 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7119 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7121 if(pName && pName[0])
7123 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7124 SetLastError(ERROR_INVALID_PARAMETER);
7125 return FALSE;
7128 if(dwDeleteFlag)
7130 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7131 SetLastError(ERROR_INVALID_PARAMETER);
7132 return FALSE;
7135 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7137 if(!hkey_drivers)
7139 ERR("Can't open drivers key\n");
7140 return FALSE;
7143 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7144 ret = TRUE;
7146 RegCloseKey(hkey_drivers);
7148 return ret;
7151 /******************************************************************************
7152 * DeletePrinterDriverExA (WINSPOOL.@)
7154 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7155 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7157 UNICODE_STRING NameW, EnvW, DriverW;
7158 BOOL ret;
7160 asciitounicode(&NameW, pName);
7161 asciitounicode(&EnvW, pEnvironment);
7162 asciitounicode(&DriverW, pDriverName);
7164 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7166 RtlFreeUnicodeString(&DriverW);
7167 RtlFreeUnicodeString(&EnvW);
7168 RtlFreeUnicodeString(&NameW);
7170 return ret;
7173 /******************************************************************************
7174 * DeletePrinterDataExW (WINSPOOL.@)
7176 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7177 LPCWSTR pValueName)
7179 FIXME("%p %s %s\n", hPrinter,
7180 debugstr_w(pKeyName), debugstr_w(pValueName));
7181 return ERROR_INVALID_PARAMETER;
7184 /******************************************************************************
7185 * DeletePrinterDataExA (WINSPOOL.@)
7187 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7188 LPCSTR pValueName)
7190 FIXME("%p %s %s\n", hPrinter,
7191 debugstr_a(pKeyName), debugstr_a(pValueName));
7192 return ERROR_INVALID_PARAMETER;
7195 /******************************************************************************
7196 * DeletePrintProcessorA (WINSPOOL.@)
7198 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7200 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7201 debugstr_a(pPrintProcessorName));
7202 return TRUE;
7205 /******************************************************************************
7206 * DeletePrintProcessorW (WINSPOOL.@)
7208 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7210 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7211 debugstr_w(pPrintProcessorName));
7212 return TRUE;
7215 /******************************************************************************
7216 * DeletePrintProvidorA (WINSPOOL.@)
7218 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7220 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7221 debugstr_a(pPrintProviderName));
7222 return TRUE;
7225 /******************************************************************************
7226 * DeletePrintProvidorW (WINSPOOL.@)
7228 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7230 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7231 debugstr_w(pPrintProviderName));
7232 return TRUE;
7235 /******************************************************************************
7236 * EnumFormsA (WINSPOOL.@)
7238 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7239 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7241 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7242 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7243 return FALSE;
7246 /******************************************************************************
7247 * EnumFormsW (WINSPOOL.@)
7249 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7250 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7252 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7253 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7254 return FALSE;
7257 /*****************************************************************************
7258 * EnumMonitorsA [WINSPOOL.@]
7260 * See EnumMonitorsW.
7263 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7264 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7266 BOOL res;
7267 LPBYTE bufferW = NULL;
7268 LPWSTR nameW = NULL;
7269 DWORD needed = 0;
7270 DWORD numentries = 0;
7271 INT len;
7273 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7274 cbBuf, pcbNeeded, pcReturned);
7276 /* convert servername to unicode */
7277 if (pName) {
7278 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7279 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7280 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7282 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7283 needed = cbBuf * sizeof(WCHAR);
7284 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7285 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7287 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7288 if (pcbNeeded) needed = *pcbNeeded;
7289 /* HeapReAlloc return NULL, when bufferW was NULL */
7290 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7291 HeapAlloc(GetProcessHeap(), 0, needed);
7293 /* Try again with the large Buffer */
7294 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7296 numentries = pcReturned ? *pcReturned : 0;
7297 needed = 0;
7299 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7300 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7302 if (res) {
7303 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7304 DWORD entrysize = 0;
7305 DWORD index;
7306 LPSTR ptr;
7307 LPMONITOR_INFO_2W mi2w;
7308 LPMONITOR_INFO_2A mi2a;
7310 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7311 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7313 /* First pass: calculate the size for all Entries */
7314 mi2w = (LPMONITOR_INFO_2W) bufferW;
7315 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7316 index = 0;
7317 while (index < numentries) {
7318 index++;
7319 needed += entrysize; /* MONITOR_INFO_?A */
7320 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7322 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7323 NULL, 0, NULL, NULL);
7324 if (Level > 1) {
7325 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7326 NULL, 0, NULL, NULL);
7327 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7328 NULL, 0, NULL, NULL);
7330 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7331 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7332 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7335 /* check for errors and quit on failure */
7336 if (cbBuf < needed) {
7337 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7338 res = FALSE;
7339 goto emA_cleanup;
7341 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7342 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7343 cbBuf -= len ; /* free Bytes in the user-Buffer */
7344 mi2w = (LPMONITOR_INFO_2W) bufferW;
7345 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7346 index = 0;
7347 /* Second Pass: Fill the User Buffer (if we have one) */
7348 while ((index < numentries) && pMonitors) {
7349 index++;
7350 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7351 mi2a->pName = ptr;
7352 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7353 ptr, cbBuf , NULL, NULL);
7354 ptr += len;
7355 cbBuf -= len;
7356 if (Level > 1) {
7357 mi2a->pEnvironment = ptr;
7358 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7359 ptr, cbBuf, NULL, NULL);
7360 ptr += len;
7361 cbBuf -= len;
7363 mi2a->pDLLName = ptr;
7364 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7365 ptr, cbBuf, NULL, NULL);
7366 ptr += len;
7367 cbBuf -= len;
7369 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7370 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7371 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7374 emA_cleanup:
7375 if (pcbNeeded) *pcbNeeded = needed;
7376 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7378 HeapFree(GetProcessHeap(), 0, nameW);
7379 HeapFree(GetProcessHeap(), 0, bufferW);
7381 TRACE("returning %d with %d (%d byte for %d entries)\n",
7382 (res), GetLastError(), needed, numentries);
7384 return (res);
7388 /*****************************************************************************
7389 * EnumMonitorsW [WINSPOOL.@]
7391 * Enumerate available Port-Monitors
7393 * PARAMS
7394 * pName [I] Servername or NULL (local Computer)
7395 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7396 * pMonitors [O] PTR to Buffer that receives the Result
7397 * cbBuf [I] Size of Buffer at pMonitors
7398 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7399 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7401 * RETURNS
7402 * Success: TRUE
7403 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7406 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7407 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7410 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7411 cbBuf, pcbNeeded, pcReturned);
7413 if ((backend == NULL) && !load_backend()) return FALSE;
7415 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7416 SetLastError(RPC_X_NULL_REF_POINTER);
7417 return FALSE;
7420 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7423 /******************************************************************************
7424 * SpoolerInit (WINSPOOL.@)
7426 * Initialize the Spooler
7428 * RETURNS
7429 * Success: TRUE
7430 * Failure: FALSE
7432 * NOTES
7433 * The function fails on windows, when the spooler service is not running
7436 BOOL WINAPI SpoolerInit(void)
7439 if ((backend == NULL) && !load_backend()) return FALSE;
7440 return TRUE;
7443 /******************************************************************************
7444 * XcvDataW (WINSPOOL.@)
7446 * Execute commands in the Printmonitor DLL
7448 * PARAMS
7449 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7450 * pszDataName [i] Name of the command to execute
7451 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7452 * cbInputData [i] Size in Bytes of Buffer at pInputData
7453 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7454 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7455 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7456 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7458 * RETURNS
7459 * Success: TRUE
7460 * Failure: FALSE
7462 * NOTES
7463 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7464 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7466 * Minimal List of commands, that a Printmonitor DLL should support:
7468 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7469 *| "AddPort" : Add a Port
7470 *| "DeletePort": Delete a Port
7472 * Many Printmonitors support additional commands. Examples for localspl.dll:
7473 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7474 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7477 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7478 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7479 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7481 opened_printer_t *printer;
7483 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7484 pInputData, cbInputData, pOutputData,
7485 cbOutputData, pcbOutputNeeded, pdwStatus);
7487 if ((backend == NULL) && !load_backend()) return FALSE;
7489 printer = get_opened_printer(hXcv);
7490 if (!printer || (!printer->backend_printer)) {
7491 SetLastError(ERROR_INVALID_HANDLE);
7492 return FALSE;
7495 if (!pcbOutputNeeded) {
7496 SetLastError(ERROR_INVALID_PARAMETER);
7497 return FALSE;
7500 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7501 SetLastError(RPC_X_NULL_REF_POINTER);
7502 return FALSE;
7505 *pcbOutputNeeded = 0;
7507 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7508 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7512 /*****************************************************************************
7513 * EnumPrinterDataA [WINSPOOL.@]
7516 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7517 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7518 DWORD cbData, LPDWORD pcbData )
7520 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7521 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7522 return ERROR_NO_MORE_ITEMS;
7525 /*****************************************************************************
7526 * EnumPrinterDataW [WINSPOOL.@]
7529 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7530 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7531 DWORD cbData, LPDWORD pcbData )
7533 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7534 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7535 return ERROR_NO_MORE_ITEMS;
7538 /*****************************************************************************
7539 * EnumPrinterKeyA [WINSPOOL.@]
7542 DWORD WINAPI EnumPrinterKeyA(HANDLE printer, const CHAR *key, CHAR *subkey, DWORD size, DWORD *needed)
7544 FIXME("%p %s %p %x %p\n", printer, debugstr_a(key), subkey, size, needed);
7545 return ERROR_CALL_NOT_IMPLEMENTED;
7548 /*****************************************************************************
7549 * EnumPrinterKeyW [WINSPOOL.@]
7552 DWORD WINAPI EnumPrinterKeyW(HANDLE printer, const WCHAR *key, WCHAR *subkey, DWORD size, DWORD *needed)
7554 FIXME("%p %s %p %x %p\n", printer, debugstr_w(key), subkey, size, needed);
7555 return ERROR_CALL_NOT_IMPLEMENTED;
7558 /*****************************************************************************
7559 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7562 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7563 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7564 LPDWORD pcbNeeded, LPDWORD pcReturned)
7566 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7567 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7568 pcbNeeded, pcReturned);
7569 return FALSE;
7572 /*****************************************************************************
7573 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7576 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7577 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7578 LPDWORD pcbNeeded, LPDWORD pcReturned)
7580 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7581 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7582 pcbNeeded, pcReturned);
7583 return FALSE;
7586 /*****************************************************************************
7587 * EnumPrintProcessorsA [WINSPOOL.@]
7589 * See EnumPrintProcessorsW.
7592 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7593 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7595 BOOL res;
7596 LPBYTE bufferW = NULL;
7597 LPWSTR nameW = NULL;
7598 LPWSTR envW = NULL;
7599 DWORD needed = 0;
7600 DWORD numentries = 0;
7601 INT len;
7603 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7604 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7606 /* convert names to unicode */
7607 if (pName) {
7608 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7609 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7610 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7612 if (pEnvironment) {
7613 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7614 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7615 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7618 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7619 needed = cbBuf * sizeof(WCHAR);
7620 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7621 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7623 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7624 if (pcbNeeded) needed = *pcbNeeded;
7625 /* HeapReAlloc return NULL, when bufferW was NULL */
7626 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7627 HeapAlloc(GetProcessHeap(), 0, needed);
7629 /* Try again with the large Buffer */
7630 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7632 numentries = pcReturned ? *pcReturned : 0;
7633 needed = 0;
7635 if (res) {
7636 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7637 DWORD index;
7638 LPSTR ptr;
7639 PPRINTPROCESSOR_INFO_1W ppiw;
7640 PPRINTPROCESSOR_INFO_1A ppia;
7642 /* First pass: calculate the size for all Entries */
7643 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7644 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7645 index = 0;
7646 while (index < numentries) {
7647 index++;
7648 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7649 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7651 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7652 NULL, 0, NULL, NULL);
7654 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7655 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7658 /* check for errors and quit on failure */
7659 if (cbBuf < needed) {
7660 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7661 res = FALSE;
7662 goto epp_cleanup;
7665 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7666 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7667 cbBuf -= len ; /* free Bytes in the user-Buffer */
7668 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7669 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7670 index = 0;
7671 /* Second Pass: Fill the User Buffer (if we have one) */
7672 while ((index < numentries) && pPPInfo) {
7673 index++;
7674 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7675 ppia->pName = ptr;
7676 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7677 ptr, cbBuf , NULL, NULL);
7678 ptr += len;
7679 cbBuf -= len;
7681 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7682 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7686 epp_cleanup:
7687 if (pcbNeeded) *pcbNeeded = needed;
7688 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7690 HeapFree(GetProcessHeap(), 0, nameW);
7691 HeapFree(GetProcessHeap(), 0, envW);
7692 HeapFree(GetProcessHeap(), 0, bufferW);
7694 TRACE("returning %d with %d (%d byte for %d entries)\n",
7695 (res), GetLastError(), needed, numentries);
7697 return (res);
7700 /*****************************************************************************
7701 * EnumPrintProcessorsW [WINSPOOL.@]
7703 * Enumerate available Print Processors
7705 * PARAMS
7706 * pName [I] Servername or NULL (local Computer)
7707 * pEnvironment [I] Printing-Environment or NULL (Default)
7708 * Level [I] Structure-Level (Only 1 is allowed)
7709 * pPPInfo [O] PTR to Buffer that receives the Result
7710 * cbBuf [I] Size of Buffer at pPPInfo
7711 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7712 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7714 * RETURNS
7715 * Success: TRUE
7716 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7719 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7720 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7723 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7724 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7726 if ((backend == NULL) && !load_backend()) return FALSE;
7728 if (!pcbNeeded || !pcReturned) {
7729 SetLastError(RPC_X_NULL_REF_POINTER);
7730 return FALSE;
7733 if (!pPPInfo && (cbBuf > 0)) {
7734 SetLastError(ERROR_INVALID_USER_BUFFER);
7735 return FALSE;
7738 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7739 cbBuf, pcbNeeded, pcReturned);
7742 /*****************************************************************************
7743 * ExtDeviceMode [WINSPOOL.@]
7746 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7747 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7748 DWORD fMode)
7750 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7751 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7752 debugstr_a(pProfile), fMode);
7753 return -1;
7756 /*****************************************************************************
7757 * FindClosePrinterChangeNotification [WINSPOOL.@]
7760 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7762 FIXME("Stub: %p\n", hChange);
7763 return TRUE;
7766 /*****************************************************************************
7767 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7770 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7771 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7773 FIXME("Stub: %p %x %x %p\n",
7774 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7775 return INVALID_HANDLE_VALUE;
7778 /*****************************************************************************
7779 * FindNextPrinterChangeNotification [WINSPOOL.@]
7782 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7783 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7785 FIXME("Stub: %p %p %p %p\n",
7786 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7787 return FALSE;
7790 /*****************************************************************************
7791 * FreePrinterNotifyInfo [WINSPOOL.@]
7794 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7796 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7797 return TRUE;
7800 /*****************************************************************************
7801 * string_to_buf
7803 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7804 * ansi depending on the unicode parameter.
7806 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7808 if(!str)
7810 *size = 0;
7811 return TRUE;
7814 if(unicode)
7816 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7817 if(*size <= cb)
7819 memcpy(ptr, str, *size);
7820 return TRUE;
7822 return FALSE;
7824 else
7826 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7827 if(*size <= cb)
7829 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7830 return TRUE;
7832 return FALSE;
7836 /*****************************************************************************
7837 * get_job_info_1
7839 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7840 LPDWORD pcbNeeded, BOOL unicode)
7842 DWORD size, left = cbBuf;
7843 BOOL space = (cbBuf > 0);
7844 LPBYTE ptr = buf;
7846 *pcbNeeded = 0;
7848 if(space)
7850 ji1->JobId = job->job_id;
7853 string_to_buf(job->document_title, ptr, left, &size, unicode);
7854 if(space && size <= left)
7856 ji1->pDocument = (LPWSTR)ptr;
7857 ptr += size;
7858 left -= size;
7860 else
7861 space = FALSE;
7862 *pcbNeeded += size;
7864 if (job->printer_name)
7866 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7867 if(space && size <= left)
7869 ji1->pPrinterName = (LPWSTR)ptr;
7870 ptr += size;
7871 left -= size;
7873 else
7874 space = FALSE;
7875 *pcbNeeded += size;
7878 return space;
7881 /*****************************************************************************
7882 * get_job_info_2
7884 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7885 LPDWORD pcbNeeded, BOOL unicode)
7887 DWORD size, left = cbBuf;
7888 DWORD shift;
7889 BOOL space = (cbBuf > 0);
7890 LPBYTE ptr = buf;
7891 LPDEVMODEA dmA = NULL;
7892 LPDEVMODEW devmode;
7894 *pcbNeeded = 0;
7896 if(space)
7898 ji2->JobId = job->job_id;
7901 string_to_buf(job->document_title, ptr, left, &size, unicode);
7902 if(space && size <= left)
7904 ji2->pDocument = (LPWSTR)ptr;
7905 ptr += size;
7906 left -= size;
7908 else
7909 space = FALSE;
7910 *pcbNeeded += size;
7912 if (job->printer_name)
7914 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7915 if(space && size <= left)
7917 ji2->pPrinterName = (LPWSTR)ptr;
7918 ptr += size;
7919 left -= size;
7921 else
7922 space = FALSE;
7923 *pcbNeeded += size;
7926 if (job->devmode)
7928 if (!unicode)
7930 dmA = DEVMODEdupWtoA(job->devmode);
7931 devmode = (LPDEVMODEW) dmA;
7932 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7934 else
7936 devmode = job->devmode;
7937 size = devmode->dmSize + devmode->dmDriverExtra;
7940 if (!devmode)
7941 FIXME("Can't convert DEVMODE W to A\n");
7942 else
7944 /* align DEVMODE to a DWORD boundary */
7945 shift = (4 - (*pcbNeeded & 3)) & 3;
7946 size += shift;
7948 if (size <= left)
7950 ptr += shift;
7951 memcpy(ptr, devmode, size-shift);
7952 ji2->pDevMode = (LPDEVMODEW)ptr;
7953 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7954 ptr += size-shift;
7955 left -= size;
7957 else
7958 space = FALSE;
7959 *pcbNeeded +=size;
7963 return space;
7966 /*****************************************************************************
7967 * get_job_info
7969 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7970 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7972 BOOL ret = FALSE;
7973 DWORD needed = 0, size;
7974 job_t *job;
7975 LPBYTE ptr = pJob;
7977 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7979 EnterCriticalSection(&printer_handles_cs);
7980 job = get_job(hPrinter, JobId);
7981 if(!job)
7982 goto end;
7984 switch(Level)
7986 case 1:
7987 size = sizeof(JOB_INFO_1W);
7988 if(cbBuf >= size)
7990 cbBuf -= size;
7991 ptr += size;
7992 memset(pJob, 0, size);
7994 else
7995 cbBuf = 0;
7996 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7997 needed += size;
7998 break;
8000 case 2:
8001 size = sizeof(JOB_INFO_2W);
8002 if(cbBuf >= size)
8004 cbBuf -= size;
8005 ptr += size;
8006 memset(pJob, 0, size);
8008 else
8009 cbBuf = 0;
8010 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
8011 needed += size;
8012 break;
8014 case 3:
8015 size = sizeof(JOB_INFO_3);
8016 if(cbBuf >= size)
8018 cbBuf -= size;
8019 memset(pJob, 0, size);
8020 ret = TRUE;
8022 else
8023 cbBuf = 0;
8024 needed = size;
8025 break;
8027 default:
8028 SetLastError(ERROR_INVALID_LEVEL);
8029 goto end;
8031 if(pcbNeeded)
8032 *pcbNeeded = needed;
8033 end:
8034 LeaveCriticalSection(&printer_handles_cs);
8035 return ret;
8038 /*****************************************************************************
8039 * GetJobA [WINSPOOL.@]
8042 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8043 DWORD cbBuf, LPDWORD pcbNeeded)
8045 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8048 /*****************************************************************************
8049 * GetJobW [WINSPOOL.@]
8052 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8053 DWORD cbBuf, LPDWORD pcbNeeded)
8055 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8058 /*****************************************************************************
8059 * schedule_pipe
8061 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8063 #ifdef HAVE_FORK
8064 char *unixname, *cmdA;
8065 DWORD len;
8066 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8067 BOOL ret = FALSE;
8068 char buf[1024];
8069 pid_t pid, wret;
8070 int status;
8072 if(!(unixname = wine_get_unix_file_name(filename)))
8073 return FALSE;
8075 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8076 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8077 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8079 TRACE("printing with: %s\n", cmdA);
8081 if((file_fd = open(unixname, O_RDONLY)) == -1)
8082 goto end;
8084 if (pipe(fds))
8086 ERR("pipe() failed!\n");
8087 goto end;
8090 if ((pid = fork()) == 0)
8092 close(0);
8093 dup2(fds[0], 0);
8094 close(fds[1]);
8096 /* reset signals that we previously set to SIG_IGN */
8097 signal(SIGPIPE, SIG_DFL);
8099 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8100 _exit(1);
8102 else if (pid == -1)
8104 ERR("fork() failed!\n");
8105 goto end;
8108 close(fds[0]);
8109 fds[0] = -1;
8110 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8111 write(fds[1], buf, no_read);
8113 close(fds[1]);
8114 fds[1] = -1;
8116 /* reap child */
8117 do {
8118 wret = waitpid(pid, &status, 0);
8119 } while (wret < 0 && errno == EINTR);
8120 if (wret < 0)
8122 ERR("waitpid() failed!\n");
8123 goto end;
8125 if (!WIFEXITED(status) || WEXITSTATUS(status))
8127 ERR("child process failed! %d\n", status);
8128 goto end;
8131 ret = TRUE;
8133 end:
8134 if(file_fd != -1) close(file_fd);
8135 if(fds[0] != -1) close(fds[0]);
8136 if(fds[1] != -1) close(fds[1]);
8138 HeapFree(GetProcessHeap(), 0, cmdA);
8139 HeapFree(GetProcessHeap(), 0, unixname);
8140 return ret;
8141 #else
8142 return FALSE;
8143 #endif
8146 /*****************************************************************************
8147 * schedule_lpr
8149 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8151 WCHAR *cmd;
8152 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8153 BOOL r;
8155 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8156 sprintfW(cmd, fmtW, printer_name);
8158 r = schedule_pipe(cmd, filename);
8160 HeapFree(GetProcessHeap(), 0, cmd);
8161 return r;
8164 #ifdef SONAME_LIBCUPS
8165 /*****************************************************************************
8166 * get_cups_jobs_ticket_options
8168 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8169 * The CUPS scheduler only looks for these in Print-File requests, and since
8170 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8171 * parsed.
8173 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8175 FILE *fp = fopen( file, "r" );
8176 char buf[257]; /* DSC max of 256 + '\0' */
8177 const char *ps_adobe = "%!PS-Adobe-";
8178 const char *cups_job = "%cupsJobTicket:";
8180 if (!fp) return num_options;
8181 if (!fgets( buf, sizeof(buf), fp )) goto end;
8182 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8183 while (fgets( buf, sizeof(buf), fp ))
8185 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8186 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8189 end:
8190 fclose( fp );
8191 return num_options;
8194 static int get_cups_default_options( const char *printer, int num_options, cups_option_t **options )
8196 cups_dest_t *dest;
8197 int i;
8199 if (!pcupsGetNamedDest) return num_options;
8201 dest = pcupsGetNamedDest( NULL, printer, NULL );
8202 if (!dest) return num_options;
8204 for (i = 0; i < dest->num_options; i++)
8206 if (!pcupsGetOption( dest->options[i].name, num_options, *options ))
8207 num_options = pcupsAddOption( dest->options[i].name, dest->options[i].value,
8208 num_options, options );
8211 pcupsFreeDests( 1, dest );
8212 return num_options;
8214 #endif
8216 /*****************************************************************************
8217 * schedule_cups
8219 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8221 #ifdef SONAME_LIBCUPS
8222 if(pcupsPrintFile)
8224 char *unixname, *queue, *unix_doc_title;
8225 DWORD len;
8226 BOOL ret;
8227 int num_options = 0, i;
8228 cups_option_t *options = NULL;
8230 if(!(unixname = wine_get_unix_file_name(filename)))
8231 return FALSE;
8233 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8234 queue = HeapAlloc(GetProcessHeap(), 0, len);
8235 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8237 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8238 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8239 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8241 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8242 num_options = get_cups_default_options( queue, num_options, &options );
8244 TRACE( "printing via cups with options:\n" );
8245 for (i = 0; i < num_options; i++)
8246 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8248 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8249 if (ret == 0 && pcupsLastErrorString)
8250 WARN("cupsPrintFile failed with error %s\n", debugstr_a(pcupsLastErrorString()));
8252 pcupsFreeOptions( num_options, options );
8254 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8255 HeapFree(GetProcessHeap(), 0, queue);
8256 HeapFree(GetProcessHeap(), 0, unixname);
8257 return ret;
8259 else
8260 #endif
8262 return schedule_lpr(printer_name, filename);
8266 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8268 LPWSTR filename;
8270 switch(msg)
8272 case WM_INITDIALOG:
8273 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8274 return TRUE;
8276 case WM_COMMAND:
8277 if(HIWORD(wparam) == BN_CLICKED)
8279 if(LOWORD(wparam) == IDOK)
8281 HANDLE hf;
8282 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8283 LPWSTR *output;
8285 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8286 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8288 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8290 WCHAR caption[200], message[200];
8291 int mb_ret;
8293 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8294 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8295 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8296 if(mb_ret == IDCANCEL)
8298 HeapFree(GetProcessHeap(), 0, filename);
8299 return TRUE;
8302 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8303 if(hf == INVALID_HANDLE_VALUE)
8305 WCHAR caption[200], message[200];
8307 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8308 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8309 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8310 HeapFree(GetProcessHeap(), 0, filename);
8311 return TRUE;
8313 CloseHandle(hf);
8314 DeleteFileW(filename);
8315 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8316 *output = filename;
8317 EndDialog(hwnd, IDOK);
8318 return TRUE;
8320 if(LOWORD(wparam) == IDCANCEL)
8322 EndDialog(hwnd, IDCANCEL);
8323 return TRUE;
8326 return FALSE;
8328 return FALSE;
8331 /*****************************************************************************
8332 * get_filename
8334 static BOOL get_filename(LPWSTR *filename)
8336 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8337 file_dlg_proc, (LPARAM)filename) == IDOK;
8340 /*****************************************************************************
8341 * schedule_file
8343 static BOOL schedule_file(LPCWSTR filename)
8345 LPWSTR output = NULL;
8347 if(get_filename(&output))
8349 BOOL r;
8350 TRACE("copy to %s\n", debugstr_w(output));
8351 r = CopyFileW(filename, output, FALSE);
8352 HeapFree(GetProcessHeap(), 0, output);
8353 return r;
8355 return FALSE;
8358 /*****************************************************************************
8359 * schedule_unixfile
8361 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8363 int in_fd, out_fd, no_read;
8364 char buf[1024];
8365 BOOL ret = FALSE;
8366 char *unixname, *outputA;
8367 DWORD len;
8369 if(!(unixname = wine_get_unix_file_name(filename)))
8370 return FALSE;
8372 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8373 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8374 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8376 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8377 in_fd = open(unixname, O_RDONLY);
8378 if(out_fd == -1 || in_fd == -1)
8379 goto end;
8381 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8382 write(out_fd, buf, no_read);
8384 ret = TRUE;
8385 end:
8386 if(in_fd != -1) close(in_fd);
8387 if(out_fd != -1) close(out_fd);
8388 HeapFree(GetProcessHeap(), 0, outputA);
8389 HeapFree(GetProcessHeap(), 0, unixname);
8390 return ret;
8393 /*****************************************************************************
8394 * ScheduleJob [WINSPOOL.@]
8397 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8399 opened_printer_t *printer;
8400 BOOL ret = FALSE;
8401 struct list *cursor, *cursor2;
8403 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8404 EnterCriticalSection(&printer_handles_cs);
8405 printer = get_opened_printer(hPrinter);
8406 if(!printer)
8407 goto end;
8409 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8411 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8412 HANDLE hf;
8414 if(job->job_id != dwJobID) continue;
8416 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8417 if(hf != INVALID_HANDLE_VALUE)
8419 PRINTER_INFO_5W *pi5 = NULL;
8420 LPWSTR portname = job->portname;
8421 DWORD needed;
8422 HKEY hkey;
8423 WCHAR output[1024];
8424 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8425 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8427 if (!portname)
8429 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8430 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8431 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8432 portname = pi5->pPortName;
8434 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8435 debugstr_w(portname));
8437 output[0] = 0;
8439 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8440 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8442 DWORD type, count = sizeof(output);
8443 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8444 RegCloseKey(hkey);
8446 if(output[0] == '|')
8448 ret = schedule_pipe(output + 1, job->filename);
8450 else if(output[0])
8452 ret = schedule_unixfile(output, job->filename);
8454 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8456 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8458 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8460 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8462 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8464 ret = schedule_file(job->filename);
8466 else if(isalpha(portname[0]) && portname[1] == ':')
8468 TRACE("copying to %s\n", debugstr_w(portname));
8469 ret = CopyFileW(job->filename, portname, FALSE);
8471 else
8473 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8475 HeapFree(GetProcessHeap(), 0, pi5);
8476 CloseHandle(hf);
8477 DeleteFileW(job->filename);
8479 list_remove(cursor);
8480 HeapFree(GetProcessHeap(), 0, job->document_title);
8481 HeapFree(GetProcessHeap(), 0, job->printer_name);
8482 HeapFree(GetProcessHeap(), 0, job->portname);
8483 HeapFree(GetProcessHeap(), 0, job->filename);
8484 HeapFree(GetProcessHeap(), 0, job->devmode);
8485 HeapFree(GetProcessHeap(), 0, job);
8486 break;
8488 end:
8489 LeaveCriticalSection(&printer_handles_cs);
8490 return ret;
8493 /*****************************************************************************
8494 * StartDocDlgA [WINSPOOL.@]
8496 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8498 UNICODE_STRING usBuffer;
8499 DOCINFOW docW;
8500 LPWSTR retW;
8501 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8502 LPSTR ret = NULL;
8504 docW.cbSize = sizeof(docW);
8505 if (doc->lpszDocName)
8507 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8508 if (!(docW.lpszDocName = docnameW)) return NULL;
8510 if (doc->lpszOutput)
8512 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8513 if (!(docW.lpszOutput = outputW)) return NULL;
8515 if (doc->lpszDatatype)
8517 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8518 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8520 docW.fwType = doc->fwType;
8522 retW = StartDocDlgW(hPrinter, &docW);
8524 if(retW)
8526 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8527 ret = HeapAlloc(GetProcessHeap(), 0, len);
8528 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8529 HeapFree(GetProcessHeap(), 0, retW);
8532 HeapFree(GetProcessHeap(), 0, datatypeW);
8533 HeapFree(GetProcessHeap(), 0, outputW);
8534 HeapFree(GetProcessHeap(), 0, docnameW);
8536 return ret;
8539 /*****************************************************************************
8540 * StartDocDlgW [WINSPOOL.@]
8542 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8543 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8544 * port is "FILE:". Also returns the full path if passed a relative path.
8546 * The caller should free the returned string from the process heap.
8548 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8550 LPWSTR ret = NULL;
8551 DWORD len, attr;
8553 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8555 PRINTER_INFO_5W *pi5;
8556 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8557 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8558 return NULL;
8559 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8560 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8561 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8563 HeapFree(GetProcessHeap(), 0, pi5);
8564 return NULL;
8566 HeapFree(GetProcessHeap(), 0, pi5);
8569 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8571 LPWSTR name;
8573 if (get_filename(&name))
8575 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8577 HeapFree(GetProcessHeap(), 0, name);
8578 return NULL;
8580 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8581 GetFullPathNameW(name, len, ret, NULL);
8582 HeapFree(GetProcessHeap(), 0, name);
8584 return ret;
8587 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8588 return NULL;
8590 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8591 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8593 attr = GetFileAttributesW(ret);
8594 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8596 HeapFree(GetProcessHeap(), 0, ret);
8597 ret = NULL;
8599 return ret;
8602 /*****************************************************************************
8603 * UploadPrinterDriverPackageA [WINSPOOL.@]
8605 HRESULT WINAPI UploadPrinterDriverPackageA( LPCSTR server, LPCSTR path, LPCSTR env,
8606 DWORD flags, HWND hwnd, LPSTR dst, PULONG dstlen )
8608 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server), debugstr_a(path), debugstr_a(env),
8609 flags, hwnd, dst, dstlen);
8610 return E_NOTIMPL;
8613 /*****************************************************************************
8614 * UploadPrinterDriverPackageW [WINSPOOL.@]
8616 HRESULT WINAPI UploadPrinterDriverPackageW( LPCWSTR server, LPCWSTR path, LPCWSTR env,
8617 DWORD flags, HWND hwnd, LPWSTR dst, PULONG dstlen )
8619 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server), debugstr_w(path), debugstr_w(env),
8620 flags, hwnd, dst, dstlen);
8621 return E_NOTIMPL;