wined3d: Add NVIDIA Geforce GTX 750 to device list.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blobe33b2572dfa2c2928ad04ed5a8a13f71bd55b70a
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include "wine/port.h"
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <stddef.h>
36 #include <errno.h>
37 #ifdef HAVE_SYS_WAIT_H
38 #include <sys/wait.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif
43 #include <signal.h>
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
46 #endif
48 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
49 #define GetCurrentProcess GetCurrentProcess_Mac
50 #define GetCurrentThread GetCurrentThread_Mac
51 #define LoadResource LoadResource_Mac
52 #define AnimatePalette AnimatePalette_Mac
53 #define EqualRgn EqualRgn_Mac
54 #define FillRgn FillRgn_Mac
55 #define FrameRgn FrameRgn_Mac
56 #define GetPixel GetPixel_Mac
57 #define InvertRgn InvertRgn_Mac
58 #define LineTo LineTo_Mac
59 #define OffsetRgn OffsetRgn_Mac
60 #define PaintRgn PaintRgn_Mac
61 #define Polygon Polygon_Mac
62 #define ResizePalette ResizePalette_Mac
63 #define SetRectRgn SetRectRgn_Mac
64 #define EqualRect EqualRect_Mac
65 #define FillRect FillRect_Mac
66 #define FrameRect FrameRect_Mac
67 #define GetCursor GetCursor_Mac
68 #define InvertRect InvertRect_Mac
69 #define OffsetRect OffsetRect_Mac
70 #define PtInRect PtInRect_Mac
71 #define SetCursor SetCursor_Mac
72 #define SetRect SetRect_Mac
73 #define ShowCursor ShowCursor_Mac
74 #define UnionRect UnionRect_Mac
75 #include <ApplicationServices/ApplicationServices.h>
76 #undef GetCurrentProcess
77 #undef GetCurrentThread
78 #undef LoadResource
79 #undef AnimatePalette
80 #undef EqualRgn
81 #undef FillRgn
82 #undef FrameRgn
83 #undef GetPixel
84 #undef InvertRgn
85 #undef LineTo
86 #undef OffsetRgn
87 #undef PaintRgn
88 #undef Polygon
89 #undef ResizePalette
90 #undef SetRectRgn
91 #undef EqualRect
92 #undef FillRect
93 #undef FrameRect
94 #undef GetCursor
95 #undef InvertRect
96 #undef OffsetRect
97 #undef PtInRect
98 #undef SetCursor
99 #undef SetRect
100 #undef ShowCursor
101 #undef UnionRect
102 #undef DPRINTF
103 #endif
105 #define NONAMELESSUNION
106 #define NONAMELESSSTRUCT
107 #include "wine/library.h"
108 #include "windef.h"
109 #include "winbase.h"
110 #include "winuser.h"
111 #include "winerror.h"
112 #include "winreg.h"
113 #include "wingdi.h"
114 #include "winspool.h"
115 #include "winternl.h"
116 #include "wine/windef16.h"
117 #include "wine/unicode.h"
118 #include "wine/debug.h"
119 #include "wine/list.h"
120 #include "winnls.h"
122 #include "ddk/winsplp.h"
123 #include "wspool.h"
125 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
127 /* ############################### */
129 static CRITICAL_SECTION printer_handles_cs;
130 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
132 0, 0, &printer_handles_cs,
133 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
134 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
136 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
138 /* ############################### */
140 typedef struct {
141 DWORD job_id;
142 HANDLE hf;
143 } started_doc_t;
145 typedef struct {
146 struct list jobs;
147 LONG ref;
148 } jobqueue_t;
150 typedef struct {
151 LPWSTR name;
152 LPWSTR printername;
153 HANDLE backend_printer;
154 jobqueue_t *queue;
155 started_doc_t *doc;
156 DEVMODEW *devmode;
157 } opened_printer_t;
159 typedef struct {
160 struct list entry;
161 DWORD job_id;
162 WCHAR *filename;
163 WCHAR *portname;
164 WCHAR *document_title;
165 WCHAR *printer_name;
166 LPDEVMODEW devmode;
167 } job_t;
170 typedef struct {
171 LPCWSTR envname;
172 LPCWSTR subdir;
173 DWORD driverversion;
174 LPCWSTR versionregpath;
175 LPCWSTR versionsubdir;
176 } printenv_t;
178 /* ############################### */
180 static opened_printer_t **printer_handles;
181 static UINT nb_printer_handles;
182 static LONG next_job_id = 1;
184 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
185 WORD fwCapability, LPSTR lpszOutput,
186 LPDEVMODEA lpdm );
187 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
188 LPSTR lpszDevice, LPSTR lpszPort,
189 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
190 DWORD fwMode );
192 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
193 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
194 'c','o','n','t','r','o','l','\\',
195 'P','r','i','n','t','\\',
196 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
197 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
199 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
200 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
201 'C','o','n','t','r','o','l','\\',
202 'P','r','i','n','t','\\',
203 'P','r','i','n','t','e','r','s',0};
205 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
207 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
208 'M','i','c','r','o','s','o','f','t','\\',
209 'W','i','n','d','o','w','s',' ','N','T','\\',
210 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
211 'W','i','n','d','o','w','s',0};
213 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
214 'M','i','c','r','o','s','o','f','t','\\',
215 'W','i','n','d','o','w','s',' ','N','T','\\',
216 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
217 'D','e','v','i','c','e','s',0};
219 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
220 'M','i','c','r','o','s','o','f','t','\\',
221 'W','i','n','d','o','w','s',' ','N','T','\\',
222 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
223 'P','o','r','t','s',0};
225 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
226 'M','i','c','r','o','s','o','f','t','\\',
227 'W','i','n','d','o','w','s',' ','N','T','\\',
228 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
229 'P','r','i','n','t','e','r','P','o','r','t','s',0};
231 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
232 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
233 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
234 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
235 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
236 static const WCHAR subdir_x64W[] = {'x','6','4',0};
237 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
238 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
239 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
240 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
241 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
243 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
245 static const WCHAR AttributesW[] = {'A','t','t','r','i','b','u','t','e','s',0};
246 static const WCHAR backslashW[] = {'\\',0};
247 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
248 'i','o','n',' ','F','i','l','e',0};
249 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
250 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
251 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
252 static const WCHAR Default_PriorityW[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
253 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
254 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
255 static const WCHAR dnsTimeoutW[] = {'d','n','s','T','i','m','e','o','u','t',0};
256 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
257 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
258 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
259 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
260 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
261 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
262 static const WCHAR NameW[] = {'N','a','m','e',0};
263 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
264 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
265 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
266 static const WCHAR PortW[] = {'P','o','r','t',0};
267 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
268 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
269 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
270 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
271 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
272 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
273 static const WCHAR PriorityW[] = {'P','r','i','o','r','i','t','y',0};
274 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
275 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
276 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
277 static const WCHAR StartTimeW[] = {'S','t','a','r','t','T','i','m','e',0};
278 static const WCHAR StatusW[] = {'S','t','a','t','u','s',0};
279 static const WCHAR txTimeoutW[] = {'t','x','T','i','m','e','o','u','t',0};
280 static const WCHAR UntilTimeW[] = {'U','n','t','i','l','T','i','m','e',0};
281 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
282 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
283 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
284 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
285 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
286 static WCHAR rawW[] = {'R','A','W',0};
287 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
288 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
289 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
290 static const WCHAR commaW[] = {',',0};
291 static WCHAR emptyStringW[] = {0};
293 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
295 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
296 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
297 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
299 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
300 'D','o','c','u','m','e','n','t',0};
302 static const WCHAR PPD_Overrides[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
303 static const WCHAR DefaultPageSize[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
305 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
306 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
307 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
308 0, sizeof(DRIVER_INFO_8W)};
311 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
312 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
313 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
314 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
315 sizeof(PRINTER_INFO_9W)};
317 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
318 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
319 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
321 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
323 /******************************************************************
324 * validate the user-supplied printing-environment [internal]
326 * PARAMS
327 * env [I] PTR to Environment-String or NULL
329 * RETURNS
330 * Failure: NULL
331 * Success: PTR to printenv_t
333 * NOTES
334 * An empty string is handled the same way as NULL.
335 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
339 static const printenv_t * validate_envW(LPCWSTR env)
341 const printenv_t *result = NULL;
342 unsigned int i;
344 TRACE("testing %s\n", debugstr_w(env));
345 if (env && env[0])
347 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
349 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
351 result = all_printenv[i];
352 break;
356 if (result == NULL) {
357 FIXME("unsupported Environment: %s\n", debugstr_w(env));
358 SetLastError(ERROR_INVALID_ENVIRONMENT);
360 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
362 else
364 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
366 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
368 return result;
372 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
373 if passed a NULL string. This returns NULLs to the result.
375 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
377 if ( (src) )
379 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
380 return usBufferPtr->Buffer;
382 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
383 return NULL;
386 static LPWSTR strdupW(LPCWSTR p)
388 LPWSTR ret;
389 DWORD len;
391 if(!p) return NULL;
392 len = (strlenW(p) + 1) * sizeof(WCHAR);
393 ret = HeapAlloc(GetProcessHeap(), 0, len);
394 memcpy(ret, p, len);
395 return ret;
398 static LPSTR strdupWtoA( LPCWSTR str )
400 LPSTR ret;
401 INT len;
403 if (!str) return NULL;
404 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
405 ret = HeapAlloc( GetProcessHeap(), 0, len );
406 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
407 return ret;
410 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
412 DEVMODEW *ret;
414 if (!dm) return NULL;
415 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
416 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
417 return ret;
420 /***********************************************************
421 * DEVMODEdupWtoA
422 * Creates an ansi copy of supplied devmode
424 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
426 LPDEVMODEA dmA;
427 DWORD size;
429 if (!dmW) return NULL;
430 size = dmW->dmSize - CCHDEVICENAME -
431 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
433 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
434 if (!dmA) return NULL;
436 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
437 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
439 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
441 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
442 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
444 else
446 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
447 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
448 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
449 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
451 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
454 dmA->dmSize = size;
455 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
456 return dmA;
460 /******************************************************************
461 * verify, that the filename is a local file
464 static inline BOOL is_local_file(LPWSTR name)
466 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
469 /* ################################ */
471 static int multi_sz_lenA(const char *str)
473 const char *ptr = str;
474 if(!str) return 0;
477 ptr += lstrlenA(ptr) + 1;
478 } while(*ptr);
480 return ptr - str + 1;
483 /*****************************************************************************
484 * get_dword_from_reg
486 * Return DWORD associated with name from hkey.
488 static DWORD get_dword_from_reg( HKEY hkey, const WCHAR *name )
490 DWORD sz = sizeof(DWORD), type, value = 0;
491 LONG ret;
493 ret = RegQueryValueExW( hkey, name, 0, &type, (LPBYTE)&value, &sz );
495 if (ret != ERROR_SUCCESS)
497 WARN( "Got ret = %d on name %s\n", ret, debugstr_w(name) );
498 return 0;
500 if (type != REG_DWORD)
502 ERR( "Got type %d\n", type );
503 return 0;
505 return value;
508 static inline DWORD set_reg_DWORD( HKEY hkey, const WCHAR *keyname, const DWORD value )
510 return RegSetValueExW( hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value) );
513 /******************************************************************
514 * get_opened_printer
515 * Get the pointer to the opened printer referred by the handle
517 static opened_printer_t *get_opened_printer(HANDLE hprn)
519 UINT_PTR idx = (UINT_PTR)hprn;
520 opened_printer_t *ret = NULL;
522 EnterCriticalSection(&printer_handles_cs);
524 if ((idx > 0) && (idx <= nb_printer_handles)) {
525 ret = printer_handles[idx - 1];
527 LeaveCriticalSection(&printer_handles_cs);
528 return ret;
531 /******************************************************************
532 * get_opened_printer_name
533 * Get the pointer to the opened printer name referred by the handle
535 static LPCWSTR get_opened_printer_name(HANDLE hprn)
537 opened_printer_t *printer = get_opened_printer(hprn);
538 if(!printer) return NULL;
539 return printer->name;
542 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
544 HKEY printers;
545 DWORD err;
547 *key = NULL;
548 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
549 if (err) return err;
551 err = RegOpenKeyW( printers, name, key );
552 if (err) err = ERROR_INVALID_PRINTER_NAME;
553 RegCloseKey( printers );
554 return err;
557 /******************************************************************
558 * WINSPOOL_GetOpenedPrinterRegKey
561 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
563 LPCWSTR name = get_opened_printer_name(hPrinter);
565 if(!name) return ERROR_INVALID_HANDLE;
566 return open_printer_reg_key( name, phkey );
569 static void
570 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
571 char qbuf[200];
573 /* If forcing, or no profile string entry for device yet, set the entry
575 * The always change entry if not WINEPS yet is discussable.
577 if (force ||
578 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
579 !strcmp(qbuf,"*") ||
580 !strstr(qbuf,"WINEPS.DRV")
582 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
583 HKEY hkey;
585 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
586 WriteProfileStringA("windows","device",buf);
587 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
588 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
589 RegCloseKey(hkey);
591 HeapFree(GetProcessHeap(),0,buf);
595 static BOOL add_printer_driver(const WCHAR *name, WCHAR *ppd)
597 DRIVER_INFO_3W di3;
599 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
600 di3.cVersion = 3;
601 di3.pName = (WCHAR*)name;
602 di3.pEnvironment = envname_x86W;
603 di3.pDriverPath = driver_nt;
604 di3.pDataFile = ppd;
605 di3.pConfigFile = driver_nt;
606 di3.pDefaultDataType = rawW;
608 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
609 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
611 di3.cVersion = 0;
612 di3.pEnvironment = envname_win40W;
613 di3.pDriverPath = driver_9x;
614 di3.pConfigFile = driver_9x;
615 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
616 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
618 return TRUE;
621 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
622 return FALSE;
625 static inline char *expand_env_string( char *str, DWORD type )
627 if (type == REG_EXPAND_SZ)
629 char *tmp;
630 DWORD needed = ExpandEnvironmentStringsA( str, NULL, 0 );
631 tmp = HeapAlloc( GetProcessHeap(), 0, needed );
632 if (tmp)
634 ExpandEnvironmentStringsA( str, tmp, needed );
635 HeapFree( GetProcessHeap(), 0, str );
636 return tmp;
639 return str;
642 static char *get_fallback_ppd_name( const char *printer_name )
644 static const WCHAR ppds_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
645 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
646 HKEY hkey;
647 DWORD needed, type;
648 char *ret = NULL;
650 if (RegOpenKeyW( HKEY_CURRENT_USER, ppds_key, &hkey ) == ERROR_SUCCESS )
652 const char *value_name = NULL;
654 if (RegQueryValueExA( hkey, printer_name, 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
655 value_name = printer_name;
656 else if (RegQueryValueExA( hkey, "generic", 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
657 value_name = "generic";
659 if (value_name)
661 ret = HeapAlloc( GetProcessHeap(), 0, needed );
662 if (!ret) return NULL;
663 RegQueryValueExA( hkey, value_name, 0, &type, (BYTE *)ret, &needed );
665 RegCloseKey( hkey );
666 if (ret) return expand_env_string( ret, type );
668 return NULL;
671 static BOOL copy_file( const char *src, const char *dst )
673 int fds[2] = {-1, -1}, num;
674 char buf[1024];
675 BOOL ret = FALSE;
677 fds[0] = open( src, O_RDONLY );
678 fds[1] = open( dst, O_CREAT | O_TRUNC | O_WRONLY, 0666 );
679 if (fds[0] == -1 || fds[1] == -1) goto fail;
681 while ((num = read( fds[0], buf, sizeof(buf) )) != 0)
683 if (num == -1) goto fail;
684 if (write( fds[1], buf, num ) != num) goto fail;
686 ret = TRUE;
688 fail:
689 if (fds[1] != -1) close( fds[1] );
690 if (fds[0] != -1) close( fds[0] );
691 return ret;
694 static BOOL get_internal_fallback_ppd( const WCHAR *ppd )
696 static const WCHAR typeW[] = {'P','P','D','F','I','L','E',0};
698 char *ptr, *end;
699 DWORD size, written;
700 HANDLE file;
701 BOOL ret;
702 HRSRC res = FindResourceW( WINSPOOL_hInstance, MAKEINTRESOURCEW(1), typeW );
704 if (!res || !(ptr = LoadResource( WINSPOOL_hInstance, res ))) return FALSE;
705 size = SizeofResource( WINSPOOL_hInstance, res );
706 end = memchr( ptr, 0, size ); /* resource file may contain additional nulls */
707 if (end) size = end - ptr;
708 file = CreateFileW( ppd, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0 );
709 if (file == INVALID_HANDLE_VALUE) return FALSE;
710 ret = WriteFile( file, ptr, size, &written, NULL ) && written == size;
711 CloseHandle( file );
712 if (ret) TRACE( "using internal fallback for %s\n", debugstr_w( ppd ));
713 else DeleteFileW( ppd );
714 return ret;
717 static BOOL get_fallback_ppd( const char *printer_name, const WCHAR *ppd )
719 char *dst, *src = get_fallback_ppd_name( printer_name );
720 BOOL ret = FALSE;
722 if (!src) return get_internal_fallback_ppd( ppd );
724 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name), debugstr_w(ppd), debugstr_a(src) );
726 if (!(dst = wine_get_unix_file_name( ppd ))) goto fail;
728 if (symlink( src, dst ) == -1)
729 if (errno != ENOSYS || !copy_file( src, dst ))
730 goto fail;
732 ret = TRUE;
733 fail:
734 HeapFree( GetProcessHeap(), 0, dst );
735 HeapFree( GetProcessHeap(), 0, src );
736 return ret;
739 static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
741 static const WCHAR dot_ppd[] = {'.','p','p','d',0};
742 int len = (strlenW( dir ) + strlenW( file_name )) * sizeof(WCHAR) + sizeof(dot_ppd);
743 WCHAR *ppd = HeapAlloc( GetProcessHeap(), 0, len );
745 if (!ppd) return NULL;
746 strcpyW( ppd, dir );
747 strcatW( ppd, file_name );
748 strcatW( ppd, dot_ppd );
750 return ppd;
753 static WCHAR *get_ppd_dir( void )
755 static const WCHAR wine_ppds[] = {'w','i','n','e','_','p','p','d','s','\\',0};
756 DWORD len;
757 WCHAR *dir, tmp_path[MAX_PATH];
758 BOOL res;
760 len = GetTempPathW( sizeof(tmp_path) / sizeof(tmp_path[0]), tmp_path );
761 if (!len) return NULL;
762 dir = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
763 if (!dir) return NULL;
765 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
766 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
767 res = CreateDirectoryW( dir, NULL );
768 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
770 HeapFree( GetProcessHeap(), 0, dir );
771 dir = NULL;
773 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
774 return dir;
777 static void unlink_ppd( const WCHAR *ppd )
779 char *unix_name = wine_get_unix_file_name( ppd );
780 unlink( unix_name );
781 HeapFree( GetProcessHeap(), 0, unix_name );
784 #ifdef SONAME_LIBCUPS
786 static void *cupshandle;
788 #define CUPS_FUNCS \
789 DO_FUNC(cupsAddOption); \
790 DO_FUNC(cupsFreeDests); \
791 DO_FUNC(cupsFreeOptions); \
792 DO_FUNC(cupsGetDests); \
793 DO_FUNC(cupsGetOption); \
794 DO_FUNC(cupsGetPPD); \
795 DO_FUNC(cupsParseOptions); \
796 DO_FUNC(cupsPrintFile)
797 #define CUPS_OPT_FUNCS \
798 DO_FUNC(cupsGetNamedDest); \
799 DO_FUNC(cupsGetPPD3)
801 #define DO_FUNC(f) static typeof(f) *p##f
802 CUPS_FUNCS;
803 #undef DO_FUNC
804 static cups_dest_t * (*pcupsGetNamedDest)(http_t *, const char *, const char *);
805 static http_status_t (*pcupsGetPPD3)(http_t *, const char *, time_t *, char *, size_t);
807 static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name,
808 time_t *modtime, char *buffer,
809 size_t bufsize )
811 const char *ppd;
813 if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
815 if (!pcupsGetPPD) return HTTP_NOT_FOUND;
817 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
819 *modtime = 0;
820 ppd = pcupsGetPPD( name );
822 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
824 if (!ppd) return HTTP_NOT_FOUND;
826 if (rename( ppd, buffer ) == -1)
828 BOOL res = copy_file( ppd, buffer );
829 unlink( ppd );
830 if (!res) return HTTP_NOT_FOUND;
832 return HTTP_OK;
835 static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
837 time_t modtime = 0;
838 http_status_t http_status;
839 char *unix_name = wine_get_unix_file_name( ppd );
841 TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
843 if (!unix_name) return FALSE;
845 http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
846 unix_name, strlen( unix_name ) + 1 );
848 if (http_status != HTTP_OK) unlink( unix_name );
849 HeapFree( GetProcessHeap(), 0, unix_name );
851 if (http_status == HTTP_OK) return TRUE;
853 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
854 debugstr_a(printer_name), http_status );
855 return get_fallback_ppd( printer_name, ppd );
858 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
860 const char *value;
861 WCHAR *ret;
862 int len;
864 value = pcupsGetOption( name, num_options, options );
865 if (!value) return NULL;
867 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
868 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
869 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
871 return ret;
874 static cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
876 WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
877 cups_ptype_t ret = 0;
879 if (type && *type)
881 ret = (cups_ptype_t)strtoulW( type, &end, 10 );
882 if (*end) ret = 0;
884 HeapFree( GetProcessHeap(), 0, type );
885 return ret;
888 static void load_cups(void)
890 cupshandle = wine_dlopen( SONAME_LIBCUPS, RTLD_NOW, NULL, 0 );
891 if (!cupshandle) return;
893 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
895 #define DO_FUNC(x) \
896 p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); \
897 if (!p##x) \
899 ERR("failed to load symbol %s\n", #x); \
900 cupshandle = NULL; \
901 return; \
903 CUPS_FUNCS;
904 #undef DO_FUNC
905 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 )
906 CUPS_OPT_FUNCS;
907 #undef DO_FUNC
910 static BOOL CUPS_LoadPrinters(void)
912 int i, nrofdests;
913 BOOL hadprinter = FALSE, haddefault = FALSE;
914 cups_dest_t *dests;
915 PRINTER_INFO_2W pi2;
916 WCHAR *port, *ppd_dir = NULL, *ppd;
917 HKEY hkeyPrinter, hkeyPrinters;
918 WCHAR nameW[MAX_PATH];
919 HANDLE added_printer;
920 cups_ptype_t printer_type;
922 if (!cupshandle) return FALSE;
924 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
925 ERROR_SUCCESS) {
926 ERR("Can't create Printers key\n");
927 return FALSE;
930 nrofdests = pcupsGetDests(&dests);
931 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
932 for (i=0;i<nrofdests;i++) {
933 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
934 printer_type = get_cups_printer_type( dests + i );
936 TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
938 if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
940 TRACE( "skipping scanner-only device\n" );
941 continue;
944 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
945 lstrcpyW(port, CUPS_Port);
946 lstrcatW(port, nameW);
948 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
949 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
950 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
951 and continue */
952 TRACE("Printer already exists\n");
953 /* overwrite old LPR:* port */
954 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
955 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
956 /* flag that the PPD file should be checked for an update */
957 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
958 RegCloseKey(hkeyPrinter);
959 } else {
960 BOOL added_driver = FALSE;
962 if (!ppd_dir) ppd_dir = get_ppd_dir();
963 ppd = get_ppd_filename( ppd_dir, nameW );
964 if (get_cups_ppd( dests[i].name, ppd ))
966 added_driver = add_printer_driver( nameW, ppd );
967 unlink_ppd( ppd );
969 HeapFree( GetProcessHeap(), 0, ppd );
970 if (!added_driver)
972 HeapFree( GetProcessHeap(), 0, port );
973 continue;
976 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
977 pi2.pPrinterName = nameW;
978 pi2.pDatatype = rawW;
979 pi2.pPrintProcessor = WinPrintW;
980 pi2.pDriverName = nameW;
981 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
982 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
983 pi2.pPortName = port;
984 pi2.pParameters = emptyStringW;
985 pi2.pShareName = emptyStringW;
986 pi2.pSepFile = emptyStringW;
988 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
989 if (added_printer) ClosePrinter( added_printer );
990 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
991 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
993 HeapFree( GetProcessHeap(), 0, pi2.pComment );
994 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
996 HeapFree( GetProcessHeap(), 0, port );
998 hadprinter = TRUE;
999 if (dests[i].is_default) {
1000 SetDefaultPrinterW(nameW);
1001 haddefault = TRUE;
1005 if (ppd_dir)
1007 RemoveDirectoryW( ppd_dir );
1008 HeapFree( GetProcessHeap(), 0, ppd_dir );
1011 if (hadprinter && !haddefault) {
1012 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
1013 SetDefaultPrinterW(nameW);
1015 pcupsFreeDests(nrofdests, dests);
1016 RegCloseKey(hkeyPrinters);
1017 return TRUE;
1020 #endif
1022 static char *get_queue_name( HANDLE printer, BOOL *cups )
1024 WCHAR *port, *name = NULL;
1025 DWORD err, needed, type;
1026 char *ret = NULL;
1027 HKEY key;
1029 *cups = FALSE;
1031 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1032 if (err) return NULL;
1033 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1034 if (err) goto end;
1035 port = HeapAlloc( GetProcessHeap(), 0, needed );
1036 if (!port) goto end;
1037 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1039 if (!strncmpW( port, CUPS_Port, sizeof(CUPS_Port) / sizeof(WCHAR) -1 ))
1041 name = port + sizeof(CUPS_Port) / sizeof(WCHAR) - 1;
1042 *cups = TRUE;
1044 else if (!strncmpW( port, LPR_Port, sizeof(LPR_Port) / sizeof(WCHAR) -1 ))
1045 name = port + sizeof(LPR_Port) / sizeof(WCHAR) - 1;
1046 if (name)
1048 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1049 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1050 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1052 HeapFree( GetProcessHeap(), 0, port );
1053 end:
1054 RegCloseKey( key );
1055 return ret;
1059 static void set_ppd_overrides( HANDLE printer )
1061 WCHAR *wstr = NULL;
1062 int size = 0;
1063 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1064 OSStatus status;
1065 PMPrintSession session = NULL;
1066 PMPageFormat format = NULL;
1067 PMPaper paper;
1068 CFStringRef paper_name;
1069 CFRange range;
1071 status = PMCreateSession( &session );
1072 if (status) goto end;
1074 status = PMCreatePageFormat( &format );
1075 if (status) goto end;
1077 status = PMSessionDefaultPageFormat( session, format );
1078 if (status) goto end;
1080 status = PMGetPageFormatPaper( format, &paper );
1081 if (status) goto end;
1083 status = PMPaperGetPPDPaperName( paper, &paper_name );
1084 if (status) goto end;
1086 range.location = 0;
1087 range.length = CFStringGetLength( paper_name );
1088 size = (range.length + 1) * sizeof(WCHAR);
1090 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1091 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1092 wstr[range.length] = 0;
1094 end:
1095 if (format) PMRelease( format );
1096 if (session) PMRelease( session );
1097 #endif
1099 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1100 HeapFree( GetProcessHeap(), 0, wstr );
1103 static BOOL update_driver( HANDLE printer )
1105 BOOL ret, is_cups;
1106 const WCHAR *name = get_opened_printer_name( printer );
1107 WCHAR *ppd_dir, *ppd;
1108 char *queue_name;
1110 if (!name) return FALSE;
1111 queue_name = get_queue_name( printer, &is_cups );
1112 if (!queue_name) return FALSE;
1114 ppd_dir = get_ppd_dir();
1115 ppd = get_ppd_filename( ppd_dir, name );
1117 #ifdef SONAME_LIBCUPS
1118 if (is_cups)
1119 ret = get_cups_ppd( queue_name, ppd );
1120 else
1121 #endif
1122 ret = get_fallback_ppd( queue_name, ppd );
1124 if (ret)
1126 TRACE( "updating driver %s\n", debugstr_w( name ) );
1127 ret = add_printer_driver( name, ppd );
1128 unlink_ppd( ppd );
1130 HeapFree( GetProcessHeap(), 0, ppd_dir );
1131 HeapFree( GetProcessHeap(), 0, ppd );
1132 HeapFree( GetProcessHeap(), 0, queue_name );
1134 set_ppd_overrides( printer );
1136 /* call into the driver to update the devmode */
1137 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1139 return ret;
1142 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1144 PRINTER_INFO_2A pinfo2a;
1145 const char *r;
1146 size_t name_len;
1147 char *e,*s,*name,*prettyname,*devname;
1148 BOOL ret = FALSE, set_default = FALSE;
1149 char *port = NULL, *env_default;
1150 HKEY hkeyPrinter, hkeyPrinters = NULL;
1151 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1152 HANDLE added_printer;
1154 while (isspace(*pent)) pent++;
1155 r = strchr(pent,':');
1156 if (r)
1157 name_len = r - pent;
1158 else
1159 name_len = strlen(pent);
1160 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1161 memcpy(name, pent, name_len);
1162 name[name_len] = '\0';
1163 if (r)
1164 pent = r;
1165 else
1166 pent = "";
1168 TRACE("name=%s entry=%s\n",name, pent);
1170 if(ispunct(*name)) { /* a tc entry, not a real printer */
1171 TRACE("skipping tc entry\n");
1172 goto end;
1175 if(strstr(pent,":server")) { /* server only version so skip */
1176 TRACE("skipping server entry\n");
1177 goto end;
1180 /* Determine whether this is a postscript printer. */
1182 ret = TRUE;
1183 env_default = getenv("PRINTER");
1184 prettyname = name;
1185 /* Get longest name, usually the one at the right for later display. */
1186 while((s=strchr(prettyname,'|'))) {
1187 *s = '\0';
1188 e = s;
1189 while(isspace(*--e)) *e = '\0';
1190 TRACE("\t%s\n", debugstr_a(prettyname));
1191 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1192 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1195 e = prettyname + strlen(prettyname);
1196 while(isspace(*--e)) *e = '\0';
1197 TRACE("\t%s\n", debugstr_a(prettyname));
1198 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1200 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1201 * if it is too long, we use it as comment below. */
1202 devname = prettyname;
1203 if (strlen(devname)>=CCHDEVICENAME-1)
1204 devname = name;
1205 if (strlen(devname)>=CCHDEVICENAME-1) {
1206 ret = FALSE;
1207 goto end;
1210 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1211 sprintf(port,"LPR:%s",name);
1213 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1214 ERROR_SUCCESS) {
1215 ERR("Can't create Printers key\n");
1216 ret = FALSE;
1217 goto end;
1220 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
1222 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1223 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1224 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1225 and continue */
1226 TRACE("Printer already exists\n");
1227 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1228 /* flag that the PPD file should be checked for an update */
1229 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1230 RegCloseKey(hkeyPrinter);
1231 } else {
1232 static CHAR data_type[] = "RAW",
1233 print_proc[] = "WinPrint",
1234 comment[] = "WINEPS Printer using LPR",
1235 params[] = "<parameters?>",
1236 share_name[] = "<share name?>",
1237 sep_file[] = "<sep file?>";
1238 BOOL added_driver = FALSE;
1240 if (!ppd_dir) ppd_dir = get_ppd_dir();
1241 ppd = get_ppd_filename( ppd_dir, devnameW );
1242 if (get_fallback_ppd( devname, ppd ))
1244 added_driver = add_printer_driver( devnameW, ppd );
1245 unlink_ppd( ppd );
1247 HeapFree( GetProcessHeap(), 0, ppd );
1248 if (!added_driver) goto end;
1250 memset(&pinfo2a,0,sizeof(pinfo2a));
1251 pinfo2a.pPrinterName = devname;
1252 pinfo2a.pDatatype = data_type;
1253 pinfo2a.pPrintProcessor = print_proc;
1254 pinfo2a.pDriverName = devname;
1255 pinfo2a.pComment = comment;
1256 pinfo2a.pLocation = prettyname;
1257 pinfo2a.pPortName = port;
1258 pinfo2a.pParameters = params;
1259 pinfo2a.pShareName = share_name;
1260 pinfo2a.pSepFile = sep_file;
1262 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1263 if (added_printer) ClosePrinter( added_printer );
1264 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1265 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1268 if (isfirst || set_default)
1269 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1271 end:
1272 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1273 if (ppd_dir)
1275 RemoveDirectoryW( ppd_dir );
1276 HeapFree( GetProcessHeap(), 0, ppd_dir );
1278 HeapFree(GetProcessHeap(), 0, port);
1279 HeapFree(GetProcessHeap(), 0, name);
1280 return ret;
1283 static BOOL
1284 PRINTCAP_LoadPrinters(void) {
1285 BOOL hadprinter = FALSE;
1286 char buf[200];
1287 FILE *f;
1288 char *pent = NULL;
1289 BOOL had_bash = FALSE;
1291 f = fopen("/etc/printcap","r");
1292 if (!f)
1293 return FALSE;
1295 while(fgets(buf,sizeof(buf),f)) {
1296 char *start, *end;
1298 end=strchr(buf,'\n');
1299 if (end) *end='\0';
1301 start = buf;
1302 while(isspace(*start)) start++;
1303 if(*start == '#' || *start == '\0')
1304 continue;
1306 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1307 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1308 HeapFree(GetProcessHeap(),0,pent);
1309 pent = NULL;
1312 if (end && *--end == '\\') {
1313 *end = '\0';
1314 had_bash = TRUE;
1315 } else
1316 had_bash = FALSE;
1318 if (pent) {
1319 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1320 strcat(pent,start);
1321 } else {
1322 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1323 strcpy(pent,start);
1327 if(pent) {
1328 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1329 HeapFree(GetProcessHeap(),0,pent);
1331 fclose(f);
1332 return hadprinter;
1335 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1337 if (value)
1338 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1339 (lstrlenW(value) + 1) * sizeof(WCHAR));
1340 else
1341 return ERROR_FILE_NOT_FOUND;
1344 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1346 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1347 DWORD ret = ERROR_FILE_NOT_FOUND;
1349 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1350 and we support these drivers. NT writes DEVMODEW so somehow
1351 we'll need to distinguish between these when we support NT
1352 drivers */
1354 if (dmA)
1356 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1357 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1358 HeapFree( GetProcessHeap(), 0, dmA );
1361 return ret;
1364 /******************************************************************
1365 * get_servername_from_name (internal)
1367 * for an external server, a copy of the serverpart from the full name is returned
1370 static LPWSTR get_servername_from_name(LPCWSTR name)
1372 LPWSTR server;
1373 LPWSTR ptr;
1374 WCHAR buffer[MAX_PATH];
1375 DWORD len;
1377 if (name == NULL) return NULL;
1378 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1380 server = strdupW(&name[2]); /* skip over both backslash */
1381 if (server == NULL) return NULL;
1383 /* strip '\' and the printername */
1384 ptr = strchrW(server, '\\');
1385 if (ptr) ptr[0] = '\0';
1387 TRACE("found %s\n", debugstr_w(server));
1389 len = sizeof(buffer)/sizeof(buffer[0]);
1390 if (GetComputerNameW(buffer, &len)) {
1391 if (lstrcmpW(buffer, server) == 0) {
1392 /* The requested Servername is our computername */
1393 HeapFree(GetProcessHeap(), 0, server);
1394 return NULL;
1397 return server;
1400 /******************************************************************
1401 * get_basename_from_name (internal)
1403 * skip over the serverpart from the full name
1406 static LPCWSTR get_basename_from_name(LPCWSTR name)
1408 if (name == NULL) return NULL;
1409 if ((name[0] == '\\') && (name[1] == '\\')) {
1410 /* skip over the servername and search for the following '\' */
1411 name = strchrW(&name[2], '\\');
1412 if ((name) && (name[1])) {
1413 /* found a separator ('\') followed by a name:
1414 skip over the separator and return the rest */
1415 name++;
1417 else
1419 /* no basename present (we found only a servername) */
1420 return NULL;
1423 return name;
1426 static void free_printer_entry( opened_printer_t *printer )
1428 /* the queue is shared, so don't free that here */
1429 HeapFree( GetProcessHeap(), 0, printer->printername );
1430 HeapFree( GetProcessHeap(), 0, printer->name );
1431 HeapFree( GetProcessHeap(), 0, printer->devmode );
1432 HeapFree( GetProcessHeap(), 0, printer );
1435 /******************************************************************
1436 * get_opened_printer_entry
1437 * Get the first place empty in the opened printer table
1439 * ToDo:
1440 * - pDefault is ignored
1442 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1444 UINT_PTR handle = nb_printer_handles, i;
1445 jobqueue_t *queue = NULL;
1446 opened_printer_t *printer = NULL;
1447 LPWSTR servername;
1448 LPCWSTR printername;
1450 if ((backend == NULL) && !load_backend()) return NULL;
1452 servername = get_servername_from_name(name);
1453 if (servername) {
1454 FIXME("server %s not supported\n", debugstr_w(servername));
1455 HeapFree(GetProcessHeap(), 0, servername);
1456 SetLastError(ERROR_INVALID_PRINTER_NAME);
1457 return NULL;
1460 printername = get_basename_from_name(name);
1461 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1463 /* an empty printername is invalid */
1464 if (printername && (!printername[0])) {
1465 SetLastError(ERROR_INVALID_PARAMETER);
1466 return NULL;
1469 EnterCriticalSection(&printer_handles_cs);
1471 for (i = 0; i < nb_printer_handles; i++)
1473 if (!printer_handles[i])
1475 if(handle == nb_printer_handles)
1476 handle = i;
1478 else
1480 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1481 queue = printer_handles[i]->queue;
1485 if (handle >= nb_printer_handles)
1487 opened_printer_t **new_array;
1488 if (printer_handles)
1489 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1490 (nb_printer_handles + 16) * sizeof(*new_array) );
1491 else
1492 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1493 (nb_printer_handles + 16) * sizeof(*new_array) );
1495 if (!new_array)
1497 handle = 0;
1498 goto end;
1500 printer_handles = new_array;
1501 nb_printer_handles += 16;
1504 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1506 handle = 0;
1507 goto end;
1510 /* get a printer handle from the backend */
1511 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1512 handle = 0;
1513 goto end;
1516 /* clone the base name. This is NULL for the printserver */
1517 printer->printername = strdupW(printername);
1519 /* clone the full name */
1520 printer->name = strdupW(name);
1521 if (name && (!printer->name)) {
1522 handle = 0;
1523 goto end;
1526 if (pDefault && pDefault->pDevMode)
1527 printer->devmode = dup_devmode( pDefault->pDevMode );
1529 if(queue)
1530 printer->queue = queue;
1531 else
1533 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1534 if (!printer->queue) {
1535 handle = 0;
1536 goto end;
1538 list_init(&printer->queue->jobs);
1539 printer->queue->ref = 0;
1541 InterlockedIncrement(&printer->queue->ref);
1543 printer_handles[handle] = printer;
1544 handle++;
1545 end:
1546 LeaveCriticalSection(&printer_handles_cs);
1547 if (!handle && printer) {
1548 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1549 free_printer_entry( printer );
1552 return (HANDLE)handle;
1555 static void old_printer_check( BOOL delete_phase )
1557 PRINTER_INFO_5W* pi;
1558 DWORD needed, type, num, delete, i, size;
1559 const DWORD one = 1;
1560 HKEY key;
1561 HANDLE hprn;
1563 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1564 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1566 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1567 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1568 for (i = 0; i < num; i++)
1570 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1571 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1572 continue;
1574 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1576 if (!delete_phase)
1578 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1579 RegCloseKey( key );
1581 else
1583 delete = 0;
1584 size = sizeof( delete );
1585 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1586 RegCloseKey( key );
1587 if (delete)
1589 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1590 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1592 DeletePrinter( hprn );
1593 ClosePrinter( hprn );
1595 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1599 HeapFree(GetProcessHeap(), 0, pi);
1602 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1603 'M','U','T','E','X','_','_','\0'};
1604 static HANDLE init_mutex;
1606 void WINSPOOL_LoadSystemPrinters(void)
1608 HKEY hkey, hkeyPrinters;
1609 DWORD needed, num, i;
1610 WCHAR PrinterName[256];
1611 BOOL done = FALSE;
1613 #ifdef SONAME_LIBCUPS
1614 load_cups();
1615 #endif
1617 /* FIXME: The init code should be moved to spoolsv.exe */
1618 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1619 if (!init_mutex)
1621 ERR( "Failed to create mutex\n" );
1622 return;
1624 if (GetLastError() == ERROR_ALREADY_EXISTS)
1626 WaitForSingleObject( init_mutex, INFINITE );
1627 ReleaseMutex( init_mutex );
1628 TRACE( "Init already done\n" );
1629 return;
1632 /* This ensures that all printer entries have a valid Name value. If causes
1633 problems later if they don't. If one is found to be missed we create one
1634 and set it equal to the name of the key */
1635 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1636 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1637 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1638 for(i = 0; i < num; i++) {
1639 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1640 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1641 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1642 set_reg_szW(hkey, NameW, PrinterName);
1644 RegCloseKey(hkey);
1649 RegCloseKey(hkeyPrinters);
1652 old_printer_check( FALSE );
1654 #ifdef SONAME_LIBCUPS
1655 done = CUPS_LoadPrinters();
1656 #endif
1658 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1659 PRINTCAP_LoadPrinters();
1661 old_printer_check( TRUE );
1663 ReleaseMutex( init_mutex );
1664 return;
1667 /******************************************************************
1668 * get_job
1670 * Get the pointer to the specified job.
1671 * Should hold the printer_handles_cs before calling.
1673 static job_t *get_job(HANDLE hprn, DWORD JobId)
1675 opened_printer_t *printer = get_opened_printer(hprn);
1676 job_t *job;
1678 if(!printer) return NULL;
1679 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1681 if(job->job_id == JobId)
1682 return job;
1684 return NULL;
1687 /***********************************************************
1688 * DEVMODEcpyAtoW
1690 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1692 BOOL Formname;
1693 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1694 DWORD size;
1696 Formname = (dmA->dmSize > off_formname);
1697 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1698 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1699 dmW->dmDeviceName, CCHDEVICENAME);
1700 if(!Formname) {
1701 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1702 dmA->dmSize - CCHDEVICENAME);
1703 } else {
1704 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1705 off_formname - CCHDEVICENAME);
1706 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1707 dmW->dmFormName, CCHFORMNAME);
1708 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1709 (off_formname + CCHFORMNAME));
1711 dmW->dmSize = size;
1712 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1713 dmA->dmDriverExtra);
1714 return dmW;
1717 /******************************************************************
1718 * convert_printerinfo_W_to_A [internal]
1721 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1722 DWORD level, DWORD outlen, DWORD numentries)
1724 DWORD id = 0;
1725 LPSTR ptr;
1726 INT len;
1728 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1730 len = pi_sizeof[level] * numentries;
1731 ptr = (LPSTR) out + len;
1732 outlen -= len;
1734 /* copy the numbers of all PRINTER_INFO_* first */
1735 memcpy(out, pPrintersW, len);
1737 while (id < numentries) {
1738 switch (level) {
1739 case 1:
1741 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1742 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1744 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1745 if (piW->pDescription) {
1746 piA->pDescription = ptr;
1747 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1748 ptr, outlen, NULL, NULL);
1749 ptr += len;
1750 outlen -= len;
1752 if (piW->pName) {
1753 piA->pName = ptr;
1754 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1755 ptr, outlen, NULL, NULL);
1756 ptr += len;
1757 outlen -= len;
1759 if (piW->pComment) {
1760 piA->pComment = ptr;
1761 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1762 ptr, outlen, NULL, NULL);
1763 ptr += len;
1764 outlen -= len;
1766 break;
1769 case 2:
1771 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1772 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1773 LPDEVMODEA dmA;
1775 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1776 if (piW->pServerName) {
1777 piA->pServerName = ptr;
1778 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1779 ptr, outlen, NULL, NULL);
1780 ptr += len;
1781 outlen -= len;
1783 if (piW->pPrinterName) {
1784 piA->pPrinterName = ptr;
1785 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1786 ptr, outlen, NULL, NULL);
1787 ptr += len;
1788 outlen -= len;
1790 if (piW->pShareName) {
1791 piA->pShareName = ptr;
1792 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1793 ptr, outlen, NULL, NULL);
1794 ptr += len;
1795 outlen -= len;
1797 if (piW->pPortName) {
1798 piA->pPortName = ptr;
1799 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1800 ptr, outlen, NULL, NULL);
1801 ptr += len;
1802 outlen -= len;
1804 if (piW->pDriverName) {
1805 piA->pDriverName = ptr;
1806 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1807 ptr, outlen, NULL, NULL);
1808 ptr += len;
1809 outlen -= len;
1811 if (piW->pComment) {
1812 piA->pComment = ptr;
1813 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1814 ptr, outlen, NULL, NULL);
1815 ptr += len;
1816 outlen -= len;
1818 if (piW->pLocation) {
1819 piA->pLocation = ptr;
1820 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1821 ptr, outlen, NULL, NULL);
1822 ptr += len;
1823 outlen -= len;
1826 dmA = DEVMODEdupWtoA(piW->pDevMode);
1827 if (dmA) {
1828 /* align DEVMODEA to a DWORD boundary */
1829 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1830 ptr += len;
1831 outlen -= len;
1833 piA->pDevMode = (LPDEVMODEA) ptr;
1834 len = dmA->dmSize + dmA->dmDriverExtra;
1835 memcpy(ptr, dmA, len);
1836 HeapFree(GetProcessHeap(), 0, dmA);
1838 ptr += len;
1839 outlen -= len;
1842 if (piW->pSepFile) {
1843 piA->pSepFile = ptr;
1844 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1845 ptr, outlen, NULL, NULL);
1846 ptr += len;
1847 outlen -= len;
1849 if (piW->pPrintProcessor) {
1850 piA->pPrintProcessor = ptr;
1851 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1852 ptr, outlen, NULL, NULL);
1853 ptr += len;
1854 outlen -= len;
1856 if (piW->pDatatype) {
1857 piA->pDatatype = ptr;
1858 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1859 ptr, outlen, NULL, NULL);
1860 ptr += len;
1861 outlen -= len;
1863 if (piW->pParameters) {
1864 piA->pParameters = ptr;
1865 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1866 ptr, outlen, NULL, NULL);
1867 ptr += len;
1868 outlen -= len;
1870 if (piW->pSecurityDescriptor) {
1871 piA->pSecurityDescriptor = NULL;
1872 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1874 break;
1877 case 4:
1879 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1880 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1882 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1884 if (piW->pPrinterName) {
1885 piA->pPrinterName = ptr;
1886 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1887 ptr, outlen, NULL, NULL);
1888 ptr += len;
1889 outlen -= len;
1891 if (piW->pServerName) {
1892 piA->pServerName = ptr;
1893 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1894 ptr, outlen, NULL, NULL);
1895 ptr += len;
1896 outlen -= len;
1898 break;
1901 case 5:
1903 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1904 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1906 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1908 if (piW->pPrinterName) {
1909 piA->pPrinterName = ptr;
1910 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1911 ptr, outlen, NULL, NULL);
1912 ptr += len;
1913 outlen -= len;
1915 if (piW->pPortName) {
1916 piA->pPortName = ptr;
1917 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1918 ptr, outlen, NULL, NULL);
1919 ptr += len;
1920 outlen -= len;
1922 break;
1925 case 6: /* 6A and 6W are the same structure */
1926 break;
1928 case 7:
1930 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1931 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1933 TRACE("(%u) #%u\n", level, id);
1934 if (piW->pszObjectGUID) {
1935 piA->pszObjectGUID = ptr;
1936 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1937 ptr, outlen, NULL, NULL);
1938 ptr += len;
1939 outlen -= len;
1941 break;
1944 case 8:
1945 case 9:
1947 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1948 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1949 LPDEVMODEA dmA;
1951 TRACE("(%u) #%u\n", level, id);
1952 dmA = DEVMODEdupWtoA(piW->pDevMode);
1953 if (dmA) {
1954 /* align DEVMODEA to a DWORD boundary */
1955 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1956 ptr += len;
1957 outlen -= len;
1959 piA->pDevMode = (LPDEVMODEA) ptr;
1960 len = dmA->dmSize + dmA->dmDriverExtra;
1961 memcpy(ptr, dmA, len);
1962 HeapFree(GetProcessHeap(), 0, dmA);
1964 ptr += len;
1965 outlen -= len;
1968 break;
1971 default:
1972 FIXME("for level %u\n", level);
1974 pPrintersW += pi_sizeof[level];
1975 out += pi_sizeof[level];
1976 id++;
1980 /******************************************************************
1981 * convert_driverinfo_W_to_A [internal]
1984 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1985 DWORD level, DWORD outlen, DWORD numentries)
1987 DWORD id = 0;
1988 LPSTR ptr;
1989 INT len;
1991 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1993 len = di_sizeof[level] * numentries;
1994 ptr = (LPSTR) out + len;
1995 outlen -= len;
1997 /* copy the numbers of all PRINTER_INFO_* first */
1998 memcpy(out, pDriversW, len);
2000 #define COPY_STRING(fld) \
2001 { if (diW->fld){ \
2002 diA->fld = ptr; \
2003 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
2004 ptr += len; outlen -= len;\
2006 #define COPY_MULTIZ_STRING(fld) \
2007 { LPWSTR p = diW->fld; if (p){ \
2008 diA->fld = ptr; \
2009 do {\
2010 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2011 ptr += len; outlen -= len; p += len;\
2013 while(len > 1 && outlen > 0); \
2016 while (id < numentries)
2018 switch (level)
2020 case 1:
2022 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
2023 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
2025 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2027 COPY_STRING(pName);
2028 break;
2030 case 2:
2032 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2033 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2035 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2037 COPY_STRING(pName);
2038 COPY_STRING(pEnvironment);
2039 COPY_STRING(pDriverPath);
2040 COPY_STRING(pDataFile);
2041 COPY_STRING(pConfigFile);
2042 break;
2044 case 3:
2046 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2047 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2049 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2051 COPY_STRING(pName);
2052 COPY_STRING(pEnvironment);
2053 COPY_STRING(pDriverPath);
2054 COPY_STRING(pDataFile);
2055 COPY_STRING(pConfigFile);
2056 COPY_STRING(pHelpFile);
2057 COPY_MULTIZ_STRING(pDependentFiles);
2058 COPY_STRING(pMonitorName);
2059 COPY_STRING(pDefaultDataType);
2060 break;
2062 case 4:
2064 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2065 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2067 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2069 COPY_STRING(pName);
2070 COPY_STRING(pEnvironment);
2071 COPY_STRING(pDriverPath);
2072 COPY_STRING(pDataFile);
2073 COPY_STRING(pConfigFile);
2074 COPY_STRING(pHelpFile);
2075 COPY_MULTIZ_STRING(pDependentFiles);
2076 COPY_STRING(pMonitorName);
2077 COPY_STRING(pDefaultDataType);
2078 COPY_MULTIZ_STRING(pszzPreviousNames);
2079 break;
2081 case 5:
2083 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2084 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2086 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2088 COPY_STRING(pName);
2089 COPY_STRING(pEnvironment);
2090 COPY_STRING(pDriverPath);
2091 COPY_STRING(pDataFile);
2092 COPY_STRING(pConfigFile);
2093 break;
2095 case 6:
2097 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2098 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2100 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2102 COPY_STRING(pName);
2103 COPY_STRING(pEnvironment);
2104 COPY_STRING(pDriverPath);
2105 COPY_STRING(pDataFile);
2106 COPY_STRING(pConfigFile);
2107 COPY_STRING(pHelpFile);
2108 COPY_MULTIZ_STRING(pDependentFiles);
2109 COPY_STRING(pMonitorName);
2110 COPY_STRING(pDefaultDataType);
2111 COPY_MULTIZ_STRING(pszzPreviousNames);
2112 COPY_STRING(pszMfgName);
2113 COPY_STRING(pszOEMUrl);
2114 COPY_STRING(pszHardwareID);
2115 COPY_STRING(pszProvider);
2116 break;
2118 case 8:
2120 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2121 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2123 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2125 COPY_STRING(pName);
2126 COPY_STRING(pEnvironment);
2127 COPY_STRING(pDriverPath);
2128 COPY_STRING(pDataFile);
2129 COPY_STRING(pConfigFile);
2130 COPY_STRING(pHelpFile);
2131 COPY_MULTIZ_STRING(pDependentFiles);
2132 COPY_STRING(pMonitorName);
2133 COPY_STRING(pDefaultDataType);
2134 COPY_MULTIZ_STRING(pszzPreviousNames);
2135 COPY_STRING(pszMfgName);
2136 COPY_STRING(pszOEMUrl);
2137 COPY_STRING(pszHardwareID);
2138 COPY_STRING(pszProvider);
2139 COPY_STRING(pszPrintProcessor);
2140 COPY_STRING(pszVendorSetup);
2141 COPY_MULTIZ_STRING(pszzColorProfiles);
2142 COPY_STRING(pszInfPath);
2143 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2144 break;
2148 default:
2149 FIXME("for level %u\n", level);
2152 pDriversW += di_sizeof[level];
2153 out += di_sizeof[level];
2154 id++;
2157 #undef COPY_STRING
2158 #undef COPY_MULTIZ_STRING
2162 /***********************************************************
2163 * printer_info_AtoW
2165 static void *printer_info_AtoW( const void *data, DWORD level )
2167 void *ret;
2168 UNICODE_STRING usBuffer;
2170 if (!data) return NULL;
2172 if (level < 1 || level > 9) return NULL;
2174 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2175 if (!ret) return NULL;
2177 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2179 switch (level)
2181 case 2:
2183 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2184 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2186 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2187 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2188 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2189 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2190 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2191 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2192 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2193 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2194 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2195 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2196 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2197 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2198 break;
2201 case 8:
2202 case 9:
2204 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2205 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2207 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2208 break;
2211 default:
2212 FIXME( "Unhandled level %d\n", level );
2213 HeapFree( GetProcessHeap(), 0, ret );
2214 return NULL;
2217 return ret;
2220 /***********************************************************
2221 * free_printer_info
2223 static void free_printer_info( void *data, DWORD level )
2225 if (!data) return;
2227 switch (level)
2229 case 2:
2231 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2233 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2234 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2235 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2236 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2237 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2238 HeapFree( GetProcessHeap(), 0, piW->pComment );
2239 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2240 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2241 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2242 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2243 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2244 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2245 break;
2248 case 8:
2249 case 9:
2251 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2253 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2254 break;
2257 default:
2258 FIXME( "Unhandled level %d\n", level );
2261 HeapFree( GetProcessHeap(), 0, data );
2262 return;
2265 /******************************************************************
2266 * DeviceCapabilities [WINSPOOL.@]
2267 * DeviceCapabilitiesA [WINSPOOL.@]
2270 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2271 LPSTR pOutput, LPDEVMODEA lpdm)
2273 INT ret;
2275 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice), debugstr_a(pPort), cap, pOutput, lpdm);
2277 if (!GDI_CallDeviceCapabilities16)
2279 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2280 (LPCSTR)104 );
2281 if (!GDI_CallDeviceCapabilities16) return -1;
2283 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2285 /* If DC_PAPERSIZE map POINT16s to POINTs */
2286 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2287 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2288 POINT *pt = (POINT *)pOutput;
2289 INT i;
2290 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2291 for(i = 0; i < ret; i++, pt++)
2293 pt->x = tmp[i].x;
2294 pt->y = tmp[i].y;
2296 HeapFree( GetProcessHeap(), 0, tmp );
2298 return ret;
2302 /*****************************************************************************
2303 * DeviceCapabilitiesW [WINSPOOL.@]
2305 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2308 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2309 WORD fwCapability, LPWSTR pOutput,
2310 const DEVMODEW *pDevMode)
2312 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2313 LPSTR pDeviceA = strdupWtoA(pDevice);
2314 LPSTR pPortA = strdupWtoA(pPort);
2315 INT ret;
2317 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability, pOutput, pDevMode);
2319 if(pOutput && (fwCapability == DC_BINNAMES ||
2320 fwCapability == DC_FILEDEPENDENCIES ||
2321 fwCapability == DC_PAPERNAMES)) {
2322 /* These need A -> W translation */
2323 INT size = 0, i;
2324 LPSTR pOutputA;
2325 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2326 dmA);
2327 if(ret == -1)
2328 return ret;
2329 switch(fwCapability) {
2330 case DC_BINNAMES:
2331 size = 24;
2332 break;
2333 case DC_PAPERNAMES:
2334 case DC_FILEDEPENDENCIES:
2335 size = 64;
2336 break;
2338 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2339 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2340 dmA);
2341 for(i = 0; i < ret; i++)
2342 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2343 pOutput + (i * size), size);
2344 HeapFree(GetProcessHeap(), 0, pOutputA);
2345 } else {
2346 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2347 (LPSTR)pOutput, dmA);
2349 HeapFree(GetProcessHeap(),0,pPortA);
2350 HeapFree(GetProcessHeap(),0,pDeviceA);
2351 HeapFree(GetProcessHeap(),0,dmA);
2352 return ret;
2355 /******************************************************************
2356 * DocumentPropertiesA [WINSPOOL.@]
2358 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2360 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2361 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2362 LPDEVMODEA pDevModeInput,DWORD fMode )
2364 LPSTR lpName = pDeviceName;
2365 static CHAR port[] = "LPT1:";
2366 LONG ret;
2368 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2369 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2372 if(!pDeviceName || !*pDeviceName) {
2373 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2374 if(!lpNameW) {
2375 ERR("no name from hPrinter?\n");
2376 SetLastError(ERROR_INVALID_HANDLE);
2377 return -1;
2379 lpName = strdupWtoA(lpNameW);
2382 if (!GDI_CallExtDeviceMode16)
2384 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2385 (LPCSTR)102 );
2386 if (!GDI_CallExtDeviceMode16) {
2387 ERR("No CallExtDeviceMode16?\n");
2388 return -1;
2391 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2392 pDevModeInput, NULL, fMode);
2394 if(!pDeviceName)
2395 HeapFree(GetProcessHeap(),0,lpName);
2396 return ret;
2400 /*****************************************************************************
2401 * DocumentPropertiesW (WINSPOOL.@)
2403 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2405 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2406 LPWSTR pDeviceName,
2407 LPDEVMODEW pDevModeOutput,
2408 LPDEVMODEW pDevModeInput, DWORD fMode)
2411 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2412 LPDEVMODEA pDevModeInputA;
2413 LPDEVMODEA pDevModeOutputA = NULL;
2414 LONG ret;
2416 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2417 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2418 fMode);
2419 if(pDevModeOutput) {
2420 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2421 if(ret < 0) return ret;
2422 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2424 pDevModeInputA = (fMode & DM_IN_BUFFER) ? DEVMODEdupWtoA(pDevModeInput) : NULL;
2425 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2426 pDevModeInputA, fMode);
2427 if(pDevModeOutput) {
2428 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2429 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2431 if(fMode == 0 && ret > 0)
2432 ret += (CCHDEVICENAME + CCHFORMNAME);
2433 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2434 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2435 return ret;
2438 /*****************************************************************************
2439 * IsValidDevmodeA [WINSPOOL.@]
2441 * Validate a DEVMODE structure and fix errors if possible.
2444 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2446 FIXME("(%p,%ld): stub\n", pDevMode, size);
2448 if(!pDevMode)
2449 return FALSE;
2451 return TRUE;
2454 /*****************************************************************************
2455 * IsValidDevmodeW [WINSPOOL.@]
2457 * Validate a DEVMODE structure and fix errors if possible.
2460 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2462 FIXME("(%p,%ld): stub\n", pDevMode, size);
2464 if(!pDevMode)
2465 return FALSE;
2467 return TRUE;
2470 /******************************************************************
2471 * OpenPrinterA [WINSPOOL.@]
2473 * See OpenPrinterW.
2476 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2477 LPPRINTER_DEFAULTSA pDefault)
2479 UNICODE_STRING lpPrinterNameW;
2480 UNICODE_STRING usBuffer;
2481 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2482 PWSTR pwstrPrinterNameW;
2483 BOOL ret;
2485 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName), phPrinter, pDefault);
2487 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2489 if(pDefault) {
2490 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2491 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2492 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2493 pDefaultW = &DefaultW;
2495 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2496 if(pDefault) {
2497 RtlFreeUnicodeString(&usBuffer);
2498 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2500 RtlFreeUnicodeString(&lpPrinterNameW);
2501 return ret;
2504 /******************************************************************
2505 * OpenPrinterW [WINSPOOL.@]
2507 * Open a Printer / Printserver or a Printer-Object
2509 * PARAMS
2510 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2511 * phPrinter [O] The resulting Handle is stored here
2512 * pDefault [I] PTR to Default Printer Settings or NULL
2514 * RETURNS
2515 * Success: TRUE
2516 * Failure: FALSE
2518 * NOTES
2519 * lpPrinterName is one of:
2520 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2521 *| Printer: "PrinterName"
2522 *| Printer-Object: "PrinterName,Job xxx"
2523 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2524 *| XcvPort: "Servername,XcvPort PortName"
2526 * BUGS
2527 *| Printer-Object not supported
2528 *| pDefaults is ignored
2531 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
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)
2547 HKEY key;
2548 DWORD deleting = 0, size = sizeof( deleting ), type;
2549 DWORD status;
2550 WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key );
2551 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2552 WaitForSingleObject( init_mutex, INFINITE );
2553 status = get_dword_from_reg( key, StatusW );
2554 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2555 ReleaseMutex( init_mutex );
2556 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2557 update_driver( *phPrinter );
2558 RegCloseKey( key );
2561 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2562 return (*phPrinter != 0);
2565 /******************************************************************
2566 * AddMonitorA [WINSPOOL.@]
2568 * See AddMonitorW.
2571 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2573 LPWSTR nameW = NULL;
2574 INT len;
2575 BOOL res;
2576 LPMONITOR_INFO_2A mi2a;
2577 MONITOR_INFO_2W mi2w;
2579 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2580 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2581 debugstr_a(mi2a ? mi2a->pName : NULL),
2582 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2583 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2585 if (Level != 2) {
2586 SetLastError(ERROR_INVALID_LEVEL);
2587 return FALSE;
2590 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2591 if (mi2a == NULL) {
2592 return FALSE;
2595 if (pName) {
2596 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2597 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2598 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2601 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2602 if (mi2a->pName) {
2603 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2604 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2605 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2607 if (mi2a->pEnvironment) {
2608 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2609 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2610 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2612 if (mi2a->pDLLName) {
2613 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2614 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2615 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2618 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2620 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2621 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2622 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2624 HeapFree(GetProcessHeap(), 0, nameW);
2625 return (res);
2628 /******************************************************************************
2629 * AddMonitorW [WINSPOOL.@]
2631 * Install a Printmonitor
2633 * PARAMS
2634 * pName [I] Servername or NULL (local Computer)
2635 * Level [I] Structure-Level (Must be 2)
2636 * pMonitors [I] PTR to MONITOR_INFO_2
2638 * RETURNS
2639 * Success: TRUE
2640 * Failure: FALSE
2642 * NOTES
2643 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2646 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2648 LPMONITOR_INFO_2W mi2w;
2650 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2651 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2652 debugstr_w(mi2w ? mi2w->pName : NULL),
2653 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2654 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2656 if ((backend == NULL) && !load_backend()) return FALSE;
2658 if (Level != 2) {
2659 SetLastError(ERROR_INVALID_LEVEL);
2660 return FALSE;
2663 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2664 if (mi2w == NULL) {
2665 return FALSE;
2668 return backend->fpAddMonitor(pName, Level, pMonitors);
2671 /******************************************************************
2672 * DeletePrinterDriverA [WINSPOOL.@]
2675 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2677 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2680 /******************************************************************
2681 * DeletePrinterDriverW [WINSPOOL.@]
2684 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2686 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2689 /******************************************************************
2690 * DeleteMonitorA [WINSPOOL.@]
2692 * See DeleteMonitorW.
2695 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2697 LPWSTR nameW = NULL;
2698 LPWSTR EnvironmentW = NULL;
2699 LPWSTR MonitorNameW = NULL;
2700 BOOL res;
2701 INT len;
2703 if (pName) {
2704 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2705 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2706 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2709 if (pEnvironment) {
2710 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2711 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2712 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2714 if (pMonitorName) {
2715 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2716 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2717 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2720 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2722 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2723 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2724 HeapFree(GetProcessHeap(), 0, nameW);
2725 return (res);
2728 /******************************************************************
2729 * DeleteMonitorW [WINSPOOL.@]
2731 * Delete a specific Printmonitor from a Printing-Environment
2733 * PARAMS
2734 * pName [I] Servername or NULL (local Computer)
2735 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2736 * pMonitorName [I] Name of the Monitor, that should be deleted
2738 * RETURNS
2739 * Success: TRUE
2740 * Failure: FALSE
2742 * NOTES
2743 * pEnvironment is ignored in Windows for the local Computer.
2746 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2749 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2750 debugstr_w(pMonitorName));
2752 if ((backend == NULL) && !load_backend()) return FALSE;
2754 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2758 /******************************************************************
2759 * DeletePortA [WINSPOOL.@]
2761 * See DeletePortW.
2764 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2766 LPWSTR nameW = NULL;
2767 LPWSTR portW = NULL;
2768 INT len;
2769 DWORD res;
2771 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2773 /* convert servername to unicode */
2774 if (pName) {
2775 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2776 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2777 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2780 /* convert portname to unicode */
2781 if (pPortName) {
2782 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2783 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2784 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2787 res = DeletePortW(nameW, hWnd, portW);
2788 HeapFree(GetProcessHeap(), 0, nameW);
2789 HeapFree(GetProcessHeap(), 0, portW);
2790 return res;
2793 /******************************************************************
2794 * DeletePortW [WINSPOOL.@]
2796 * Delete a specific Port
2798 * PARAMS
2799 * pName [I] Servername or NULL (local Computer)
2800 * hWnd [I] Handle to parent Window for the Dialog-Box
2801 * pPortName [I] Name of the Port, that should be deleted
2803 * RETURNS
2804 * Success: TRUE
2805 * Failure: FALSE
2808 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2810 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2812 if ((backend == NULL) && !load_backend()) return FALSE;
2814 if (!pPortName) {
2815 SetLastError(RPC_X_NULL_REF_POINTER);
2816 return FALSE;
2819 return backend->fpDeletePort(pName, hWnd, pPortName);
2822 /******************************************************************************
2823 * WritePrinter [WINSPOOL.@]
2825 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2827 opened_printer_t *printer;
2828 BOOL ret = FALSE;
2830 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2832 EnterCriticalSection(&printer_handles_cs);
2833 printer = get_opened_printer(hPrinter);
2834 if(!printer)
2836 SetLastError(ERROR_INVALID_HANDLE);
2837 goto end;
2840 if(!printer->doc)
2842 SetLastError(ERROR_SPL_NO_STARTDOC);
2843 goto end;
2846 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2847 end:
2848 LeaveCriticalSection(&printer_handles_cs);
2849 return ret;
2852 /*****************************************************************************
2853 * AddFormA [WINSPOOL.@]
2855 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2857 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2858 return TRUE;
2861 /*****************************************************************************
2862 * AddFormW [WINSPOOL.@]
2864 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2866 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2867 return TRUE;
2870 /*****************************************************************************
2871 * AddJobA [WINSPOOL.@]
2873 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2875 BOOL ret;
2876 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2877 DWORD needed;
2879 if(Level != 1) {
2880 SetLastError(ERROR_INVALID_LEVEL);
2881 return FALSE;
2884 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2886 if(ret) {
2887 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2888 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2889 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2890 if(*pcbNeeded > cbBuf) {
2891 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2892 ret = FALSE;
2893 } else {
2894 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2895 addjobA->JobId = addjobW->JobId;
2896 addjobA->Path = (char *)(addjobA + 1);
2897 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2900 return ret;
2903 /*****************************************************************************
2904 * AddJobW [WINSPOOL.@]
2906 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2908 opened_printer_t *printer;
2909 job_t *job;
2910 BOOL ret = FALSE;
2911 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2912 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2913 WCHAR path[MAX_PATH], filename[MAX_PATH];
2914 DWORD len;
2915 ADDJOB_INFO_1W *addjob;
2917 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2919 EnterCriticalSection(&printer_handles_cs);
2921 printer = get_opened_printer(hPrinter);
2923 if(!printer) {
2924 SetLastError(ERROR_INVALID_HANDLE);
2925 goto end;
2928 if(Level != 1) {
2929 SetLastError(ERROR_INVALID_LEVEL);
2930 goto end;
2933 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2934 if(!job)
2935 goto end;
2937 job->job_id = InterlockedIncrement(&next_job_id);
2939 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2940 if(path[len - 1] != '\\')
2941 path[len++] = '\\';
2942 memcpy(path + len, spool_path, sizeof(spool_path));
2943 sprintfW(filename, fmtW, path, job->job_id);
2945 len = strlenW(filename);
2946 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2947 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2948 job->portname = NULL;
2949 job->document_title = strdupW(default_doc_title);
2950 job->printer_name = strdupW(printer->name);
2951 job->devmode = dup_devmode( printer->devmode );
2952 list_add_tail(&printer->queue->jobs, &job->entry);
2954 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2955 if(*pcbNeeded <= cbBuf) {
2956 addjob = (ADDJOB_INFO_1W*)pData;
2957 addjob->JobId = job->job_id;
2958 addjob->Path = (WCHAR *)(addjob + 1);
2959 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2960 ret = TRUE;
2961 } else
2962 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2964 end:
2965 LeaveCriticalSection(&printer_handles_cs);
2966 return ret;
2969 /*****************************************************************************
2970 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2972 * Return the PATH for the Print-Processors
2974 * See GetPrintProcessorDirectoryW.
2978 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2979 DWORD level, LPBYTE Info,
2980 DWORD cbBuf, LPDWORD pcbNeeded)
2982 LPWSTR serverW = NULL;
2983 LPWSTR envW = NULL;
2984 BOOL ret;
2985 INT len;
2987 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2988 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2991 if (server) {
2992 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2993 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2994 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2997 if (env) {
2998 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2999 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3000 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
3003 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
3004 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
3006 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
3007 cbBuf, pcbNeeded);
3009 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
3010 cbBuf, NULL, NULL) > 0;
3013 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3014 HeapFree(GetProcessHeap(), 0, envW);
3015 HeapFree(GetProcessHeap(), 0, serverW);
3016 return ret;
3019 /*****************************************************************************
3020 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3022 * Return the PATH for the Print-Processors
3024 * PARAMS
3025 * server [I] Servername (NT only) or NULL (local Computer)
3026 * env [I] Printing-Environment (see below) or NULL (Default)
3027 * level [I] Structure-Level (must be 1)
3028 * Info [O] PTR to Buffer that receives the Result
3029 * cbBuf [I] Size of Buffer at "Info"
3030 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3031 * required for the Buffer at "Info"
3033 * RETURNS
3034 * Success: TRUE and in pcbNeeded the Bytes used in Info
3035 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3036 * if cbBuf is too small
3038 * Native Values returned in Info on Success:
3039 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3040 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3041 *| win9x(Windows 4.0): "%winsysdir%"
3043 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3045 * BUGS
3046 * Only NULL or "" is supported for server
3049 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3050 DWORD level, LPBYTE Info,
3051 DWORD cbBuf, LPDWORD pcbNeeded)
3054 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3055 Info, cbBuf, pcbNeeded);
3057 if ((backend == NULL) && !load_backend()) return FALSE;
3059 if (level != 1) {
3060 /* (Level != 1) is ignored in win9x */
3061 SetLastError(ERROR_INVALID_LEVEL);
3062 return FALSE;
3065 if (pcbNeeded == NULL) {
3066 /* (pcbNeeded == NULL) is ignored in win9x */
3067 SetLastError(RPC_X_NULL_REF_POINTER);
3068 return FALSE;
3071 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3074 /*****************************************************************************
3075 * WINSPOOL_OpenDriverReg [internal]
3077 * opens the registry for the printer drivers depending on the given input
3078 * variable pEnvironment
3080 * RETURNS:
3081 * the opened hkey on success
3082 * NULL on error
3084 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3086 HKEY retval = NULL;
3087 LPWSTR buffer;
3088 const printenv_t * env;
3090 TRACE("(%s)\n", debugstr_w(pEnvironment));
3092 env = validate_envW(pEnvironment);
3093 if (!env) return NULL;
3095 buffer = HeapAlloc( GetProcessHeap(), 0,
3096 (strlenW(DriversW) + strlenW(env->envname) +
3097 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3098 if(buffer) {
3099 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3100 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3101 HeapFree(GetProcessHeap(), 0, buffer);
3103 return retval;
3106 /*****************************************************************************
3107 * set_devices_and_printerports [internal]
3109 * set the [Devices] and [PrinterPorts] entries for a printer.
3112 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3114 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3115 WCHAR *devline;
3116 HKEY hkey;
3118 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3120 /* FIXME: the driver must change to "winspool" */
3121 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3122 if (devline) {
3123 lstrcpyW(devline, driver_nt);
3124 lstrcatW(devline, commaW);
3125 lstrcatW(devline, pi->pPortName);
3127 TRACE("using %s\n", debugstr_w(devline));
3128 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
3129 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3130 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3131 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3132 RegCloseKey(hkey);
3135 lstrcatW(devline, timeout_15_45);
3136 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
3137 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3138 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3139 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3140 RegCloseKey(hkey);
3142 HeapFree(GetProcessHeap(), 0, devline);
3146 /*****************************************************************************
3147 * AddPrinterW [WINSPOOL.@]
3149 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3151 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3152 LPDEVMODEW dm;
3153 HANDLE retval;
3154 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3155 LONG size;
3157 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3159 if(pName != NULL) {
3160 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3161 SetLastError(ERROR_INVALID_PARAMETER);
3162 return 0;
3164 if(Level != 2) {
3165 ERR("Level = %d, unsupported!\n", Level);
3166 SetLastError(ERROR_INVALID_LEVEL);
3167 return 0;
3169 if(!pPrinter) {
3170 SetLastError(ERROR_INVALID_PARAMETER);
3171 return 0;
3173 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3174 ERROR_SUCCESS) {
3175 ERR("Can't create Printers key\n");
3176 return 0;
3178 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3179 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3180 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3181 RegCloseKey(hkeyPrinter);
3182 RegCloseKey(hkeyPrinters);
3183 return 0;
3185 RegCloseKey(hkeyPrinter);
3187 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3188 if(!hkeyDrivers) {
3189 ERR("Can't create Drivers key\n");
3190 RegCloseKey(hkeyPrinters);
3191 return 0;
3193 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3194 ERROR_SUCCESS) {
3195 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3196 RegCloseKey(hkeyPrinters);
3197 RegCloseKey(hkeyDrivers);
3198 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3199 return 0;
3201 RegCloseKey(hkeyDriver);
3202 RegCloseKey(hkeyDrivers);
3204 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3205 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3206 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3207 RegCloseKey(hkeyPrinters);
3208 return 0;
3211 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3212 ERROR_SUCCESS) {
3213 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3214 SetLastError(ERROR_INVALID_PRINTER_NAME);
3215 RegCloseKey(hkeyPrinters);
3216 return 0;
3219 set_devices_and_printerports(pi);
3221 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3222 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3223 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3224 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3225 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3226 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3227 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3228 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3229 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3230 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3231 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3232 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3233 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3234 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3235 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3236 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3237 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3238 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3240 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3242 if (size < 0)
3244 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3245 size = sizeof(DEVMODEW);
3247 if(pi->pDevMode)
3248 dm = pi->pDevMode;
3249 else
3251 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3252 dm->dmSize = size;
3253 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3255 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3256 HeapFree( GetProcessHeap(), 0, dm );
3257 dm = NULL;
3259 else
3261 /* set devmode to printer name */
3262 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3266 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3267 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3269 RegCloseKey(hkeyPrinter);
3270 RegCloseKey(hkeyPrinters);
3271 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3272 ERR("OpenPrinter failing\n");
3273 return 0;
3275 return retval;
3278 /*****************************************************************************
3279 * AddPrinterA [WINSPOOL.@]
3281 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3283 UNICODE_STRING pNameW;
3284 PWSTR pwstrNameW;
3285 PRINTER_INFO_2W *piW;
3286 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3287 HANDLE ret;
3289 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3290 if(Level != 2) {
3291 ERR("Level = %d, unsupported!\n", Level);
3292 SetLastError(ERROR_INVALID_LEVEL);
3293 return 0;
3295 pwstrNameW = asciitounicode(&pNameW,pName);
3296 piW = printer_info_AtoW( piA, Level );
3298 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3300 free_printer_info( piW, Level );
3301 RtlFreeUnicodeString(&pNameW);
3302 return ret;
3306 /*****************************************************************************
3307 * ClosePrinter [WINSPOOL.@]
3309 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3311 UINT_PTR i = (UINT_PTR)hPrinter;
3312 opened_printer_t *printer = NULL;
3313 BOOL ret = FALSE;
3315 TRACE("(%p)\n", hPrinter);
3317 EnterCriticalSection(&printer_handles_cs);
3319 if ((i > 0) && (i <= nb_printer_handles))
3320 printer = printer_handles[i - 1];
3323 if(printer)
3325 struct list *cursor, *cursor2;
3327 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3329 if (printer->backend_printer) {
3330 backend->fpClosePrinter(printer->backend_printer);
3333 if(printer->doc)
3334 EndDocPrinter(hPrinter);
3336 if(InterlockedDecrement(&printer->queue->ref) == 0)
3338 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3340 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3341 ScheduleJob(hPrinter, job->job_id);
3343 HeapFree(GetProcessHeap(), 0, printer->queue);
3346 free_printer_entry( printer );
3347 printer_handles[i - 1] = NULL;
3348 ret = TRUE;
3350 LeaveCriticalSection(&printer_handles_cs);
3351 return ret;
3354 /*****************************************************************************
3355 * DeleteFormA [WINSPOOL.@]
3357 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3359 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3360 return TRUE;
3363 /*****************************************************************************
3364 * DeleteFormW [WINSPOOL.@]
3366 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3368 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3369 return TRUE;
3372 /*****************************************************************************
3373 * DeletePrinter [WINSPOOL.@]
3375 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3377 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3378 HKEY hkeyPrinters, hkey;
3379 WCHAR def[MAX_PATH];
3380 DWORD size = sizeof( def ) / sizeof( def[0] );
3382 if(!lpNameW) {
3383 SetLastError(ERROR_INVALID_HANDLE);
3384 return FALSE;
3386 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3387 RegDeleteTreeW(hkeyPrinters, lpNameW);
3388 RegCloseKey(hkeyPrinters);
3390 WriteProfileStringW(devicesW, lpNameW, NULL);
3391 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3393 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3394 RegDeleteValueW(hkey, lpNameW);
3395 RegCloseKey(hkey);
3398 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3399 RegDeleteValueW(hkey, lpNameW);
3400 RegCloseKey(hkey);
3403 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3405 WriteProfileStringW( windowsW, deviceW, NULL );
3406 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3408 RegDeleteValueW( hkey, deviceW );
3409 RegCloseKey( hkey );
3411 SetDefaultPrinterW( NULL );
3414 return TRUE;
3417 /*****************************************************************************
3418 * SetPrinterA [WINSPOOL.@]
3420 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3422 BYTE *dataW = data;
3423 BOOL ret;
3425 if (level != 0)
3427 dataW = printer_info_AtoW( data, level );
3428 if (!dataW) return FALSE;
3431 ret = SetPrinterW( printer, level, dataW, command );
3433 if (dataW != data) free_printer_info( dataW, level );
3435 return ret;
3438 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3440 set_reg_szW( key, NameW, pi->pPrinterName );
3441 set_reg_szW( key, Share_NameW, pi->pShareName );
3442 set_reg_szW( key, PortW, pi->pPortName );
3443 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3444 set_reg_szW( key, DescriptionW, pi->pComment );
3445 set_reg_szW( key, LocationW, pi->pLocation );
3447 if (pi->pDevMode)
3448 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3450 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3451 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3452 set_reg_szW( key, DatatypeW, pi->pDatatype );
3453 set_reg_szW( key, ParametersW, pi->pParameters );
3455 set_reg_DWORD( key, AttributesW, pi->Attributes );
3456 set_reg_DWORD( key, PriorityW, pi->Priority );
3457 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3458 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3459 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3462 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3464 if (!pi->pDevMode) return FALSE;
3466 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3467 return TRUE;
3470 /******************************************************************************
3471 * SetPrinterW [WINSPOOL.@]
3473 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3475 HKEY key;
3476 BOOL ret = FALSE;
3478 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3480 if (command != 0) FIXME( "Ignoring command %d\n", command );
3482 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3483 return FALSE;
3485 switch (level)
3487 case 2:
3489 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3490 set_printer_2( key, pi2 );
3491 ret = TRUE;
3492 break;
3495 case 9:
3497 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3498 ret = set_printer_9( key, pi );
3499 break;
3502 default:
3503 FIXME( "Unimplemented level %d\n", level );
3504 SetLastError( ERROR_INVALID_LEVEL );
3507 RegCloseKey( key );
3508 return ret;
3511 /*****************************************************************************
3512 * SetJobA [WINSPOOL.@]
3514 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3515 LPBYTE pJob, DWORD Command)
3517 BOOL ret;
3518 LPBYTE JobW;
3519 UNICODE_STRING usBuffer;
3521 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3523 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3524 are all ignored by SetJob, so we don't bother copying them */
3525 switch(Level)
3527 case 0:
3528 JobW = NULL;
3529 break;
3530 case 1:
3532 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3533 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3535 JobW = (LPBYTE)info1W;
3536 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3537 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3538 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3539 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3540 info1W->Status = info1A->Status;
3541 info1W->Priority = info1A->Priority;
3542 info1W->Position = info1A->Position;
3543 info1W->PagesPrinted = info1A->PagesPrinted;
3544 break;
3546 case 2:
3548 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3549 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3551 JobW = (LPBYTE)info2W;
3552 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3553 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3554 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3555 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3556 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3557 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3558 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3559 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3560 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3561 info2W->Status = info2A->Status;
3562 info2W->Priority = info2A->Priority;
3563 info2W->Position = info2A->Position;
3564 info2W->StartTime = info2A->StartTime;
3565 info2W->UntilTime = info2A->UntilTime;
3566 info2W->PagesPrinted = info2A->PagesPrinted;
3567 break;
3569 case 3:
3570 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3571 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3572 break;
3573 default:
3574 SetLastError(ERROR_INVALID_LEVEL);
3575 return FALSE;
3578 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3580 switch(Level)
3582 case 1:
3584 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3585 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3586 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3587 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3588 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3589 break;
3591 case 2:
3593 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3594 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3595 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3596 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3597 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3598 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3599 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3600 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3601 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3602 break;
3605 HeapFree(GetProcessHeap(), 0, JobW);
3607 return ret;
3610 /*****************************************************************************
3611 * SetJobW [WINSPOOL.@]
3613 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3614 LPBYTE pJob, DWORD Command)
3616 BOOL ret = FALSE;
3617 job_t *job;
3619 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3620 FIXME("Ignoring everything other than document title\n");
3622 EnterCriticalSection(&printer_handles_cs);
3623 job = get_job(hPrinter, JobId);
3624 if(!job)
3625 goto end;
3627 switch(Level)
3629 case 0:
3630 break;
3631 case 1:
3633 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3634 HeapFree(GetProcessHeap(), 0, job->document_title);
3635 job->document_title = strdupW(info1->pDocument);
3636 break;
3638 case 2:
3640 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3641 HeapFree(GetProcessHeap(), 0, job->document_title);
3642 job->document_title = strdupW(info2->pDocument);
3643 HeapFree(GetProcessHeap(), 0, job->devmode);
3644 job->devmode = dup_devmode( info2->pDevMode );
3645 break;
3647 case 3:
3648 break;
3649 default:
3650 SetLastError(ERROR_INVALID_LEVEL);
3651 goto end;
3653 ret = TRUE;
3654 end:
3655 LeaveCriticalSection(&printer_handles_cs);
3656 return ret;
3659 /*****************************************************************************
3660 * EndDocPrinter [WINSPOOL.@]
3662 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3664 opened_printer_t *printer;
3665 BOOL ret = FALSE;
3666 TRACE("(%p)\n", hPrinter);
3668 EnterCriticalSection(&printer_handles_cs);
3670 printer = get_opened_printer(hPrinter);
3671 if(!printer)
3673 SetLastError(ERROR_INVALID_HANDLE);
3674 goto end;
3677 if(!printer->doc)
3679 SetLastError(ERROR_SPL_NO_STARTDOC);
3680 goto end;
3683 CloseHandle(printer->doc->hf);
3684 ScheduleJob(hPrinter, printer->doc->job_id);
3685 HeapFree(GetProcessHeap(), 0, printer->doc);
3686 printer->doc = NULL;
3687 ret = TRUE;
3688 end:
3689 LeaveCriticalSection(&printer_handles_cs);
3690 return ret;
3693 /*****************************************************************************
3694 * EndPagePrinter [WINSPOOL.@]
3696 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3698 FIXME("(%p): stub\n", hPrinter);
3699 return TRUE;
3702 /*****************************************************************************
3703 * StartDocPrinterA [WINSPOOL.@]
3705 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3707 UNICODE_STRING usBuffer;
3708 DOC_INFO_2W doc2W;
3709 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3710 DWORD ret;
3712 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3713 or one (DOC_INFO_3) extra DWORDs */
3715 switch(Level) {
3716 case 2:
3717 doc2W.JobId = doc2->JobId;
3718 /* fall through */
3719 case 3:
3720 doc2W.dwMode = doc2->dwMode;
3721 /* fall through */
3722 case 1:
3723 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3724 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3725 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3726 break;
3728 default:
3729 SetLastError(ERROR_INVALID_LEVEL);
3730 return FALSE;
3733 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3735 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3736 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3737 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3739 return ret;
3742 /*****************************************************************************
3743 * StartDocPrinterW [WINSPOOL.@]
3745 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3747 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3748 opened_printer_t *printer;
3749 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3750 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3751 JOB_INFO_1W job_info;
3752 DWORD needed, ret = 0;
3753 HANDLE hf;
3754 WCHAR *filename;
3755 job_t *job;
3757 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3758 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3759 debugstr_w(doc->pDatatype));
3761 if(Level < 1 || Level > 3)
3763 SetLastError(ERROR_INVALID_LEVEL);
3764 return 0;
3767 EnterCriticalSection(&printer_handles_cs);
3768 printer = get_opened_printer(hPrinter);
3769 if(!printer)
3771 SetLastError(ERROR_INVALID_HANDLE);
3772 goto end;
3775 if(printer->doc)
3777 SetLastError(ERROR_INVALID_PRINTER_STATE);
3778 goto end;
3781 /* Even if we're printing to a file we still add a print job, we'll
3782 just ignore the spool file name */
3784 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3786 ERR("AddJob failed gle %u\n", GetLastError());
3787 goto end;
3790 /* use pOutputFile only, when it is a real filename */
3791 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3792 filename = doc->pOutputFile;
3793 else
3794 filename = addjob->Path;
3796 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3797 if(hf == INVALID_HANDLE_VALUE)
3798 goto end;
3800 memset(&job_info, 0, sizeof(job_info));
3801 job_info.pDocument = doc->pDocName;
3802 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3804 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3805 printer->doc->hf = hf;
3806 ret = printer->doc->job_id = addjob->JobId;
3807 job = get_job(hPrinter, ret);
3808 job->portname = strdupW(doc->pOutputFile);
3810 end:
3811 LeaveCriticalSection(&printer_handles_cs);
3813 return ret;
3816 /*****************************************************************************
3817 * StartPagePrinter [WINSPOOL.@]
3819 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3821 FIXME("(%p): stub\n", hPrinter);
3822 return TRUE;
3825 /*****************************************************************************
3826 * GetFormA [WINSPOOL.@]
3828 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3829 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3831 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3832 Level,pForm,cbBuf,pcbNeeded);
3833 return FALSE;
3836 /*****************************************************************************
3837 * GetFormW [WINSPOOL.@]
3839 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3840 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3842 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3843 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3844 return FALSE;
3847 /*****************************************************************************
3848 * SetFormA [WINSPOOL.@]
3850 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3851 LPBYTE pForm)
3853 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3854 return FALSE;
3857 /*****************************************************************************
3858 * SetFormW [WINSPOOL.@]
3860 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3861 LPBYTE pForm)
3863 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3864 return FALSE;
3867 /*****************************************************************************
3868 * ReadPrinter [WINSPOOL.@]
3870 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3871 LPDWORD pNoBytesRead)
3873 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3874 return FALSE;
3877 /*****************************************************************************
3878 * ResetPrinterA [WINSPOOL.@]
3880 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3882 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3883 return FALSE;
3886 /*****************************************************************************
3887 * ResetPrinterW [WINSPOOL.@]
3889 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3891 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3892 return FALSE;
3895 /*****************************************************************************
3896 * get_filename_from_reg [internal]
3898 * Get ValueName from hkey storing result in out
3899 * when the Value in the registry has only a filename, use driverdir as prefix
3900 * outlen is space left in out
3901 * String is stored either as unicode or ascii
3905 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3906 LPBYTE out, DWORD outlen, LPDWORD needed)
3908 WCHAR filename[MAX_PATH];
3909 DWORD size;
3910 DWORD type;
3911 LONG ret;
3912 LPWSTR buffer = filename;
3913 LPWSTR ptr;
3915 *needed = 0;
3916 size = sizeof(filename);
3917 buffer[0] = '\0';
3918 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3919 if (ret == ERROR_MORE_DATA) {
3920 TRACE("need dynamic buffer: %u\n", size);
3921 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3922 if (!buffer) {
3923 /* No Memory is bad */
3924 return FALSE;
3926 buffer[0] = '\0';
3927 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3930 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3931 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3932 return FALSE;
3935 ptr = buffer;
3936 while (ptr) {
3937 /* do we have a full path ? */
3938 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3939 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3941 if (!ret) {
3942 /* we must build the full Path */
3943 *needed += dirlen;
3944 if ((out) && (outlen > dirlen)) {
3945 lstrcpyW((LPWSTR)out, driverdir);
3946 out += dirlen;
3947 outlen -= dirlen;
3949 else
3950 out = NULL;
3953 /* write the filename */
3954 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3955 if ((out) && (outlen >= size)) {
3956 lstrcpyW((LPWSTR)out, ptr);
3957 out += size;
3958 outlen -= size;
3960 else
3961 out = NULL;
3962 *needed += size;
3963 ptr += lstrlenW(ptr)+1;
3964 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3967 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3969 /* write the multisz-termination */
3970 if (type == REG_MULTI_SZ) {
3971 size = sizeof(WCHAR);
3973 *needed += size;
3974 if (out && (outlen >= size)) {
3975 memset (out, 0, size);
3978 return TRUE;
3981 /*****************************************************************************
3982 * WINSPOOL_GetStringFromReg
3984 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3985 * String is stored as unicode.
3987 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3988 DWORD buflen, DWORD *needed)
3990 DWORD sz = buflen, type;
3991 LONG ret;
3993 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3994 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3995 WARN("Got ret = %d\n", ret);
3996 *needed = 0;
3997 return FALSE;
3999 /* add space for terminating '\0' */
4000 sz += sizeof(WCHAR);
4001 *needed = sz;
4003 if (ptr)
4004 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
4006 return TRUE;
4009 /*****************************************************************************
4010 * WINSPOOL_GetDefaultDevMode
4012 * Get a default DevMode values for wineps.
4014 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr, DWORD buflen, DWORD *needed)
4016 static const WCHAR winepsW[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4018 if (buflen >= sizeof(DEVMODEW))
4020 DEVMODEW *dm = (DEVMODEW *)ptr;
4022 /* the driver will update registry with real values */
4023 memset(dm, 0, sizeof(*dm));
4024 dm->dmSize = sizeof(*dm);
4025 lstrcpyW(dm->dmDeviceName, winepsW);
4027 *needed = sizeof(DEVMODEW);
4030 /*****************************************************************************
4031 * WINSPOOL_GetDevModeFromReg
4033 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4034 * DevMode is stored either as unicode or ascii.
4036 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4037 LPBYTE ptr,
4038 DWORD buflen, DWORD *needed)
4040 DWORD sz = buflen, type;
4041 LONG ret;
4043 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4044 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4045 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4046 if (sz < sizeof(DEVMODEA))
4048 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4049 return FALSE;
4051 /* ensures that dmSize is not erratically bogus if registry is invalid */
4052 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4053 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4054 sz += (CCHDEVICENAME + CCHFORMNAME);
4055 if (ptr && (buflen >= sz)) {
4056 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4057 memcpy(ptr, dmW, sz);
4058 HeapFree(GetProcessHeap(),0,dmW);
4060 *needed = sz;
4061 return TRUE;
4064 /*********************************************************************
4065 * WINSPOOL_GetPrinter_1
4067 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4069 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4070 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4072 DWORD size, left = cbBuf;
4073 BOOL space = (cbBuf > 0);
4074 LPBYTE ptr = buf;
4076 *pcbNeeded = 0;
4078 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4079 if(space && size <= left) {
4080 pi1->pName = (LPWSTR)ptr;
4081 ptr += size;
4082 left -= size;
4083 } else
4084 space = FALSE;
4085 *pcbNeeded += size;
4088 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4089 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4090 if(space && size <= left) {
4091 pi1->pDescription = (LPWSTR)ptr;
4092 ptr += size;
4093 left -= size;
4094 } else
4095 space = FALSE;
4096 *pcbNeeded += size;
4099 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4100 if(space && size <= left) {
4101 pi1->pComment = (LPWSTR)ptr;
4102 ptr += size;
4103 left -= size;
4104 } else
4105 space = FALSE;
4106 *pcbNeeded += size;
4109 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4111 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4112 memset(pi1, 0, sizeof(*pi1));
4114 return space;
4116 /*********************************************************************
4117 * WINSPOOL_GetPrinter_2
4119 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4121 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4122 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4124 DWORD size, left = cbBuf;
4125 BOOL space = (cbBuf > 0);
4126 LPBYTE ptr = buf;
4128 *pcbNeeded = 0;
4130 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4131 if(space && size <= left) {
4132 pi2->pPrinterName = (LPWSTR)ptr;
4133 ptr += size;
4134 left -= size;
4135 } else
4136 space = FALSE;
4137 *pcbNeeded += size;
4139 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4140 if(space && size <= left) {
4141 pi2->pShareName = (LPWSTR)ptr;
4142 ptr += size;
4143 left -= size;
4144 } else
4145 space = FALSE;
4146 *pcbNeeded += size;
4148 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4149 if(space && size <= left) {
4150 pi2->pPortName = (LPWSTR)ptr;
4151 ptr += size;
4152 left -= size;
4153 } else
4154 space = FALSE;
4155 *pcbNeeded += size;
4157 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4158 if(space && size <= left) {
4159 pi2->pDriverName = (LPWSTR)ptr;
4160 ptr += size;
4161 left -= size;
4162 } else
4163 space = FALSE;
4164 *pcbNeeded += size;
4166 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4167 if(space && size <= left) {
4168 pi2->pComment = (LPWSTR)ptr;
4169 ptr += size;
4170 left -= size;
4171 } else
4172 space = FALSE;
4173 *pcbNeeded += size;
4175 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4176 if(space && size <= left) {
4177 pi2->pLocation = (LPWSTR)ptr;
4178 ptr += size;
4179 left -= size;
4180 } else
4181 space = FALSE;
4182 *pcbNeeded += size;
4184 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4185 if(space && size <= left) {
4186 pi2->pDevMode = (LPDEVMODEW)ptr;
4187 ptr += size;
4188 left -= size;
4189 } else
4190 space = FALSE;
4191 *pcbNeeded += size;
4193 else
4195 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4196 if(space && size <= left) {
4197 pi2->pDevMode = (LPDEVMODEW)ptr;
4198 ptr += size;
4199 left -= size;
4200 } else
4201 space = FALSE;
4202 *pcbNeeded += size;
4204 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4205 if(space && size <= left) {
4206 pi2->pSepFile = (LPWSTR)ptr;
4207 ptr += size;
4208 left -= size;
4209 } else
4210 space = FALSE;
4211 *pcbNeeded += size;
4213 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4214 if(space && size <= left) {
4215 pi2->pPrintProcessor = (LPWSTR)ptr;
4216 ptr += size;
4217 left -= size;
4218 } else
4219 space = FALSE;
4220 *pcbNeeded += size;
4222 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4223 if(space && size <= left) {
4224 pi2->pDatatype = (LPWSTR)ptr;
4225 ptr += size;
4226 left -= size;
4227 } else
4228 space = FALSE;
4229 *pcbNeeded += size;
4231 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4232 if(space && size <= left) {
4233 pi2->pParameters = (LPWSTR)ptr;
4234 ptr += size;
4235 left -= size;
4236 } else
4237 space = FALSE;
4238 *pcbNeeded += size;
4240 if(pi2) {
4241 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4242 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4243 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4244 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4245 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4248 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4249 memset(pi2, 0, sizeof(*pi2));
4251 return space;
4254 /*********************************************************************
4255 * WINSPOOL_GetPrinter_4
4257 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4259 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4260 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4262 DWORD size, left = cbBuf;
4263 BOOL space = (cbBuf > 0);
4264 LPBYTE ptr = buf;
4266 *pcbNeeded = 0;
4268 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4269 if(space && size <= left) {
4270 pi4->pPrinterName = (LPWSTR)ptr;
4271 ptr += size;
4272 left -= size;
4273 } else
4274 space = FALSE;
4275 *pcbNeeded += size;
4277 if(pi4) {
4278 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4281 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4282 memset(pi4, 0, sizeof(*pi4));
4284 return space;
4287 /*********************************************************************
4288 * WINSPOOL_GetPrinter_5
4290 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4292 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4293 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4295 DWORD size, left = cbBuf;
4296 BOOL space = (cbBuf > 0);
4297 LPBYTE ptr = buf;
4299 *pcbNeeded = 0;
4301 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4302 if(space && size <= left) {
4303 pi5->pPrinterName = (LPWSTR)ptr;
4304 ptr += size;
4305 left -= size;
4306 } else
4307 space = FALSE;
4308 *pcbNeeded += size;
4310 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4311 if(space && size <= left) {
4312 pi5->pPortName = (LPWSTR)ptr;
4313 ptr += size;
4314 left -= size;
4315 } else
4316 space = FALSE;
4317 *pcbNeeded += size;
4319 if(pi5) {
4320 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4321 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4322 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4325 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4326 memset(pi5, 0, sizeof(*pi5));
4328 return space;
4331 /*********************************************************************
4332 * WINSPOOL_GetPrinter_7
4334 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4336 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4337 DWORD cbBuf, LPDWORD pcbNeeded)
4339 DWORD size, left = cbBuf;
4340 BOOL space = (cbBuf > 0);
4341 LPBYTE ptr = buf;
4343 *pcbNeeded = 0;
4345 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4347 ptr = NULL;
4348 size = sizeof(pi7->pszObjectGUID);
4350 if (space && size <= left) {
4351 pi7->pszObjectGUID = (LPWSTR)ptr;
4352 ptr += size;
4353 left -= size;
4354 } else
4355 space = FALSE;
4356 *pcbNeeded += size;
4357 if (pi7) {
4358 /* We do not have a Directory Service */
4359 pi7->dwAction = DSPRINT_UNPUBLISH;
4362 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4363 memset(pi7, 0, sizeof(*pi7));
4365 return space;
4368 /*********************************************************************
4369 * WINSPOOL_GetPrinter_9
4371 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4373 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4374 DWORD cbBuf, LPDWORD pcbNeeded)
4376 DWORD size;
4377 BOOL space = (cbBuf > 0);
4379 *pcbNeeded = 0;
4381 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4382 if(space && size <= cbBuf) {
4383 pi9->pDevMode = (LPDEVMODEW)buf;
4384 } else
4385 space = FALSE;
4386 *pcbNeeded += size;
4388 else
4390 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4391 if(space && size <= cbBuf) {
4392 pi9->pDevMode = (LPDEVMODEW)buf;
4393 } else
4394 space = FALSE;
4395 *pcbNeeded += size;
4398 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4399 memset(pi9, 0, sizeof(*pi9));
4401 return space;
4404 /*****************************************************************************
4405 * GetPrinterW [WINSPOOL.@]
4407 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4408 DWORD cbBuf, LPDWORD pcbNeeded)
4410 DWORD size, needed = 0, err;
4411 LPBYTE ptr = NULL;
4412 HKEY hkeyPrinter;
4413 BOOL ret;
4415 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4417 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4418 if (err)
4420 SetLastError( err );
4421 return FALSE;
4424 switch(Level) {
4425 case 2:
4427 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4429 size = sizeof(PRINTER_INFO_2W);
4430 if(size <= cbBuf) {
4431 ptr = pPrinter + size;
4432 cbBuf -= size;
4433 memset(pPrinter, 0, size);
4434 } else {
4435 pi2 = NULL;
4436 cbBuf = 0;
4438 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4439 needed += size;
4440 break;
4443 case 4:
4445 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4447 size = sizeof(PRINTER_INFO_4W);
4448 if(size <= cbBuf) {
4449 ptr = pPrinter + size;
4450 cbBuf -= size;
4451 memset(pPrinter, 0, size);
4452 } else {
4453 pi4 = NULL;
4454 cbBuf = 0;
4456 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4457 needed += size;
4458 break;
4462 case 5:
4464 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4466 size = sizeof(PRINTER_INFO_5W);
4467 if(size <= cbBuf) {
4468 ptr = pPrinter + size;
4469 cbBuf -= size;
4470 memset(pPrinter, 0, size);
4471 } else {
4472 pi5 = NULL;
4473 cbBuf = 0;
4476 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4477 needed += size;
4478 break;
4482 case 6:
4484 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4486 size = sizeof(PRINTER_INFO_6);
4487 if (size <= cbBuf) {
4488 /* FIXME: We do not update the status yet */
4489 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4490 ret = TRUE;
4491 } else {
4492 ret = FALSE;
4495 needed += size;
4496 break;
4499 case 7:
4501 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4503 size = sizeof(PRINTER_INFO_7W);
4504 if (size <= cbBuf) {
4505 ptr = pPrinter + size;
4506 cbBuf -= size;
4507 memset(pPrinter, 0, size);
4508 } else {
4509 pi7 = NULL;
4510 cbBuf = 0;
4513 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4514 needed += size;
4515 break;
4519 case 8:
4520 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4521 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4522 /* fall through */
4523 case 9:
4525 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4527 size = sizeof(PRINTER_INFO_9W);
4528 if(size <= cbBuf) {
4529 ptr = pPrinter + size;
4530 cbBuf -= size;
4531 memset(pPrinter, 0, size);
4532 } else {
4533 pi9 = NULL;
4534 cbBuf = 0;
4537 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4538 needed += size;
4539 break;
4543 default:
4544 FIXME("Unimplemented level %d\n", Level);
4545 SetLastError(ERROR_INVALID_LEVEL);
4546 RegCloseKey(hkeyPrinter);
4547 return FALSE;
4550 RegCloseKey(hkeyPrinter);
4552 TRACE("returning %d needed = %d\n", ret, needed);
4553 if(pcbNeeded) *pcbNeeded = needed;
4554 if(!ret)
4555 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4556 return ret;
4559 /*****************************************************************************
4560 * GetPrinterA [WINSPOOL.@]
4562 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4563 DWORD cbBuf, LPDWORD pcbNeeded)
4565 BOOL ret;
4566 LPBYTE buf = NULL;
4568 if (cbBuf)
4569 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4571 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4572 if (ret)
4573 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4574 HeapFree(GetProcessHeap(), 0, buf);
4576 return ret;
4579 /*****************************************************************************
4580 * WINSPOOL_EnumPrintersW
4582 * Implementation of EnumPrintersW
4584 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4585 DWORD dwLevel, LPBYTE lpbPrinters,
4586 DWORD cbBuf, LPDWORD lpdwNeeded,
4587 LPDWORD lpdwReturned)
4590 HKEY hkeyPrinters, hkeyPrinter;
4591 WCHAR PrinterName[255];
4592 DWORD needed = 0, number = 0;
4593 DWORD used, i, left;
4594 PBYTE pi, buf;
4596 if(lpbPrinters)
4597 memset(lpbPrinters, 0, cbBuf);
4598 if(lpdwReturned)
4599 *lpdwReturned = 0;
4600 if(lpdwNeeded)
4601 *lpdwNeeded = 0;
4603 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4604 if(dwType == PRINTER_ENUM_DEFAULT)
4605 return TRUE;
4607 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4608 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4609 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4610 if (!dwType) {
4611 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4612 return TRUE;
4617 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4618 FIXME("dwType = %08x\n", dwType);
4619 SetLastError(ERROR_INVALID_FLAGS);
4620 return FALSE;
4623 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4624 ERROR_SUCCESS) {
4625 ERR("Can't create Printers key\n");
4626 return FALSE;
4629 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4630 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4631 RegCloseKey(hkeyPrinters);
4632 ERR("Can't query Printers key\n");
4633 return FALSE;
4635 TRACE("Found %d printers\n", number);
4637 switch(dwLevel) {
4638 case 1:
4639 used = number * sizeof(PRINTER_INFO_1W);
4640 break;
4641 case 2:
4642 used = number * sizeof(PRINTER_INFO_2W);
4643 break;
4644 case 4:
4645 used = number * sizeof(PRINTER_INFO_4W);
4646 break;
4647 case 5:
4648 used = number * sizeof(PRINTER_INFO_5W);
4649 break;
4651 default:
4652 SetLastError(ERROR_INVALID_LEVEL);
4653 RegCloseKey(hkeyPrinters);
4654 return FALSE;
4656 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4658 for(i = 0; i < number; i++) {
4659 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4660 ERROR_SUCCESS) {
4661 ERR("Can't enum key number %d\n", i);
4662 RegCloseKey(hkeyPrinters);
4663 return FALSE;
4665 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4666 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4667 ERROR_SUCCESS) {
4668 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4669 RegCloseKey(hkeyPrinters);
4670 return FALSE;
4673 if(cbBuf > used) {
4674 buf = lpbPrinters + used;
4675 left = cbBuf - used;
4676 } else {
4677 buf = NULL;
4678 left = 0;
4681 switch(dwLevel) {
4682 case 1:
4683 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4684 left, &needed);
4685 used += needed;
4686 if(pi) pi += sizeof(PRINTER_INFO_1W);
4687 break;
4688 case 2:
4689 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4690 left, &needed);
4691 used += needed;
4692 if(pi) pi += sizeof(PRINTER_INFO_2W);
4693 break;
4694 case 4:
4695 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4696 left, &needed);
4697 used += needed;
4698 if(pi) pi += sizeof(PRINTER_INFO_4W);
4699 break;
4700 case 5:
4701 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4702 left, &needed);
4703 used += needed;
4704 if(pi) pi += sizeof(PRINTER_INFO_5W);
4705 break;
4706 default:
4707 ERR("Shouldn't be here!\n");
4708 RegCloseKey(hkeyPrinter);
4709 RegCloseKey(hkeyPrinters);
4710 return FALSE;
4712 RegCloseKey(hkeyPrinter);
4714 RegCloseKey(hkeyPrinters);
4716 if(lpdwNeeded)
4717 *lpdwNeeded = used;
4719 if(used > cbBuf) {
4720 if(lpbPrinters)
4721 memset(lpbPrinters, 0, cbBuf);
4722 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4723 return FALSE;
4725 if(lpdwReturned)
4726 *lpdwReturned = number;
4727 SetLastError(ERROR_SUCCESS);
4728 return TRUE;
4732 /******************************************************************
4733 * EnumPrintersW [WINSPOOL.@]
4735 * Enumerates the available printers, print servers and print
4736 * providers, depending on the specified flags, name and level.
4738 * RETURNS:
4740 * If level is set to 1:
4741 * Returns an array of PRINTER_INFO_1 data structures in the
4742 * lpbPrinters buffer.
4744 * If level is set to 2:
4745 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4746 * Returns an array of PRINTER_INFO_2 data structures in the
4747 * lpbPrinters buffer. Note that according to MSDN also an
4748 * OpenPrinter should be performed on every remote printer.
4750 * If level is set to 4 (officially WinNT only):
4751 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4752 * Fast: Only the registry is queried to retrieve printer names,
4753 * no connection to the driver is made.
4754 * Returns an array of PRINTER_INFO_4 data structures in the
4755 * lpbPrinters buffer.
4757 * If level is set to 5 (officially WinNT4/Win9x only):
4758 * Fast: Only the registry is queried to retrieve printer names,
4759 * no connection to the driver is made.
4760 * Returns an array of PRINTER_INFO_5 data structures in the
4761 * lpbPrinters buffer.
4763 * If level set to 3 or 6+:
4764 * returns zero (failure!)
4766 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4767 * for information.
4769 * BUGS:
4770 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4771 * - Only levels 2, 4 and 5 are implemented at the moment.
4772 * - 16-bit printer drivers are not enumerated.
4773 * - Returned amount of bytes used/needed does not match the real Windoze
4774 * implementation (as in this implementation, all strings are part
4775 * of the buffer, whereas Win32 keeps them somewhere else)
4776 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4778 * NOTE:
4779 * - In a regular Wine installation, no registry settings for printers
4780 * exist, which makes this function return an empty list.
4782 BOOL WINAPI EnumPrintersW(
4783 DWORD dwType, /* [in] Types of print objects to enumerate */
4784 LPWSTR lpszName, /* [in] name of objects to enumerate */
4785 DWORD dwLevel, /* [in] type of printer info structure */
4786 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4787 DWORD cbBuf, /* [in] max size of buffer in bytes */
4788 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4789 LPDWORD lpdwReturned /* [out] number of entries returned */
4792 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4793 lpdwNeeded, lpdwReturned);
4796 /******************************************************************
4797 * EnumPrintersA [WINSPOOL.@]
4799 * See EnumPrintersW
4802 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4803 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4805 BOOL ret;
4806 UNICODE_STRING pNameU;
4807 LPWSTR pNameW;
4808 LPBYTE pPrintersW;
4810 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4811 pPrinters, cbBuf, pcbNeeded, pcReturned);
4813 pNameW = asciitounicode(&pNameU, pName);
4815 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4816 MS Office need this */
4817 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4819 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4821 RtlFreeUnicodeString(&pNameU);
4822 if (ret) {
4823 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4825 HeapFree(GetProcessHeap(), 0, pPrintersW);
4826 return ret;
4829 /*****************************************************************************
4830 * WINSPOOL_GetDriverInfoFromReg [internal]
4832 * Enters the information from the registry into the DRIVER_INFO struct
4834 * RETURNS
4835 * zero if the printer driver does not exist in the registry
4836 * (only if Level > 1) otherwise nonzero
4838 static BOOL WINSPOOL_GetDriverInfoFromReg(
4839 HKEY hkeyDrivers,
4840 LPWSTR DriverName,
4841 const printenv_t * env,
4842 DWORD Level,
4843 LPBYTE ptr, /* DRIVER_INFO */
4844 LPBYTE pDriverStrings, /* strings buffer */
4845 DWORD cbBuf, /* size of string buffer */
4846 LPDWORD pcbNeeded) /* space needed for str. */
4848 DWORD size, tmp;
4849 HKEY hkeyDriver;
4850 WCHAR driverdir[MAX_PATH];
4851 DWORD dirlen;
4852 LPBYTE strPtr = pDriverStrings;
4853 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4855 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4856 debugstr_w(DriverName), env,
4857 Level, di, pDriverStrings, cbBuf);
4859 if (di) ZeroMemory(di, di_sizeof[Level]);
4861 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4862 if (*pcbNeeded <= cbBuf)
4863 strcpyW((LPWSTR)strPtr, DriverName);
4865 /* pName for level 1 has a different offset! */
4866 if (Level == 1) {
4867 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4868 return TRUE;
4871 /* .cVersion and .pName for level > 1 */
4872 if (di) {
4873 di->cVersion = env->driverversion;
4874 di->pName = (LPWSTR) strPtr;
4875 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4878 /* Reserve Space for the largest subdir and a Backslash*/
4879 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4880 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4881 /* Should never Fail */
4882 return FALSE;
4884 lstrcatW(driverdir, env->versionsubdir);
4885 lstrcatW(driverdir, backslashW);
4887 /* dirlen must not include the terminating zero */
4888 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4890 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4891 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4892 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4893 return FALSE;
4896 /* pEnvironment */
4897 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4899 *pcbNeeded += size;
4900 if (*pcbNeeded <= cbBuf) {
4901 lstrcpyW((LPWSTR)strPtr, env->envname);
4902 if (di) di->pEnvironment = (LPWSTR)strPtr;
4903 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4906 /* .pDriverPath is the Graphics rendering engine.
4907 The full Path is required to avoid a crash in some apps */
4908 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4909 *pcbNeeded += size;
4910 if (*pcbNeeded <= cbBuf)
4911 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4913 if (di) di->pDriverPath = (LPWSTR)strPtr;
4914 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4917 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4918 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4919 *pcbNeeded += size;
4920 if (*pcbNeeded <= cbBuf)
4921 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4923 if (di) di->pDataFile = (LPWSTR)strPtr;
4924 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4927 /* .pConfigFile is the Driver user Interface */
4928 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4929 *pcbNeeded += size;
4930 if (*pcbNeeded <= cbBuf)
4931 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4933 if (di) di->pConfigFile = (LPWSTR)strPtr;
4934 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4937 if (Level == 2 ) {
4938 RegCloseKey(hkeyDriver);
4939 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4940 return TRUE;
4943 if (Level == 5 ) {
4944 RegCloseKey(hkeyDriver);
4945 FIXME("level 5: incomplete\n");
4946 return TRUE;
4949 /* .pHelpFile */
4950 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4951 *pcbNeeded += size;
4952 if (*pcbNeeded <= cbBuf)
4953 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4955 if (di) di->pHelpFile = (LPWSTR)strPtr;
4956 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4959 /* .pDependentFiles */
4960 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4961 *pcbNeeded += size;
4962 if (*pcbNeeded <= cbBuf)
4963 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4965 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4966 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4968 else if (GetVersion() & 0x80000000) {
4969 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4970 size = 2 * sizeof(WCHAR);
4971 *pcbNeeded += size;
4972 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4974 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4975 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4978 /* .pMonitorName is the optional Language Monitor */
4979 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4980 *pcbNeeded += size;
4981 if (*pcbNeeded <= cbBuf)
4982 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4984 if (di) di->pMonitorName = (LPWSTR)strPtr;
4985 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4988 /* .pDefaultDataType */
4989 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4990 *pcbNeeded += size;
4991 if(*pcbNeeded <= cbBuf)
4992 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4994 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4995 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4998 if (Level == 3 ) {
4999 RegCloseKey(hkeyDriver);
5000 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5001 return TRUE;
5004 /* .pszzPreviousNames */
5005 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
5006 *pcbNeeded += size;
5007 if(*pcbNeeded <= cbBuf)
5008 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
5010 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
5011 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5014 if (Level == 4 ) {
5015 RegCloseKey(hkeyDriver);
5016 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5017 return TRUE;
5020 /* support is missing, but not important enough for a FIXME */
5021 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5023 /* .pszMfgName */
5024 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5025 *pcbNeeded += size;
5026 if(*pcbNeeded <= cbBuf)
5027 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5029 if (di) di->pszMfgName = (LPWSTR)strPtr;
5030 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5033 /* .pszOEMUrl */
5034 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5035 *pcbNeeded += size;
5036 if(*pcbNeeded <= cbBuf)
5037 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5039 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5040 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5043 /* .pszHardwareID */
5044 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5045 *pcbNeeded += size;
5046 if(*pcbNeeded <= cbBuf)
5047 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5049 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5050 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5053 /* .pszProvider */
5054 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5055 *pcbNeeded += size;
5056 if(*pcbNeeded <= cbBuf)
5057 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5059 if (di) di->pszProvider = (LPWSTR)strPtr;
5060 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5063 if (Level == 6 ) {
5064 RegCloseKey(hkeyDriver);
5065 return TRUE;
5068 /* support is missing, but not important enough for a FIXME */
5069 TRACE("level 8: incomplete\n");
5071 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5072 RegCloseKey(hkeyDriver);
5073 return TRUE;
5076 /*****************************************************************************
5077 * GetPrinterDriverW [WINSPOOL.@]
5079 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5080 DWORD Level, LPBYTE pDriverInfo,
5081 DWORD cbBuf, LPDWORD pcbNeeded)
5083 LPCWSTR name;
5084 WCHAR DriverName[100];
5085 DWORD ret, type, size, needed = 0;
5086 LPBYTE ptr = NULL;
5087 HKEY hkeyPrinter, hkeyDrivers;
5088 const printenv_t * env;
5090 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5091 Level,pDriverInfo,cbBuf, pcbNeeded);
5093 if (cbBuf > 0)
5094 ZeroMemory(pDriverInfo, cbBuf);
5096 if (!(name = get_opened_printer_name(hPrinter))) {
5097 SetLastError(ERROR_INVALID_HANDLE);
5098 return FALSE;
5101 if (Level < 1 || Level == 7 || Level > 8) {
5102 SetLastError(ERROR_INVALID_LEVEL);
5103 return FALSE;
5106 env = validate_envW(pEnvironment);
5107 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5109 ret = open_printer_reg_key( name, &hkeyPrinter );
5110 if (ret)
5112 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5113 SetLastError( ret );
5114 return FALSE;
5117 size = sizeof(DriverName);
5118 DriverName[0] = 0;
5119 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5120 (LPBYTE)DriverName, &size);
5121 RegCloseKey(hkeyPrinter);
5122 if(ret != ERROR_SUCCESS) {
5123 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5124 return FALSE;
5127 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5128 if(!hkeyDrivers) {
5129 ERR("Can't create Drivers key\n");
5130 return FALSE;
5133 size = di_sizeof[Level];
5134 if ((size <= cbBuf) && pDriverInfo)
5135 ptr = pDriverInfo + size;
5137 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5138 env, Level, pDriverInfo, ptr,
5139 (cbBuf < size) ? 0 : cbBuf - size,
5140 &needed)) {
5141 RegCloseKey(hkeyDrivers);
5142 return FALSE;
5145 RegCloseKey(hkeyDrivers);
5147 if(pcbNeeded) *pcbNeeded = size + needed;
5148 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5149 if(cbBuf >= size + needed) return TRUE;
5150 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5151 return FALSE;
5154 /*****************************************************************************
5155 * GetPrinterDriverA [WINSPOOL.@]
5157 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5158 DWORD Level, LPBYTE pDriverInfo,
5159 DWORD cbBuf, LPDWORD pcbNeeded)
5161 BOOL ret;
5162 UNICODE_STRING pEnvW;
5163 PWSTR pwstrEnvW;
5164 LPBYTE buf = NULL;
5166 if (cbBuf)
5168 ZeroMemory(pDriverInfo, cbBuf);
5169 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5172 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5173 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5174 cbBuf, pcbNeeded);
5175 if (ret)
5176 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5178 HeapFree(GetProcessHeap(), 0, buf);
5180 RtlFreeUnicodeString(&pEnvW);
5181 return ret;
5184 /*****************************************************************************
5185 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5187 * Return the PATH for the Printer-Drivers (UNICODE)
5189 * PARAMS
5190 * pName [I] Servername (NT only) or NULL (local Computer)
5191 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5192 * Level [I] Structure-Level (must be 1)
5193 * pDriverDirectory [O] PTR to Buffer that receives the Result
5194 * cbBuf [I] Size of Buffer at pDriverDirectory
5195 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5196 * required for pDriverDirectory
5198 * RETURNS
5199 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5200 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5201 * if cbBuf is too small
5203 * Native Values returned in pDriverDirectory on Success:
5204 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5205 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5206 *| win9x(Windows 4.0): "%winsysdir%"
5208 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5210 * FIXME
5211 *- Only NULL or "" is supported for pName
5214 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5215 DWORD Level, LPBYTE pDriverDirectory,
5216 DWORD cbBuf, LPDWORD pcbNeeded)
5218 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5219 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5221 if ((backend == NULL) && !load_backend()) return FALSE;
5223 if (Level != 1) {
5224 /* (Level != 1) is ignored in win9x */
5225 SetLastError(ERROR_INVALID_LEVEL);
5226 return FALSE;
5228 if (pcbNeeded == NULL) {
5229 /* (pcbNeeded == NULL) is ignored in win9x */
5230 SetLastError(RPC_X_NULL_REF_POINTER);
5231 return FALSE;
5234 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5235 pDriverDirectory, cbBuf, pcbNeeded);
5240 /*****************************************************************************
5241 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5243 * Return the PATH for the Printer-Drivers (ANSI)
5245 * See GetPrinterDriverDirectoryW.
5247 * NOTES
5248 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5251 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5252 DWORD Level, LPBYTE pDriverDirectory,
5253 DWORD cbBuf, LPDWORD pcbNeeded)
5255 UNICODE_STRING nameW, environmentW;
5256 BOOL ret;
5257 DWORD pcbNeededW;
5258 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5259 WCHAR *driverDirectoryW = NULL;
5261 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5262 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5264 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5266 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5267 else nameW.Buffer = NULL;
5268 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5269 else environmentW.Buffer = NULL;
5271 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5272 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5273 if (ret) {
5274 DWORD needed;
5275 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5276 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5277 if(pcbNeeded)
5278 *pcbNeeded = needed;
5279 ret = needed <= cbBuf;
5280 } else
5281 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5283 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5285 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5286 RtlFreeUnicodeString(&environmentW);
5287 RtlFreeUnicodeString(&nameW);
5289 return ret;
5292 /*****************************************************************************
5293 * AddPrinterDriverA [WINSPOOL.@]
5295 * See AddPrinterDriverW.
5298 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5300 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5301 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5304 /******************************************************************************
5305 * AddPrinterDriverW (WINSPOOL.@)
5307 * Install a Printer Driver
5309 * PARAMS
5310 * pName [I] Servername or NULL (local Computer)
5311 * level [I] Level for the supplied DRIVER_INFO_*W struct
5312 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5314 * RESULTS
5315 * Success: TRUE
5316 * Failure: FALSE
5319 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5321 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5322 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5325 /*****************************************************************************
5326 * AddPrintProcessorA [WINSPOOL.@]
5328 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5329 LPSTR pPrintProcessorName)
5331 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5332 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5333 return FALSE;
5336 /*****************************************************************************
5337 * AddPrintProcessorW [WINSPOOL.@]
5339 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5340 LPWSTR pPrintProcessorName)
5342 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5343 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5344 return TRUE;
5347 /*****************************************************************************
5348 * AddPrintProvidorA [WINSPOOL.@]
5350 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5352 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5353 return FALSE;
5356 /*****************************************************************************
5357 * AddPrintProvidorW [WINSPOOL.@]
5359 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5361 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5362 return FALSE;
5365 /*****************************************************************************
5366 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5368 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5369 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5371 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5372 pDevModeOutput, pDevModeInput);
5373 return 0;
5376 /*****************************************************************************
5377 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5379 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5380 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5382 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5383 pDevModeOutput, pDevModeInput);
5384 return 0;
5387 /*****************************************************************************
5388 * PrinterProperties [WINSPOOL.@]
5390 * Displays a dialog to set the properties of the printer.
5392 * RETURNS
5393 * nonzero on success or zero on failure
5395 * BUGS
5396 * implemented as stub only
5398 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5399 HANDLE hPrinter /* [in] handle to printer object */
5401 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5402 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5403 return FALSE;
5406 /*****************************************************************************
5407 * EnumJobsA [WINSPOOL.@]
5410 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5411 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5412 LPDWORD pcReturned)
5414 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5415 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5417 if(pcbNeeded) *pcbNeeded = 0;
5418 if(pcReturned) *pcReturned = 0;
5419 return FALSE;
5423 /*****************************************************************************
5424 * EnumJobsW [WINSPOOL.@]
5427 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5428 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5429 LPDWORD pcReturned)
5431 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5432 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5434 if(pcbNeeded) *pcbNeeded = 0;
5435 if(pcReturned) *pcReturned = 0;
5436 return FALSE;
5439 /*****************************************************************************
5440 * WINSPOOL_EnumPrinterDrivers [internal]
5442 * Delivers information about all printer drivers installed on the
5443 * localhost or a given server
5445 * RETURNS
5446 * nonzero on success or zero on failure. If the buffer for the returned
5447 * information is too small the function will return an error
5449 * BUGS
5450 * - only implemented for localhost, foreign hosts will return an error
5452 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5453 DWORD Level, LPBYTE pDriverInfo,
5454 DWORD driver_index,
5455 DWORD cbBuf, LPDWORD pcbNeeded,
5456 LPDWORD pcFound, DWORD data_offset)
5458 { HKEY hkeyDrivers;
5459 DWORD i, size = 0;
5460 const printenv_t * env;
5462 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5463 debugstr_w(pName), debugstr_w(pEnvironment),
5464 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5466 env = validate_envW(pEnvironment);
5467 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5469 *pcFound = 0;
5471 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5472 if(!hkeyDrivers) {
5473 ERR("Can't open Drivers key\n");
5474 return FALSE;
5477 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5478 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5479 RegCloseKey(hkeyDrivers);
5480 ERR("Can't query Drivers key\n");
5481 return FALSE;
5483 TRACE("Found %d Drivers\n", *pcFound);
5485 /* get size of single struct
5486 * unicode and ascii structure have the same size
5488 size = di_sizeof[Level];
5490 if (data_offset == 0)
5491 data_offset = size * (*pcFound);
5492 *pcbNeeded = data_offset;
5494 for( i = 0; i < *pcFound; i++) {
5495 WCHAR DriverNameW[255];
5496 PBYTE table_ptr = NULL;
5497 PBYTE data_ptr = NULL;
5498 DWORD needed = 0;
5500 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5501 != ERROR_SUCCESS) {
5502 ERR("Can't enum key number %d\n", i);
5503 RegCloseKey(hkeyDrivers);
5504 return FALSE;
5507 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5508 table_ptr = pDriverInfo + (driver_index + i) * size;
5509 if (pDriverInfo && *pcbNeeded <= cbBuf)
5510 data_ptr = pDriverInfo + *pcbNeeded;
5512 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5513 env, Level, table_ptr, data_ptr,
5514 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5515 &needed)) {
5516 RegCloseKey(hkeyDrivers);
5517 return FALSE;
5520 *pcbNeeded += needed;
5523 RegCloseKey(hkeyDrivers);
5525 if(cbBuf < *pcbNeeded){
5526 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5527 return FALSE;
5530 return TRUE;
5533 /*****************************************************************************
5534 * EnumPrinterDriversW [WINSPOOL.@]
5536 * see function EnumPrinterDrivers for RETURNS, BUGS
5538 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5539 LPBYTE pDriverInfo, DWORD cbBuf,
5540 LPDWORD pcbNeeded, LPDWORD pcReturned)
5542 static const WCHAR allW[] = {'a','l','l',0};
5543 BOOL ret;
5544 DWORD found;
5546 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5548 SetLastError(RPC_X_NULL_REF_POINTER);
5549 return FALSE;
5552 /* check for local drivers */
5553 if((pName) && (pName[0])) {
5554 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5555 SetLastError(ERROR_ACCESS_DENIED);
5556 return FALSE;
5559 /* check input parameter */
5560 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5561 SetLastError(ERROR_INVALID_LEVEL);
5562 return FALSE;
5565 if(pDriverInfo && cbBuf > 0)
5566 memset( pDriverInfo, 0, cbBuf);
5568 /* Exception: pull all printers */
5569 if (pEnvironment && !strcmpW(pEnvironment, allW))
5571 DWORD i, needed, bufsize = cbBuf;
5572 DWORD total_found = 0;
5573 DWORD data_offset;
5575 /* Precompute the overall total; we need this to know
5576 where pointers end and data begins (i.e. data_offset) */
5577 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5579 needed = found = 0;
5580 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5581 NULL, 0, 0, &needed, &found, 0);
5582 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5583 total_found += found;
5586 data_offset = di_sizeof[Level] * total_found;
5588 *pcReturned = 0;
5589 *pcbNeeded = 0;
5590 total_found = 0;
5591 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5593 needed = found = 0;
5594 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5595 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5596 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5597 else if (ret)
5598 *pcReturned += found;
5599 *pcbNeeded = needed;
5600 data_offset = needed;
5601 total_found += found;
5603 return ret;
5606 /* Normal behavior */
5607 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5608 0, cbBuf, pcbNeeded, &found, 0);
5609 if (ret)
5610 *pcReturned = found;
5612 return ret;
5615 /*****************************************************************************
5616 * EnumPrinterDriversA [WINSPOOL.@]
5618 * see function EnumPrinterDrivers for RETURNS, BUGS
5620 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5621 LPBYTE pDriverInfo, DWORD cbBuf,
5622 LPDWORD pcbNeeded, LPDWORD pcReturned)
5624 BOOL ret;
5625 UNICODE_STRING pNameW, pEnvironmentW;
5626 PWSTR pwstrNameW, pwstrEnvironmentW;
5627 LPBYTE buf = NULL;
5629 if (cbBuf)
5630 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5632 pwstrNameW = asciitounicode(&pNameW, pName);
5633 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5635 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5636 buf, cbBuf, pcbNeeded, pcReturned);
5637 if (ret)
5638 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5640 HeapFree(GetProcessHeap(), 0, buf);
5642 RtlFreeUnicodeString(&pNameW);
5643 RtlFreeUnicodeString(&pEnvironmentW);
5645 return ret;
5648 /******************************************************************************
5649 * EnumPortsA (WINSPOOL.@)
5651 * See EnumPortsW.
5654 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5655 LPDWORD pcbNeeded, LPDWORD pcReturned)
5657 BOOL res;
5658 LPBYTE bufferW = NULL;
5659 LPWSTR nameW = NULL;
5660 DWORD needed = 0;
5661 DWORD numentries = 0;
5662 INT len;
5664 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5665 cbBuf, pcbNeeded, pcReturned);
5667 /* convert servername to unicode */
5668 if (pName) {
5669 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5670 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5671 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5673 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5674 needed = cbBuf * sizeof(WCHAR);
5675 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5676 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5678 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5679 if (pcbNeeded) needed = *pcbNeeded;
5680 /* HeapReAlloc return NULL, when bufferW was NULL */
5681 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5682 HeapAlloc(GetProcessHeap(), 0, needed);
5684 /* Try again with the large Buffer */
5685 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5687 needed = pcbNeeded ? *pcbNeeded : 0;
5688 numentries = pcReturned ? *pcReturned : 0;
5691 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5692 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5694 if (res) {
5695 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5696 DWORD entrysize = 0;
5697 DWORD index;
5698 LPSTR ptr;
5699 LPPORT_INFO_2W pi2w;
5700 LPPORT_INFO_2A pi2a;
5702 needed = 0;
5703 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5705 /* First pass: calculate the size for all Entries */
5706 pi2w = (LPPORT_INFO_2W) bufferW;
5707 pi2a = (LPPORT_INFO_2A) pPorts;
5708 index = 0;
5709 while (index < numentries) {
5710 index++;
5711 needed += entrysize; /* PORT_INFO_?A */
5712 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5714 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5715 NULL, 0, NULL, NULL);
5716 if (Level > 1) {
5717 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5718 NULL, 0, NULL, NULL);
5719 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5720 NULL, 0, NULL, NULL);
5722 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5723 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5724 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5727 /* check for errors and quit on failure */
5728 if (cbBuf < needed) {
5729 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5730 res = FALSE;
5731 goto cleanup;
5733 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5734 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5735 cbBuf -= len ; /* free Bytes in the user-Buffer */
5736 pi2w = (LPPORT_INFO_2W) bufferW;
5737 pi2a = (LPPORT_INFO_2A) pPorts;
5738 index = 0;
5739 /* Second Pass: Fill the User Buffer (if we have one) */
5740 while ((index < numentries) && pPorts) {
5741 index++;
5742 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5743 pi2a->pPortName = ptr;
5744 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5745 ptr, cbBuf , NULL, NULL);
5746 ptr += len;
5747 cbBuf -= len;
5748 if (Level > 1) {
5749 pi2a->pMonitorName = ptr;
5750 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5751 ptr, cbBuf, NULL, NULL);
5752 ptr += len;
5753 cbBuf -= len;
5755 pi2a->pDescription = ptr;
5756 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5757 ptr, cbBuf, NULL, NULL);
5758 ptr += len;
5759 cbBuf -= len;
5761 pi2a->fPortType = pi2w->fPortType;
5762 pi2a->Reserved = 0; /* documented: "must be zero" */
5765 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5766 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5767 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5771 cleanup:
5772 if (pcbNeeded) *pcbNeeded = needed;
5773 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5775 HeapFree(GetProcessHeap(), 0, nameW);
5776 HeapFree(GetProcessHeap(), 0, bufferW);
5778 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5779 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5781 return (res);
5785 /******************************************************************************
5786 * EnumPortsW (WINSPOOL.@)
5788 * Enumerate available Ports
5790 * PARAMS
5791 * pName [I] Servername or NULL (local Computer)
5792 * Level [I] Structure-Level (1 or 2)
5793 * pPorts [O] PTR to Buffer that receives the Result
5794 * cbBuf [I] Size of Buffer at pPorts
5795 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5796 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5798 * RETURNS
5799 * Success: TRUE
5800 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5803 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5806 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5807 cbBuf, pcbNeeded, pcReturned);
5809 if ((backend == NULL) && !load_backend()) return FALSE;
5811 /* Level is not checked in win9x */
5812 if (!Level || (Level > 2)) {
5813 WARN("level (%d) is ignored in win9x\n", Level);
5814 SetLastError(ERROR_INVALID_LEVEL);
5815 return FALSE;
5817 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5818 SetLastError(RPC_X_NULL_REF_POINTER);
5819 return FALSE;
5822 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5825 /******************************************************************************
5826 * GetDefaultPrinterW (WINSPOOL.@)
5828 * FIXME
5829 * This function must read the value from data 'device' of key
5830 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5832 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5834 BOOL retval = TRUE;
5835 DWORD insize, len;
5836 WCHAR *buffer, *ptr;
5838 if (!namesize)
5840 SetLastError(ERROR_INVALID_PARAMETER);
5841 return FALSE;
5844 /* make the buffer big enough for the stuff from the profile/registry,
5845 * the content must fit into the local buffer to compute the correct
5846 * size even if the extern buffer is too small or not given.
5847 * (20 for ,driver,port) */
5848 insize = *namesize;
5849 len = max(100, (insize + 20));
5850 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5852 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5854 SetLastError (ERROR_FILE_NOT_FOUND);
5855 retval = FALSE;
5856 goto end;
5858 TRACE("%s\n", debugstr_w(buffer));
5860 if ((ptr = strchrW(buffer, ',')) == NULL)
5862 SetLastError(ERROR_INVALID_NAME);
5863 retval = FALSE;
5864 goto end;
5867 *ptr = 0;
5868 *namesize = strlenW(buffer) + 1;
5869 if(!name || (*namesize > insize))
5871 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5872 retval = FALSE;
5873 goto end;
5875 strcpyW(name, buffer);
5877 end:
5878 HeapFree( GetProcessHeap(), 0, buffer);
5879 return retval;
5883 /******************************************************************************
5884 * GetDefaultPrinterA (WINSPOOL.@)
5886 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5888 BOOL retval = TRUE;
5889 DWORD insize = 0;
5890 WCHAR *bufferW = NULL;
5892 if (!namesize)
5894 SetLastError(ERROR_INVALID_PARAMETER);
5895 return FALSE;
5898 if(name && *namesize) {
5899 insize = *namesize;
5900 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5903 if(!GetDefaultPrinterW( bufferW, namesize)) {
5904 retval = FALSE;
5905 goto end;
5908 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5909 NULL, NULL);
5910 if (!*namesize)
5912 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5913 retval = FALSE;
5915 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5917 end:
5918 HeapFree( GetProcessHeap(), 0, bufferW);
5919 return retval;
5923 /******************************************************************************
5924 * SetDefaultPrinterW (WINSPOOL.204)
5926 * Set the Name of the Default Printer
5928 * PARAMS
5929 * pszPrinter [I] Name of the Printer or NULL
5931 * RETURNS
5932 * Success: True
5933 * Failure: FALSE
5935 * NOTES
5936 * When the Parameter is NULL or points to an Empty String and
5937 * a Default Printer was already present, then this Function changes nothing.
5938 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5939 * the First enumerated local Printer is used.
5942 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5944 WCHAR default_printer[MAX_PATH];
5945 LPWSTR buffer = NULL;
5946 HKEY hreg;
5947 DWORD size;
5948 DWORD namelen;
5949 LONG lres;
5951 TRACE("(%s)\n", debugstr_w(pszPrinter));
5952 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5954 default_printer[0] = '\0';
5955 size = sizeof(default_printer)/sizeof(WCHAR);
5957 /* if we have a default Printer, do nothing. */
5958 if (GetDefaultPrinterW(default_printer, &size))
5959 return TRUE;
5961 pszPrinter = NULL;
5962 /* we have no default Printer: search local Printers and use the first */
5963 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5965 default_printer[0] = '\0';
5966 size = sizeof(default_printer)/sizeof(WCHAR);
5967 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5969 pszPrinter = default_printer;
5970 TRACE("using %s\n", debugstr_w(pszPrinter));
5972 RegCloseKey(hreg);
5975 if (pszPrinter == NULL) {
5976 TRACE("no local printer found\n");
5977 SetLastError(ERROR_FILE_NOT_FOUND);
5978 return FALSE;
5982 /* "pszPrinter" is never empty or NULL here. */
5983 namelen = lstrlenW(pszPrinter);
5984 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5985 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5986 if (!buffer ||
5987 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5988 HeapFree(GetProcessHeap(), 0, buffer);
5989 SetLastError(ERROR_FILE_NOT_FOUND);
5990 return FALSE;
5993 /* read the devices entry for the printer (driver,port) to build the string for the
5994 default device entry (printer,driver,port) */
5995 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5996 buffer[namelen] = ',';
5997 namelen++; /* move index to the start of the driver */
5999 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
6000 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
6001 if (!lres) {
6002 TRACE("set device to %s\n", debugstr_w(buffer));
6004 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
6005 TRACE("failed to set the device entry: %d\n", GetLastError());
6006 lres = ERROR_INVALID_PRINTER_NAME;
6009 /* remove the next section, when INIFileMapping is implemented */
6011 HKEY hdev;
6012 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
6013 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6014 RegCloseKey(hdev);
6018 else
6020 if (lres != ERROR_FILE_NOT_FOUND)
6021 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6023 SetLastError(ERROR_INVALID_PRINTER_NAME);
6026 RegCloseKey(hreg);
6027 HeapFree(GetProcessHeap(), 0, buffer);
6028 return (lres == ERROR_SUCCESS);
6031 /******************************************************************************
6032 * SetDefaultPrinterA (WINSPOOL.202)
6034 * See SetDefaultPrinterW.
6037 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6039 LPWSTR bufferW = NULL;
6040 BOOL res;
6042 TRACE("(%s)\n", debugstr_a(pszPrinter));
6043 if(pszPrinter) {
6044 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6045 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6046 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6048 res = SetDefaultPrinterW(bufferW);
6049 HeapFree(GetProcessHeap(), 0, bufferW);
6050 return res;
6053 /******************************************************************************
6054 * SetPrinterDataExA (WINSPOOL.@)
6056 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6057 LPCSTR pValueName, DWORD Type,
6058 LPBYTE pData, DWORD cbData)
6060 HKEY hkeyPrinter, hkeySubkey;
6061 DWORD ret;
6063 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6064 debugstr_a(pValueName), Type, pData, cbData);
6066 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6067 != ERROR_SUCCESS)
6068 return ret;
6070 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6071 != ERROR_SUCCESS) {
6072 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6073 RegCloseKey(hkeyPrinter);
6074 return ret;
6076 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6077 RegCloseKey(hkeySubkey);
6078 RegCloseKey(hkeyPrinter);
6079 return ret;
6082 /******************************************************************************
6083 * SetPrinterDataExW (WINSPOOL.@)
6085 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6086 LPCWSTR pValueName, DWORD Type,
6087 LPBYTE pData, DWORD cbData)
6089 HKEY hkeyPrinter, hkeySubkey;
6090 DWORD ret;
6092 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6093 debugstr_w(pValueName), Type, pData, cbData);
6095 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6096 != ERROR_SUCCESS)
6097 return ret;
6099 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6100 != ERROR_SUCCESS) {
6101 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6102 RegCloseKey(hkeyPrinter);
6103 return ret;
6105 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6106 RegCloseKey(hkeySubkey);
6107 RegCloseKey(hkeyPrinter);
6108 return ret;
6111 /******************************************************************************
6112 * SetPrinterDataA (WINSPOOL.@)
6114 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6115 LPBYTE pData, DWORD cbData)
6117 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6118 pData, cbData);
6121 /******************************************************************************
6122 * SetPrinterDataW (WINSPOOL.@)
6124 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6125 LPBYTE pData, DWORD cbData)
6127 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6128 pData, cbData);
6131 /******************************************************************************
6132 * GetPrinterDataExA (WINSPOOL.@)
6134 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6135 LPCSTR pValueName, LPDWORD pType,
6136 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6138 opened_printer_t *printer;
6139 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6140 DWORD ret;
6142 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6143 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6145 printer = get_opened_printer(hPrinter);
6146 if(!printer) return ERROR_INVALID_HANDLE;
6148 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6149 if (ret) return ret;
6151 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6153 if (printer->name) {
6155 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6156 if (ret) {
6157 RegCloseKey(hkeyPrinters);
6158 return ret;
6160 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6161 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6162 RegCloseKey(hkeyPrinter);
6163 RegCloseKey(hkeyPrinters);
6164 return ret;
6167 *pcbNeeded = nSize;
6168 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6169 0, pType, pData, pcbNeeded);
6171 if (!ret && !pData) ret = ERROR_MORE_DATA;
6173 RegCloseKey(hkeySubkey);
6174 RegCloseKey(hkeyPrinter);
6175 RegCloseKey(hkeyPrinters);
6177 TRACE("--> %d\n", ret);
6178 return ret;
6181 /******************************************************************************
6182 * GetPrinterDataExW (WINSPOOL.@)
6184 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6185 LPCWSTR pValueName, LPDWORD pType,
6186 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6188 opened_printer_t *printer;
6189 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6190 DWORD ret;
6192 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6193 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6195 printer = get_opened_printer(hPrinter);
6196 if(!printer) return ERROR_INVALID_HANDLE;
6198 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6199 if (ret) return ret;
6201 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6203 if (printer->name) {
6205 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6206 if (ret) {
6207 RegCloseKey(hkeyPrinters);
6208 return ret;
6210 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6211 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6212 RegCloseKey(hkeyPrinter);
6213 RegCloseKey(hkeyPrinters);
6214 return ret;
6217 *pcbNeeded = nSize;
6218 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6219 0, pType, pData, pcbNeeded);
6221 if (!ret && !pData) ret = ERROR_MORE_DATA;
6223 RegCloseKey(hkeySubkey);
6224 RegCloseKey(hkeyPrinter);
6225 RegCloseKey(hkeyPrinters);
6227 TRACE("--> %d\n", ret);
6228 return ret;
6231 /******************************************************************************
6232 * GetPrinterDataA (WINSPOOL.@)
6234 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6235 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6237 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6238 pData, nSize, pcbNeeded);
6241 /******************************************************************************
6242 * GetPrinterDataW (WINSPOOL.@)
6244 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6245 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6247 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6248 pData, nSize, pcbNeeded);
6251 /*******************************************************************************
6252 * EnumPrinterDataExW [WINSPOOL.@]
6254 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6255 LPBYTE pEnumValues, DWORD cbEnumValues,
6256 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6258 HKEY hkPrinter, hkSubKey;
6259 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6260 cbValueNameLen, cbMaxValueLen, cbValueLen,
6261 cbBufSize, dwType;
6262 LPWSTR lpValueName;
6263 HANDLE hHeap;
6264 PBYTE lpValue;
6265 PPRINTER_ENUM_VALUESW ppev;
6267 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6269 if (pKeyName == NULL || *pKeyName == 0)
6270 return ERROR_INVALID_PARAMETER;
6272 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6273 if (ret != ERROR_SUCCESS)
6275 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6276 hPrinter, ret);
6277 return ret;
6280 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6281 if (ret != ERROR_SUCCESS)
6283 r = RegCloseKey (hkPrinter);
6284 if (r != ERROR_SUCCESS)
6285 WARN ("RegCloseKey returned %i\n", r);
6286 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6287 debugstr_w (pKeyName), ret);
6288 return ret;
6291 ret = RegCloseKey (hkPrinter);
6292 if (ret != ERROR_SUCCESS)
6294 ERR ("RegCloseKey returned %i\n", ret);
6295 r = RegCloseKey (hkSubKey);
6296 if (r != ERROR_SUCCESS)
6297 WARN ("RegCloseKey returned %i\n", r);
6298 return ret;
6301 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6302 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6303 if (ret != ERROR_SUCCESS)
6305 r = RegCloseKey (hkSubKey);
6306 if (r != ERROR_SUCCESS)
6307 WARN ("RegCloseKey returned %i\n", r);
6308 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6309 return ret;
6312 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6313 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6315 if (cValues == 0) /* empty key */
6317 r = RegCloseKey (hkSubKey);
6318 if (r != ERROR_SUCCESS)
6319 WARN ("RegCloseKey returned %i\n", r);
6320 *pcbEnumValues = *pnEnumValues = 0;
6321 return ERROR_SUCCESS;
6324 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6326 hHeap = GetProcessHeap ();
6327 if (hHeap == NULL)
6329 ERR ("GetProcessHeap failed\n");
6330 r = RegCloseKey (hkSubKey);
6331 if (r != ERROR_SUCCESS)
6332 WARN ("RegCloseKey returned %i\n", r);
6333 return ERROR_OUTOFMEMORY;
6336 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6337 if (lpValueName == NULL)
6339 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6340 r = RegCloseKey (hkSubKey);
6341 if (r != ERROR_SUCCESS)
6342 WARN ("RegCloseKey returned %i\n", r);
6343 return ERROR_OUTOFMEMORY;
6346 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6347 if (lpValue == NULL)
6349 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6350 if (HeapFree (hHeap, 0, lpValueName) == 0)
6351 WARN ("HeapFree failed with code %i\n", GetLastError ());
6352 r = RegCloseKey (hkSubKey);
6353 if (r != ERROR_SUCCESS)
6354 WARN ("RegCloseKey returned %i\n", r);
6355 return ERROR_OUTOFMEMORY;
6358 TRACE ("pass 1: calculating buffer required for all names and values\n");
6360 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6362 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6364 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6366 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6367 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6368 NULL, NULL, lpValue, &cbValueLen);
6369 if (ret != ERROR_SUCCESS)
6371 if (HeapFree (hHeap, 0, lpValue) == 0)
6372 WARN ("HeapFree failed with code %i\n", GetLastError ());
6373 if (HeapFree (hHeap, 0, lpValueName) == 0)
6374 WARN ("HeapFree failed with code %i\n", GetLastError ());
6375 r = RegCloseKey (hkSubKey);
6376 if (r != ERROR_SUCCESS)
6377 WARN ("RegCloseKey returned %i\n", r);
6378 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6379 return ret;
6382 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6383 debugstr_w (lpValueName), dwIndex,
6384 cbValueNameLen + 1, cbValueLen);
6386 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6387 cbBufSize += cbValueLen;
6390 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6392 *pcbEnumValues = cbBufSize;
6393 *pnEnumValues = cValues;
6395 if (cbEnumValues < cbBufSize) /* buffer too small */
6397 if (HeapFree (hHeap, 0, lpValue) == 0)
6398 WARN ("HeapFree failed with code %i\n", GetLastError ());
6399 if (HeapFree (hHeap, 0, lpValueName) == 0)
6400 WARN ("HeapFree failed with code %i\n", GetLastError ());
6401 r = RegCloseKey (hkSubKey);
6402 if (r != ERROR_SUCCESS)
6403 WARN ("RegCloseKey returned %i\n", r);
6404 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6405 return ERROR_MORE_DATA;
6408 TRACE ("pass 2: copying all names and values to buffer\n");
6410 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6411 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6413 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6415 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6416 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6417 NULL, &dwType, lpValue, &cbValueLen);
6418 if (ret != ERROR_SUCCESS)
6420 if (HeapFree (hHeap, 0, lpValue) == 0)
6421 WARN ("HeapFree failed with code %i\n", GetLastError ());
6422 if (HeapFree (hHeap, 0, lpValueName) == 0)
6423 WARN ("HeapFree failed with code %i\n", GetLastError ());
6424 r = RegCloseKey (hkSubKey);
6425 if (r != ERROR_SUCCESS)
6426 WARN ("RegCloseKey returned %i\n", r);
6427 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6428 return ret;
6431 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6432 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6433 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6434 pEnumValues += cbValueNameLen;
6436 /* return # of *bytes* (including trailing \0), not # of chars */
6437 ppev[dwIndex].cbValueName = cbValueNameLen;
6439 ppev[dwIndex].dwType = dwType;
6441 memcpy (pEnumValues, lpValue, cbValueLen);
6442 ppev[dwIndex].pData = pEnumValues;
6443 pEnumValues += cbValueLen;
6445 ppev[dwIndex].cbData = cbValueLen;
6447 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6448 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6451 if (HeapFree (hHeap, 0, lpValue) == 0)
6453 ret = GetLastError ();
6454 ERR ("HeapFree failed with code %i\n", ret);
6455 if (HeapFree (hHeap, 0, lpValueName) == 0)
6456 WARN ("HeapFree failed with code %i\n", GetLastError ());
6457 r = RegCloseKey (hkSubKey);
6458 if (r != ERROR_SUCCESS)
6459 WARN ("RegCloseKey returned %i\n", r);
6460 return ret;
6463 if (HeapFree (hHeap, 0, lpValueName) == 0)
6465 ret = GetLastError ();
6466 ERR ("HeapFree failed with code %i\n", ret);
6467 r = RegCloseKey (hkSubKey);
6468 if (r != ERROR_SUCCESS)
6469 WARN ("RegCloseKey returned %i\n", r);
6470 return ret;
6473 ret = RegCloseKey (hkSubKey);
6474 if (ret != ERROR_SUCCESS)
6476 ERR ("RegCloseKey returned %i\n", ret);
6477 return ret;
6480 return ERROR_SUCCESS;
6483 /*******************************************************************************
6484 * EnumPrinterDataExA [WINSPOOL.@]
6486 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6487 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6488 * what Windows 2000 SP1 does.
6491 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6492 LPBYTE pEnumValues, DWORD cbEnumValues,
6493 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6495 INT len;
6496 LPWSTR pKeyNameW;
6497 DWORD ret, dwIndex, dwBufSize;
6498 HANDLE hHeap;
6499 LPSTR pBuffer;
6501 TRACE ("%p %s\n", hPrinter, pKeyName);
6503 if (pKeyName == NULL || *pKeyName == 0)
6504 return ERROR_INVALID_PARAMETER;
6506 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6507 if (len == 0)
6509 ret = GetLastError ();
6510 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6511 return ret;
6514 hHeap = GetProcessHeap ();
6515 if (hHeap == NULL)
6517 ERR ("GetProcessHeap failed\n");
6518 return ERROR_OUTOFMEMORY;
6521 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6522 if (pKeyNameW == NULL)
6524 ERR ("Failed to allocate %i bytes from process heap\n",
6525 (LONG)(len * sizeof (WCHAR)));
6526 return ERROR_OUTOFMEMORY;
6529 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6531 ret = GetLastError ();
6532 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6533 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6534 WARN ("HeapFree failed with code %i\n", GetLastError ());
6535 return ret;
6538 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6539 pcbEnumValues, pnEnumValues);
6540 if (ret != ERROR_SUCCESS)
6542 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6543 WARN ("HeapFree failed with code %i\n", GetLastError ());
6544 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6545 return ret;
6548 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6550 ret = GetLastError ();
6551 ERR ("HeapFree failed with code %i\n", ret);
6552 return ret;
6555 if (*pnEnumValues == 0) /* empty key */
6556 return ERROR_SUCCESS;
6558 dwBufSize = 0;
6559 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6561 PPRINTER_ENUM_VALUESW ppev =
6562 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6564 if (dwBufSize < ppev->cbValueName)
6565 dwBufSize = ppev->cbValueName;
6567 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6568 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6569 dwBufSize = ppev->cbData;
6572 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6574 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6575 if (pBuffer == NULL)
6577 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6578 return ERROR_OUTOFMEMORY;
6581 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6583 PPRINTER_ENUM_VALUESW ppev =
6584 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6586 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6587 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6588 NULL);
6589 if (len == 0)
6591 ret = GetLastError ();
6592 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6593 if (HeapFree (hHeap, 0, pBuffer) == 0)
6594 WARN ("HeapFree failed with code %i\n", GetLastError ());
6595 return ret;
6598 memcpy (ppev->pValueName, pBuffer, len);
6600 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6602 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6603 ppev->dwType != REG_MULTI_SZ)
6604 continue;
6606 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6607 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6608 if (len == 0)
6610 ret = GetLastError ();
6611 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6612 if (HeapFree (hHeap, 0, pBuffer) == 0)
6613 WARN ("HeapFree failed with code %i\n", GetLastError ());
6614 return ret;
6617 memcpy (ppev->pData, pBuffer, len);
6619 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6620 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6623 if (HeapFree (hHeap, 0, pBuffer) == 0)
6625 ret = GetLastError ();
6626 ERR ("HeapFree failed with code %i\n", ret);
6627 return ret;
6630 return ERROR_SUCCESS;
6633 /******************************************************************************
6634 * AbortPrinter (WINSPOOL.@)
6636 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6638 FIXME("(%p), stub!\n", hPrinter);
6639 return TRUE;
6642 /******************************************************************************
6643 * AddPortA (WINSPOOL.@)
6645 * See AddPortW.
6648 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6650 LPWSTR nameW = NULL;
6651 LPWSTR monitorW = NULL;
6652 DWORD len;
6653 BOOL res;
6655 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6657 if (pName) {
6658 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6659 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6660 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6663 if (pMonitorName) {
6664 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6665 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6666 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6668 res = AddPortW(nameW, hWnd, monitorW);
6669 HeapFree(GetProcessHeap(), 0, nameW);
6670 HeapFree(GetProcessHeap(), 0, monitorW);
6671 return res;
6674 /******************************************************************************
6675 * AddPortW (WINSPOOL.@)
6677 * Add a Port for a specific Monitor
6679 * PARAMS
6680 * pName [I] Servername or NULL (local Computer)
6681 * hWnd [I] Handle to parent Window for the Dialog-Box
6682 * pMonitorName [I] Name of the Monitor that manage the Port
6684 * RETURNS
6685 * Success: TRUE
6686 * Failure: FALSE
6689 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6691 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6693 if ((backend == NULL) && !load_backend()) return FALSE;
6695 if (!pMonitorName) {
6696 SetLastError(RPC_X_NULL_REF_POINTER);
6697 return FALSE;
6700 return backend->fpAddPort(pName, hWnd, pMonitorName);
6703 /******************************************************************************
6704 * AddPortExA (WINSPOOL.@)
6706 * See AddPortExW.
6709 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6711 PORT_INFO_2W pi2W;
6712 PORT_INFO_2A * pi2A;
6713 LPWSTR nameW = NULL;
6714 LPWSTR monitorW = NULL;
6715 DWORD len;
6716 BOOL res;
6718 pi2A = (PORT_INFO_2A *) pBuffer;
6720 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6721 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6723 if ((level < 1) || (level > 2)) {
6724 SetLastError(ERROR_INVALID_LEVEL);
6725 return FALSE;
6728 if (!pi2A) {
6729 SetLastError(ERROR_INVALID_PARAMETER);
6730 return FALSE;
6733 if (pName) {
6734 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6735 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6736 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6739 if (pMonitorName) {
6740 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6741 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6742 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6745 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6747 if (pi2A->pPortName) {
6748 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6749 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6750 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6753 if (level > 1) {
6754 if (pi2A->pMonitorName) {
6755 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6756 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6757 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6760 if (pi2A->pDescription) {
6761 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6762 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6763 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6765 pi2W.fPortType = pi2A->fPortType;
6766 pi2W.Reserved = pi2A->Reserved;
6769 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6771 HeapFree(GetProcessHeap(), 0, nameW);
6772 HeapFree(GetProcessHeap(), 0, monitorW);
6773 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6774 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6775 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6776 return res;
6780 /******************************************************************************
6781 * AddPortExW (WINSPOOL.@)
6783 * Add a Port for a specific Monitor, without presenting a user interface
6785 * PARAMS
6786 * pName [I] Servername or NULL (local Computer)
6787 * level [I] Structure-Level (1 or 2) for pBuffer
6788 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6789 * pMonitorName [I] Name of the Monitor that manage the Port
6791 * RETURNS
6792 * Success: TRUE
6793 * Failure: FALSE
6796 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6798 PORT_INFO_2W * pi2;
6800 pi2 = (PORT_INFO_2W *) pBuffer;
6802 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6803 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6804 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6805 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6807 if ((backend == NULL) && !load_backend()) return FALSE;
6809 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6810 SetLastError(ERROR_INVALID_PARAMETER);
6811 return FALSE;
6814 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6817 /******************************************************************************
6818 * AddPrinterConnectionA (WINSPOOL.@)
6820 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6822 FIXME("%s\n", debugstr_a(pName));
6823 return FALSE;
6826 /******************************************************************************
6827 * AddPrinterConnectionW (WINSPOOL.@)
6829 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6831 FIXME("%s\n", debugstr_w(pName));
6832 return FALSE;
6835 /******************************************************************************
6836 * AddPrinterDriverExW (WINSPOOL.@)
6838 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6840 * PARAMS
6841 * pName [I] Servername or NULL (local Computer)
6842 * level [I] Level for the supplied DRIVER_INFO_*W struct
6843 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6844 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6846 * RESULTS
6847 * Success: TRUE
6848 * Failure: FALSE
6851 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6853 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6855 if ((backend == NULL) && !load_backend()) return FALSE;
6857 if (level < 2 || level == 5 || level == 7 || level > 8) {
6858 SetLastError(ERROR_INVALID_LEVEL);
6859 return FALSE;
6862 if (!pDriverInfo) {
6863 SetLastError(ERROR_INVALID_PARAMETER);
6864 return FALSE;
6867 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6870 /******************************************************************************
6871 * AddPrinterDriverExA (WINSPOOL.@)
6873 * See AddPrinterDriverExW.
6876 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6878 DRIVER_INFO_8A *diA;
6879 DRIVER_INFO_8W diW;
6880 LPWSTR nameW = NULL;
6881 DWORD lenA;
6882 DWORD len;
6883 BOOL res = FALSE;
6885 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6887 diA = (DRIVER_INFO_8A *) pDriverInfo;
6888 ZeroMemory(&diW, sizeof(diW));
6890 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6891 SetLastError(ERROR_INVALID_LEVEL);
6892 return FALSE;
6895 if (diA == NULL) {
6896 SetLastError(ERROR_INVALID_PARAMETER);
6897 return FALSE;
6900 /* convert servername to unicode */
6901 if (pName) {
6902 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6903 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6904 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6907 /* common fields */
6908 diW.cVersion = diA->cVersion;
6910 if (diA->pName) {
6911 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6912 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6913 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6916 if (diA->pEnvironment) {
6917 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6918 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6919 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6922 if (diA->pDriverPath) {
6923 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6924 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6925 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6928 if (diA->pDataFile) {
6929 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6930 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6931 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6934 if (diA->pConfigFile) {
6935 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6936 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6937 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6940 if ((Level > 2) && diA->pDependentFiles) {
6941 lenA = multi_sz_lenA(diA->pDependentFiles);
6942 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6943 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6944 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6947 if ((Level > 2) && diA->pMonitorName) {
6948 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6949 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6950 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6953 if ((Level > 3) && diA->pDefaultDataType) {
6954 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6955 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6956 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6959 if ((Level > 3) && diA->pszzPreviousNames) {
6960 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6961 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6962 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6963 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6966 if ((Level > 5) && diA->pszMfgName) {
6967 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6968 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6969 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6972 if ((Level > 5) && diA->pszOEMUrl) {
6973 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6974 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6975 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6978 if ((Level > 5) && diA->pszHardwareID) {
6979 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6980 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6981 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6984 if ((Level > 5) && diA->pszProvider) {
6985 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6986 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6987 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6990 if (Level > 7) {
6991 FIXME("level %u is incomplete\n", Level);
6994 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6995 TRACE("got %u with %u\n", res, GetLastError());
6996 HeapFree(GetProcessHeap(), 0, nameW);
6997 HeapFree(GetProcessHeap(), 0, diW.pName);
6998 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6999 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
7000 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
7001 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
7002 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
7003 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
7004 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
7005 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
7006 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
7007 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
7008 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
7009 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
7011 TRACE("=> %u with %u\n", res, GetLastError());
7012 return res;
7015 /******************************************************************************
7016 * ConfigurePortA (WINSPOOL.@)
7018 * See ConfigurePortW.
7021 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7023 LPWSTR nameW = NULL;
7024 LPWSTR portW = NULL;
7025 INT len;
7026 DWORD res;
7028 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7030 /* convert servername to unicode */
7031 if (pName) {
7032 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7033 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7034 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7037 /* convert portname to unicode */
7038 if (pPortName) {
7039 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7040 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7041 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7044 res = ConfigurePortW(nameW, hWnd, portW);
7045 HeapFree(GetProcessHeap(), 0, nameW);
7046 HeapFree(GetProcessHeap(), 0, portW);
7047 return res;
7050 /******************************************************************************
7051 * ConfigurePortW (WINSPOOL.@)
7053 * Display the Configuration-Dialog for a specific Port
7055 * PARAMS
7056 * pName [I] Servername or NULL (local Computer)
7057 * hWnd [I] Handle to parent Window for the Dialog-Box
7058 * pPortName [I] Name of the Port, that should be configured
7060 * RETURNS
7061 * Success: TRUE
7062 * Failure: FALSE
7065 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7068 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7070 if ((backend == NULL) && !load_backend()) return FALSE;
7072 if (!pPortName) {
7073 SetLastError(RPC_X_NULL_REF_POINTER);
7074 return FALSE;
7077 return backend->fpConfigurePort(pName, hWnd, pPortName);
7080 /******************************************************************************
7081 * ConnectToPrinterDlg (WINSPOOL.@)
7083 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7085 FIXME("%p %x\n", hWnd, Flags);
7086 return NULL;
7089 /******************************************************************************
7090 * DeletePrinterConnectionA (WINSPOOL.@)
7092 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7094 FIXME("%s\n", debugstr_a(pName));
7095 return TRUE;
7098 /******************************************************************************
7099 * DeletePrinterConnectionW (WINSPOOL.@)
7101 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7103 FIXME("%s\n", debugstr_w(pName));
7104 return TRUE;
7107 /******************************************************************************
7108 * DeletePrinterDriverExW (WINSPOOL.@)
7110 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7111 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7113 HKEY hkey_drivers;
7114 BOOL ret = FALSE;
7116 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7117 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7119 if(pName && pName[0])
7121 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7122 SetLastError(ERROR_INVALID_PARAMETER);
7123 return FALSE;
7126 if(dwDeleteFlag)
7128 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7129 SetLastError(ERROR_INVALID_PARAMETER);
7130 return FALSE;
7133 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7135 if(!hkey_drivers)
7137 ERR("Can't open drivers key\n");
7138 return FALSE;
7141 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7142 ret = TRUE;
7144 RegCloseKey(hkey_drivers);
7146 return ret;
7149 /******************************************************************************
7150 * DeletePrinterDriverExA (WINSPOOL.@)
7152 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7153 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7155 UNICODE_STRING NameW, EnvW, DriverW;
7156 BOOL ret;
7158 asciitounicode(&NameW, pName);
7159 asciitounicode(&EnvW, pEnvironment);
7160 asciitounicode(&DriverW, pDriverName);
7162 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7164 RtlFreeUnicodeString(&DriverW);
7165 RtlFreeUnicodeString(&EnvW);
7166 RtlFreeUnicodeString(&NameW);
7168 return ret;
7171 /******************************************************************************
7172 * DeletePrinterDataExW (WINSPOOL.@)
7174 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7175 LPCWSTR pValueName)
7177 FIXME("%p %s %s\n", hPrinter,
7178 debugstr_w(pKeyName), debugstr_w(pValueName));
7179 return ERROR_INVALID_PARAMETER;
7182 /******************************************************************************
7183 * DeletePrinterDataExA (WINSPOOL.@)
7185 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7186 LPCSTR pValueName)
7188 FIXME("%p %s %s\n", hPrinter,
7189 debugstr_a(pKeyName), debugstr_a(pValueName));
7190 return ERROR_INVALID_PARAMETER;
7193 /******************************************************************************
7194 * DeletePrintProcessorA (WINSPOOL.@)
7196 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7198 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7199 debugstr_a(pPrintProcessorName));
7200 return TRUE;
7203 /******************************************************************************
7204 * DeletePrintProcessorW (WINSPOOL.@)
7206 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7208 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7209 debugstr_w(pPrintProcessorName));
7210 return TRUE;
7213 /******************************************************************************
7214 * DeletePrintProvidorA (WINSPOOL.@)
7216 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7218 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7219 debugstr_a(pPrintProviderName));
7220 return TRUE;
7223 /******************************************************************************
7224 * DeletePrintProvidorW (WINSPOOL.@)
7226 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7228 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7229 debugstr_w(pPrintProviderName));
7230 return TRUE;
7233 /******************************************************************************
7234 * EnumFormsA (WINSPOOL.@)
7236 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7237 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7239 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7240 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7241 return FALSE;
7244 /******************************************************************************
7245 * EnumFormsW (WINSPOOL.@)
7247 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7248 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7250 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7251 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7252 return FALSE;
7255 /*****************************************************************************
7256 * EnumMonitorsA [WINSPOOL.@]
7258 * See EnumMonitorsW.
7261 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7262 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7264 BOOL res;
7265 LPBYTE bufferW = NULL;
7266 LPWSTR nameW = NULL;
7267 DWORD needed = 0;
7268 DWORD numentries = 0;
7269 INT len;
7271 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7272 cbBuf, pcbNeeded, pcReturned);
7274 /* convert servername to unicode */
7275 if (pName) {
7276 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7277 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7278 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7280 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7281 needed = cbBuf * sizeof(WCHAR);
7282 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7283 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7285 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7286 if (pcbNeeded) needed = *pcbNeeded;
7287 /* HeapReAlloc return NULL, when bufferW was NULL */
7288 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7289 HeapAlloc(GetProcessHeap(), 0, needed);
7291 /* Try again with the large Buffer */
7292 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7294 numentries = pcReturned ? *pcReturned : 0;
7295 needed = 0;
7297 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7298 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7300 if (res) {
7301 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7302 DWORD entrysize = 0;
7303 DWORD index;
7304 LPSTR ptr;
7305 LPMONITOR_INFO_2W mi2w;
7306 LPMONITOR_INFO_2A mi2a;
7308 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7309 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7311 /* First pass: calculate the size for all Entries */
7312 mi2w = (LPMONITOR_INFO_2W) bufferW;
7313 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7314 index = 0;
7315 while (index < numentries) {
7316 index++;
7317 needed += entrysize; /* MONITOR_INFO_?A */
7318 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7320 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7321 NULL, 0, NULL, NULL);
7322 if (Level > 1) {
7323 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7324 NULL, 0, NULL, NULL);
7325 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7326 NULL, 0, NULL, NULL);
7328 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7329 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7330 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7333 /* check for errors and quit on failure */
7334 if (cbBuf < needed) {
7335 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7336 res = FALSE;
7337 goto emA_cleanup;
7339 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7340 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7341 cbBuf -= len ; /* free Bytes in the user-Buffer */
7342 mi2w = (LPMONITOR_INFO_2W) bufferW;
7343 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7344 index = 0;
7345 /* Second Pass: Fill the User Buffer (if we have one) */
7346 while ((index < numentries) && pMonitors) {
7347 index++;
7348 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7349 mi2a->pName = ptr;
7350 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7351 ptr, cbBuf , NULL, NULL);
7352 ptr += len;
7353 cbBuf -= len;
7354 if (Level > 1) {
7355 mi2a->pEnvironment = ptr;
7356 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7357 ptr, cbBuf, NULL, NULL);
7358 ptr += len;
7359 cbBuf -= len;
7361 mi2a->pDLLName = ptr;
7362 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7363 ptr, cbBuf, NULL, NULL);
7364 ptr += len;
7365 cbBuf -= len;
7367 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7368 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7369 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7372 emA_cleanup:
7373 if (pcbNeeded) *pcbNeeded = needed;
7374 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7376 HeapFree(GetProcessHeap(), 0, nameW);
7377 HeapFree(GetProcessHeap(), 0, bufferW);
7379 TRACE("returning %d with %d (%d byte for %d entries)\n",
7380 (res), GetLastError(), needed, numentries);
7382 return (res);
7386 /*****************************************************************************
7387 * EnumMonitorsW [WINSPOOL.@]
7389 * Enumerate available Port-Monitors
7391 * PARAMS
7392 * pName [I] Servername or NULL (local Computer)
7393 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7394 * pMonitors [O] PTR to Buffer that receives the Result
7395 * cbBuf [I] Size of Buffer at pMonitors
7396 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7397 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7399 * RETURNS
7400 * Success: TRUE
7401 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7404 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7405 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7408 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7409 cbBuf, pcbNeeded, pcReturned);
7411 if ((backend == NULL) && !load_backend()) return FALSE;
7413 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7414 SetLastError(RPC_X_NULL_REF_POINTER);
7415 return FALSE;
7418 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7421 /******************************************************************************
7422 * SpoolerInit (WINSPOOL.@)
7424 * Initialize the Spooler
7426 * RETURNS
7427 * Success: TRUE
7428 * Failure: FALSE
7430 * NOTES
7431 * The function fails on windows, when the spooler service is not running
7434 BOOL WINAPI SpoolerInit(void)
7437 if ((backend == NULL) && !load_backend()) return FALSE;
7438 return TRUE;
7441 /******************************************************************************
7442 * XcvDataW (WINSPOOL.@)
7444 * Execute commands in the Printmonitor DLL
7446 * PARAMS
7447 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7448 * pszDataName [i] Name of the command to execute
7449 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7450 * cbInputData [i] Size in Bytes of Buffer at pInputData
7451 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7452 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7453 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7454 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7456 * RETURNS
7457 * Success: TRUE
7458 * Failure: FALSE
7460 * NOTES
7461 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7462 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7464 * Minimal List of commands, that a Printmonitor DLL should support:
7466 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7467 *| "AddPort" : Add a Port
7468 *| "DeletePort": Delete a Port
7470 * Many Printmonitors support additional commands. Examples for localspl.dll:
7471 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7472 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7475 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7476 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7477 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7479 opened_printer_t *printer;
7481 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7482 pInputData, cbInputData, pOutputData,
7483 cbOutputData, pcbOutputNeeded, pdwStatus);
7485 if ((backend == NULL) && !load_backend()) return FALSE;
7487 printer = get_opened_printer(hXcv);
7488 if (!printer || (!printer->backend_printer)) {
7489 SetLastError(ERROR_INVALID_HANDLE);
7490 return FALSE;
7493 if (!pcbOutputNeeded) {
7494 SetLastError(ERROR_INVALID_PARAMETER);
7495 return FALSE;
7498 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7499 SetLastError(RPC_X_NULL_REF_POINTER);
7500 return FALSE;
7503 *pcbOutputNeeded = 0;
7505 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7506 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7510 /*****************************************************************************
7511 * EnumPrinterDataA [WINSPOOL.@]
7514 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7515 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7516 DWORD cbData, LPDWORD pcbData )
7518 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7519 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7520 return ERROR_NO_MORE_ITEMS;
7523 /*****************************************************************************
7524 * EnumPrinterDataW [WINSPOOL.@]
7527 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7528 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7529 DWORD cbData, LPDWORD pcbData )
7531 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7532 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7533 return ERROR_NO_MORE_ITEMS;
7536 /*****************************************************************************
7537 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7540 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7541 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7542 LPDWORD pcbNeeded, LPDWORD pcReturned)
7544 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7545 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7546 pcbNeeded, pcReturned);
7547 return FALSE;
7550 /*****************************************************************************
7551 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7554 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7555 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7556 LPDWORD pcbNeeded, LPDWORD pcReturned)
7558 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7559 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7560 pcbNeeded, pcReturned);
7561 return FALSE;
7564 /*****************************************************************************
7565 * EnumPrintProcessorsA [WINSPOOL.@]
7567 * See EnumPrintProcessorsW.
7570 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7571 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7573 BOOL res;
7574 LPBYTE bufferW = NULL;
7575 LPWSTR nameW = NULL;
7576 LPWSTR envW = NULL;
7577 DWORD needed = 0;
7578 DWORD numentries = 0;
7579 INT len;
7581 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7582 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7584 /* convert names to unicode */
7585 if (pName) {
7586 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7587 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7588 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7590 if (pEnvironment) {
7591 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7592 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7593 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7596 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7597 needed = cbBuf * sizeof(WCHAR);
7598 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7599 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7601 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7602 if (pcbNeeded) needed = *pcbNeeded;
7603 /* HeapReAlloc return NULL, when bufferW was NULL */
7604 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7605 HeapAlloc(GetProcessHeap(), 0, needed);
7607 /* Try again with the large Buffer */
7608 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7610 numentries = pcReturned ? *pcReturned : 0;
7611 needed = 0;
7613 if (res) {
7614 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7615 DWORD index;
7616 LPSTR ptr;
7617 PPRINTPROCESSOR_INFO_1W ppiw;
7618 PPRINTPROCESSOR_INFO_1A ppia;
7620 /* First pass: calculate the size for all Entries */
7621 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7622 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7623 index = 0;
7624 while (index < numentries) {
7625 index++;
7626 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7627 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7629 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7630 NULL, 0, NULL, NULL);
7632 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7633 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7636 /* check for errors and quit on failure */
7637 if (cbBuf < needed) {
7638 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7639 res = FALSE;
7640 goto epp_cleanup;
7643 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7644 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7645 cbBuf -= len ; /* free Bytes in the user-Buffer */
7646 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7647 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7648 index = 0;
7649 /* Second Pass: Fill the User Buffer (if we have one) */
7650 while ((index < numentries) && pPPInfo) {
7651 index++;
7652 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7653 ppia->pName = ptr;
7654 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7655 ptr, cbBuf , NULL, NULL);
7656 ptr += len;
7657 cbBuf -= len;
7659 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7660 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7664 epp_cleanup:
7665 if (pcbNeeded) *pcbNeeded = needed;
7666 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7668 HeapFree(GetProcessHeap(), 0, nameW);
7669 HeapFree(GetProcessHeap(), 0, envW);
7670 HeapFree(GetProcessHeap(), 0, bufferW);
7672 TRACE("returning %d with %d (%d byte for %d entries)\n",
7673 (res), GetLastError(), needed, numentries);
7675 return (res);
7678 /*****************************************************************************
7679 * EnumPrintProcessorsW [WINSPOOL.@]
7681 * Enumerate available Print Processors
7683 * PARAMS
7684 * pName [I] Servername or NULL (local Computer)
7685 * pEnvironment [I] Printing-Environment or NULL (Default)
7686 * Level [I] Structure-Level (Only 1 is allowed)
7687 * pPPInfo [O] PTR to Buffer that receives the Result
7688 * cbBuf [I] Size of Buffer at pPPInfo
7689 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7690 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7692 * RETURNS
7693 * Success: TRUE
7694 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7697 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7698 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7701 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7702 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7704 if ((backend == NULL) && !load_backend()) return FALSE;
7706 if (!pcbNeeded || !pcReturned) {
7707 SetLastError(RPC_X_NULL_REF_POINTER);
7708 return FALSE;
7711 if (!pPPInfo && (cbBuf > 0)) {
7712 SetLastError(ERROR_INVALID_USER_BUFFER);
7713 return FALSE;
7716 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7717 cbBuf, pcbNeeded, pcReturned);
7720 /*****************************************************************************
7721 * ExtDeviceMode [WINSPOOL.@]
7724 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7725 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7726 DWORD fMode)
7728 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7729 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7730 debugstr_a(pProfile), fMode);
7731 return -1;
7734 /*****************************************************************************
7735 * FindClosePrinterChangeNotification [WINSPOOL.@]
7738 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7740 FIXME("Stub: %p\n", hChange);
7741 return TRUE;
7744 /*****************************************************************************
7745 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7748 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7749 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7751 FIXME("Stub: %p %x %x %p\n",
7752 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7753 return INVALID_HANDLE_VALUE;
7756 /*****************************************************************************
7757 * FindNextPrinterChangeNotification [WINSPOOL.@]
7760 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7761 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7763 FIXME("Stub: %p %p %p %p\n",
7764 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7765 return FALSE;
7768 /*****************************************************************************
7769 * FreePrinterNotifyInfo [WINSPOOL.@]
7772 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7774 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7775 return TRUE;
7778 /*****************************************************************************
7779 * string_to_buf
7781 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7782 * ansi depending on the unicode parameter.
7784 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7786 if(!str)
7788 *size = 0;
7789 return TRUE;
7792 if(unicode)
7794 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7795 if(*size <= cb)
7797 memcpy(ptr, str, *size);
7798 return TRUE;
7800 return FALSE;
7802 else
7804 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7805 if(*size <= cb)
7807 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7808 return TRUE;
7810 return FALSE;
7814 /*****************************************************************************
7815 * get_job_info_1
7817 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7818 LPDWORD pcbNeeded, BOOL unicode)
7820 DWORD size, left = cbBuf;
7821 BOOL space = (cbBuf > 0);
7822 LPBYTE ptr = buf;
7824 *pcbNeeded = 0;
7826 if(space)
7828 ji1->JobId = job->job_id;
7831 string_to_buf(job->document_title, ptr, left, &size, unicode);
7832 if(space && size <= left)
7834 ji1->pDocument = (LPWSTR)ptr;
7835 ptr += size;
7836 left -= size;
7838 else
7839 space = FALSE;
7840 *pcbNeeded += size;
7842 if (job->printer_name)
7844 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7845 if(space && size <= left)
7847 ji1->pPrinterName = (LPWSTR)ptr;
7848 ptr += size;
7849 left -= size;
7851 else
7852 space = FALSE;
7853 *pcbNeeded += size;
7856 return space;
7859 /*****************************************************************************
7860 * get_job_info_2
7862 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7863 LPDWORD pcbNeeded, BOOL unicode)
7865 DWORD size, left = cbBuf;
7866 DWORD shift;
7867 BOOL space = (cbBuf > 0);
7868 LPBYTE ptr = buf;
7869 LPDEVMODEA dmA = NULL;
7870 LPDEVMODEW devmode;
7872 *pcbNeeded = 0;
7874 if(space)
7876 ji2->JobId = job->job_id;
7879 string_to_buf(job->document_title, ptr, left, &size, unicode);
7880 if(space && size <= left)
7882 ji2->pDocument = (LPWSTR)ptr;
7883 ptr += size;
7884 left -= size;
7886 else
7887 space = FALSE;
7888 *pcbNeeded += size;
7890 if (job->printer_name)
7892 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7893 if(space && size <= left)
7895 ji2->pPrinterName = (LPWSTR)ptr;
7896 ptr += size;
7897 left -= size;
7899 else
7900 space = FALSE;
7901 *pcbNeeded += size;
7904 if (job->devmode)
7906 if (!unicode)
7908 dmA = DEVMODEdupWtoA(job->devmode);
7909 devmode = (LPDEVMODEW) dmA;
7910 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7912 else
7914 devmode = job->devmode;
7915 size = devmode->dmSize + devmode->dmDriverExtra;
7918 if (!devmode)
7919 FIXME("Can't convert DEVMODE W to A\n");
7920 else
7922 /* align DEVMODE to a DWORD boundary */
7923 shift = (4 - (*pcbNeeded & 3)) & 3;
7924 size += shift;
7926 if (size <= left)
7928 ptr += shift;
7929 memcpy(ptr, devmode, size-shift);
7930 ji2->pDevMode = (LPDEVMODEW)ptr;
7931 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7932 ptr += size-shift;
7933 left -= size;
7935 else
7936 space = FALSE;
7937 *pcbNeeded +=size;
7941 return space;
7944 /*****************************************************************************
7945 * get_job_info
7947 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7948 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7950 BOOL ret = FALSE;
7951 DWORD needed = 0, size;
7952 job_t *job;
7953 LPBYTE ptr = pJob;
7955 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7957 EnterCriticalSection(&printer_handles_cs);
7958 job = get_job(hPrinter, JobId);
7959 if(!job)
7960 goto end;
7962 switch(Level)
7964 case 1:
7965 size = sizeof(JOB_INFO_1W);
7966 if(cbBuf >= size)
7968 cbBuf -= size;
7969 ptr += size;
7970 memset(pJob, 0, size);
7972 else
7973 cbBuf = 0;
7974 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7975 needed += size;
7976 break;
7978 case 2:
7979 size = sizeof(JOB_INFO_2W);
7980 if(cbBuf >= size)
7982 cbBuf -= size;
7983 ptr += size;
7984 memset(pJob, 0, size);
7986 else
7987 cbBuf = 0;
7988 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7989 needed += size;
7990 break;
7992 case 3:
7993 size = sizeof(JOB_INFO_3);
7994 if(cbBuf >= size)
7996 cbBuf -= size;
7997 memset(pJob, 0, size);
7998 ret = TRUE;
8000 else
8001 cbBuf = 0;
8002 needed = size;
8003 break;
8005 default:
8006 SetLastError(ERROR_INVALID_LEVEL);
8007 goto end;
8009 if(pcbNeeded)
8010 *pcbNeeded = needed;
8011 end:
8012 LeaveCriticalSection(&printer_handles_cs);
8013 return ret;
8016 /*****************************************************************************
8017 * GetJobA [WINSPOOL.@]
8020 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8021 DWORD cbBuf, LPDWORD pcbNeeded)
8023 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8026 /*****************************************************************************
8027 * GetJobW [WINSPOOL.@]
8030 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8031 DWORD cbBuf, LPDWORD pcbNeeded)
8033 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8036 /*****************************************************************************
8037 * schedule_pipe
8039 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8041 #ifdef HAVE_FORK
8042 char *unixname, *cmdA;
8043 DWORD len;
8044 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8045 BOOL ret = FALSE;
8046 char buf[1024];
8047 pid_t pid, wret;
8048 int status;
8050 if(!(unixname = wine_get_unix_file_name(filename)))
8051 return FALSE;
8053 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8054 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8055 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8057 TRACE("printing with: %s\n", cmdA);
8059 if((file_fd = open(unixname, O_RDONLY)) == -1)
8060 goto end;
8062 if (pipe(fds))
8064 ERR("pipe() failed!\n");
8065 goto end;
8068 if ((pid = fork()) == 0)
8070 close(0);
8071 dup2(fds[0], 0);
8072 close(fds[1]);
8074 /* reset signals that we previously set to SIG_IGN */
8075 signal(SIGPIPE, SIG_DFL);
8077 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8078 _exit(1);
8080 else if (pid == -1)
8082 ERR("fork() failed!\n");
8083 goto end;
8086 close(fds[0]);
8087 fds[0] = -1;
8088 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8089 write(fds[1], buf, no_read);
8091 close(fds[1]);
8092 fds[1] = -1;
8094 /* reap child */
8095 do {
8096 wret = waitpid(pid, &status, 0);
8097 } while (wret < 0 && errno == EINTR);
8098 if (wret < 0)
8100 ERR("waitpid() failed!\n");
8101 goto end;
8103 if (!WIFEXITED(status) || WEXITSTATUS(status))
8105 ERR("child process failed! %d\n", status);
8106 goto end;
8109 ret = TRUE;
8111 end:
8112 if(file_fd != -1) close(file_fd);
8113 if(fds[0] != -1) close(fds[0]);
8114 if(fds[1] != -1) close(fds[1]);
8116 HeapFree(GetProcessHeap(), 0, cmdA);
8117 HeapFree(GetProcessHeap(), 0, unixname);
8118 return ret;
8119 #else
8120 return FALSE;
8121 #endif
8124 /*****************************************************************************
8125 * schedule_lpr
8127 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8129 WCHAR *cmd;
8130 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8131 BOOL r;
8133 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8134 sprintfW(cmd, fmtW, printer_name);
8136 r = schedule_pipe(cmd, filename);
8138 HeapFree(GetProcessHeap(), 0, cmd);
8139 return r;
8142 #ifdef SONAME_LIBCUPS
8143 /*****************************************************************************
8144 * get_cups_jobs_ticket_options
8146 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8147 * The CUPS scheduler only looks for these in Print-File requests, and since
8148 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8149 * parsed.
8151 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8153 FILE *fp = fopen( file, "r" );
8154 char buf[257]; /* DSC max of 256 + '\0' */
8155 const char *ps_adobe = "%!PS-Adobe-";
8156 const char *cups_job = "%cupsJobTicket:";
8158 if (!fp) return num_options;
8159 if (!fgets( buf, sizeof(buf), fp )) goto end;
8160 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8161 while (fgets( buf, sizeof(buf), fp ))
8163 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8164 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8167 end:
8168 fclose( fp );
8169 return num_options;
8172 static int get_cups_default_options( const char *printer, int num_options, cups_option_t **options )
8174 cups_dest_t *dest;
8175 int i;
8177 if (!pcupsGetNamedDest) return num_options;
8179 dest = pcupsGetNamedDest( NULL, printer, NULL );
8180 if (!dest) return num_options;
8182 for (i = 0; i < dest->num_options; i++)
8184 if (!pcupsGetOption( dest->options[i].name, num_options, *options ))
8185 num_options = pcupsAddOption( dest->options[i].name, dest->options[i].value,
8186 num_options, options );
8189 pcupsFreeDests( 1, dest );
8190 return num_options;
8192 #endif
8194 /*****************************************************************************
8195 * schedule_cups
8197 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8199 #ifdef SONAME_LIBCUPS
8200 if(pcupsPrintFile)
8202 char *unixname, *queue, *unix_doc_title;
8203 DWORD len;
8204 BOOL ret;
8205 int num_options = 0, i;
8206 cups_option_t *options = NULL;
8208 if(!(unixname = wine_get_unix_file_name(filename)))
8209 return FALSE;
8211 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8212 queue = HeapAlloc(GetProcessHeap(), 0, len);
8213 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8215 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8216 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8217 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8219 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8220 num_options = get_cups_default_options( queue, num_options, &options );
8222 TRACE( "printing via cups with options:\n" );
8223 for (i = 0; i < num_options; i++)
8224 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8226 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8228 pcupsFreeOptions( num_options, options );
8230 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8231 HeapFree(GetProcessHeap(), 0, queue);
8232 HeapFree(GetProcessHeap(), 0, unixname);
8233 return ret;
8235 else
8236 #endif
8238 return schedule_lpr(printer_name, filename);
8242 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8244 LPWSTR filename;
8246 switch(msg)
8248 case WM_INITDIALOG:
8249 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8250 return TRUE;
8252 case WM_COMMAND:
8253 if(HIWORD(wparam) == BN_CLICKED)
8255 if(LOWORD(wparam) == IDOK)
8257 HANDLE hf;
8258 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8259 LPWSTR *output;
8261 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8262 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8264 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8266 WCHAR caption[200], message[200];
8267 int mb_ret;
8269 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8270 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8271 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8272 if(mb_ret == IDCANCEL)
8274 HeapFree(GetProcessHeap(), 0, filename);
8275 return TRUE;
8278 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8279 if(hf == INVALID_HANDLE_VALUE)
8281 WCHAR caption[200], message[200];
8283 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8284 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8285 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8286 HeapFree(GetProcessHeap(), 0, filename);
8287 return TRUE;
8289 CloseHandle(hf);
8290 DeleteFileW(filename);
8291 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8292 *output = filename;
8293 EndDialog(hwnd, IDOK);
8294 return TRUE;
8296 if(LOWORD(wparam) == IDCANCEL)
8298 EndDialog(hwnd, IDCANCEL);
8299 return TRUE;
8302 return FALSE;
8304 return FALSE;
8307 /*****************************************************************************
8308 * get_filename
8310 static BOOL get_filename(LPWSTR *filename)
8312 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8313 file_dlg_proc, (LPARAM)filename) == IDOK;
8316 /*****************************************************************************
8317 * schedule_file
8319 static BOOL schedule_file(LPCWSTR filename)
8321 LPWSTR output = NULL;
8323 if(get_filename(&output))
8325 BOOL r;
8326 TRACE("copy to %s\n", debugstr_w(output));
8327 r = CopyFileW(filename, output, FALSE);
8328 HeapFree(GetProcessHeap(), 0, output);
8329 return r;
8331 return FALSE;
8334 /*****************************************************************************
8335 * schedule_unixfile
8337 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8339 int in_fd, out_fd, no_read;
8340 char buf[1024];
8341 BOOL ret = FALSE;
8342 char *unixname, *outputA;
8343 DWORD len;
8345 if(!(unixname = wine_get_unix_file_name(filename)))
8346 return FALSE;
8348 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8349 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8350 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8352 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8353 in_fd = open(unixname, O_RDONLY);
8354 if(out_fd == -1 || in_fd == -1)
8355 goto end;
8357 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8358 write(out_fd, buf, no_read);
8360 ret = TRUE;
8361 end:
8362 if(in_fd != -1) close(in_fd);
8363 if(out_fd != -1) close(out_fd);
8364 HeapFree(GetProcessHeap(), 0, outputA);
8365 HeapFree(GetProcessHeap(), 0, unixname);
8366 return ret;
8369 /*****************************************************************************
8370 * ScheduleJob [WINSPOOL.@]
8373 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8375 opened_printer_t *printer;
8376 BOOL ret = FALSE;
8377 struct list *cursor, *cursor2;
8379 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8380 EnterCriticalSection(&printer_handles_cs);
8381 printer = get_opened_printer(hPrinter);
8382 if(!printer)
8383 goto end;
8385 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8387 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8388 HANDLE hf;
8390 if(job->job_id != dwJobID) continue;
8392 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8393 if(hf != INVALID_HANDLE_VALUE)
8395 PRINTER_INFO_5W *pi5 = NULL;
8396 LPWSTR portname = job->portname;
8397 DWORD needed;
8398 HKEY hkey;
8399 WCHAR output[1024];
8400 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8401 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8403 if (!portname)
8405 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8406 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8407 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8408 portname = pi5->pPortName;
8410 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8411 debugstr_w(portname));
8413 output[0] = 0;
8415 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8416 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8418 DWORD type, count = sizeof(output);
8419 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8420 RegCloseKey(hkey);
8422 if(output[0] == '|')
8424 ret = schedule_pipe(output + 1, job->filename);
8426 else if(output[0])
8428 ret = schedule_unixfile(output, job->filename);
8430 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8432 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8434 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8436 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8438 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8440 ret = schedule_file(job->filename);
8442 else
8444 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8446 HeapFree(GetProcessHeap(), 0, pi5);
8447 CloseHandle(hf);
8448 DeleteFileW(job->filename);
8450 list_remove(cursor);
8451 HeapFree(GetProcessHeap(), 0, job->document_title);
8452 HeapFree(GetProcessHeap(), 0, job->printer_name);
8453 HeapFree(GetProcessHeap(), 0, job->portname);
8454 HeapFree(GetProcessHeap(), 0, job->filename);
8455 HeapFree(GetProcessHeap(), 0, job->devmode);
8456 HeapFree(GetProcessHeap(), 0, job);
8457 break;
8459 end:
8460 LeaveCriticalSection(&printer_handles_cs);
8461 return ret;
8464 /*****************************************************************************
8465 * StartDocDlgA [WINSPOOL.@]
8467 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8469 UNICODE_STRING usBuffer;
8470 DOCINFOW docW;
8471 LPWSTR retW;
8472 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8473 LPSTR ret = NULL;
8475 docW.cbSize = sizeof(docW);
8476 if (doc->lpszDocName)
8478 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8479 if (!(docW.lpszDocName = docnameW)) return NULL;
8481 if (doc->lpszOutput)
8483 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8484 if (!(docW.lpszOutput = outputW)) return NULL;
8486 if (doc->lpszDatatype)
8488 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8489 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8491 docW.fwType = doc->fwType;
8493 retW = StartDocDlgW(hPrinter, &docW);
8495 if(retW)
8497 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8498 ret = HeapAlloc(GetProcessHeap(), 0, len);
8499 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8500 HeapFree(GetProcessHeap(), 0, retW);
8503 HeapFree(GetProcessHeap(), 0, datatypeW);
8504 HeapFree(GetProcessHeap(), 0, outputW);
8505 HeapFree(GetProcessHeap(), 0, docnameW);
8507 return ret;
8510 /*****************************************************************************
8511 * StartDocDlgW [WINSPOOL.@]
8513 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8514 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8515 * port is "FILE:". Also returns the full path if passed a relative path.
8517 * The caller should free the returned string from the process heap.
8519 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8521 LPWSTR ret = NULL;
8522 DWORD len, attr;
8524 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8526 PRINTER_INFO_5W *pi5;
8527 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8528 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8529 return NULL;
8530 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8531 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8532 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8534 HeapFree(GetProcessHeap(), 0, pi5);
8535 return NULL;
8537 HeapFree(GetProcessHeap(), 0, pi5);
8540 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8542 LPWSTR name;
8544 if (get_filename(&name))
8546 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8548 HeapFree(GetProcessHeap(), 0, name);
8549 return NULL;
8551 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8552 GetFullPathNameW(name, len, ret, NULL);
8553 HeapFree(GetProcessHeap(), 0, name);
8555 return ret;
8558 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8559 return NULL;
8561 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8562 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8564 attr = GetFileAttributesW(ret);
8565 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8567 HeapFree(GetProcessHeap(), 0, ret);
8568 ret = NULL;
8570 return ret;
8573 /*****************************************************************************
8574 * UploadPrinterDriverPackageA [WINSPOOL.@]
8576 HRESULT WINAPI UploadPrinterDriverPackageA( LPCSTR server, LPCSTR path, LPCSTR env,
8577 DWORD flags, HWND hwnd, LPSTR dst, PULONG dstlen )
8579 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server), debugstr_a(path), debugstr_a(env),
8580 flags, hwnd, dst, dstlen);
8581 return E_NOTIMPL;
8584 /*****************************************************************************
8585 * UploadPrinterDriverPackageW [WINSPOOL.@]
8587 HRESULT WINAPI UploadPrinterDriverPackageW( LPCWSTR server, LPCWSTR path, LPCWSTR env,
8588 DWORD flags, HWND hwnd, LPWSTR dst, PULONG dstlen )
8590 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server), debugstr_w(path), debugstr_w(env),
8591 flags, hwnd, dst, dstlen);
8592 return E_NOTIMPL;