msvcp60: Avoid FALSE:TRUE conditional expressions.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blob8027a1a099ed0f2c37d7d13853c1143120a946ee
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;
649 const char *data_dir, *filename;
651 if (RegOpenKeyW( HKEY_CURRENT_USER, ppds_key, &hkey ) == ERROR_SUCCESS )
653 const char *value_name = NULL;
655 if (RegQueryValueExA( hkey, printer_name, 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
656 value_name = printer_name;
657 else if (RegQueryValueExA( hkey, "generic", 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
658 value_name = "generic";
660 if (value_name)
662 ret = HeapAlloc( GetProcessHeap(), 0, needed );
663 if (!ret) return NULL;
664 RegQueryValueExA( hkey, value_name, 0, &type, (BYTE *)ret, &needed );
666 RegCloseKey( hkey );
667 if (ret) return expand_env_string( ret, type );
670 if ((data_dir = wine_get_data_dir())) filename = "/generic.ppd";
671 else if ((data_dir = wine_get_build_dir())) filename = "/dlls/wineps.drv/generic.ppd";
672 else
674 ERR( "Error getting PPD file name for printer '%s'\n", debugstr_a(printer_name) );
675 return NULL;
677 ret = HeapAlloc( GetProcessHeap(), 0, strlen(data_dir) + strlen(filename) + 1 );
678 if (ret)
680 strcpy( ret, data_dir );
681 strcat( ret, filename );
684 return ret;
687 static BOOL copy_file( const char *src, const char *dst )
689 int fds[2] = {-1, -1}, num;
690 char buf[1024];
691 BOOL ret = FALSE;
693 fds[0] = open( src, O_RDONLY );
694 fds[1] = open( dst, O_CREAT | O_TRUNC | O_WRONLY, 0666 );
695 if (fds[0] == -1 || fds[1] == -1) goto fail;
697 while ((num = read( fds[0], buf, sizeof(buf) )) != 0)
699 if (num == -1) goto fail;
700 if (write( fds[1], buf, num ) != num) goto fail;
702 ret = TRUE;
704 fail:
705 if (fds[1] != -1) close( fds[1] );
706 if (fds[0] != -1) close( fds[0] );
707 return ret;
710 static BOOL get_fallback_ppd( const char *printer_name, const WCHAR *ppd )
712 char *src = get_fallback_ppd_name( printer_name );
713 char *dst = wine_get_unix_file_name( ppd );
714 BOOL ret = FALSE;
716 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name), debugstr_w(ppd), debugstr_a(src) );
718 if (!src || !dst) goto fail;
720 if (symlink( src, dst ) == -1)
721 if (errno != ENOSYS || !copy_file( src, dst ))
722 goto fail;
724 ret = TRUE;
725 fail:
726 HeapFree( GetProcessHeap(), 0, dst );
727 HeapFree( GetProcessHeap(), 0, src );
728 return ret;
731 static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
733 static const WCHAR dot_ppd[] = {'.','p','p','d',0};
734 int len = (strlenW( dir ) + strlenW( file_name )) * sizeof(WCHAR) + sizeof(dot_ppd);
735 WCHAR *ppd = HeapAlloc( GetProcessHeap(), 0, len );
737 if (!ppd) return NULL;
738 strcpyW( ppd, dir );
739 strcatW( ppd, file_name );
740 strcatW( ppd, dot_ppd );
742 return ppd;
745 static WCHAR *get_ppd_dir( void )
747 static const WCHAR wine_ppds[] = {'w','i','n','e','_','p','p','d','s','\\',0};
748 DWORD len;
749 WCHAR *dir, tmp_path[MAX_PATH];
750 BOOL res;
752 len = GetTempPathW( sizeof(tmp_path) / sizeof(tmp_path[0]), tmp_path );
753 if (!len) return NULL;
754 dir = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
755 if (!dir) return NULL;
757 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
758 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
759 res = CreateDirectoryW( dir, NULL );
760 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
762 HeapFree( GetProcessHeap(), 0, dir );
763 dir = NULL;
765 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
766 return dir;
769 static void unlink_ppd( const WCHAR *ppd )
771 char *unix_name = wine_get_unix_file_name( ppd );
772 unlink( unix_name );
773 HeapFree( GetProcessHeap(), 0, unix_name );
776 #ifdef SONAME_LIBCUPS
778 static void *cupshandle;
780 #define CUPS_FUNCS \
781 DO_FUNC(cupsFreeDests); \
782 DO_FUNC(cupsFreeOptions); \
783 DO_FUNC(cupsGetDests); \
784 DO_FUNC(cupsGetOption); \
785 DO_FUNC(cupsGetPPD); \
786 DO_FUNC(cupsParseOptions); \
787 DO_FUNC(cupsPrintFile);
788 #define CUPS_OPT_FUNCS \
789 DO_FUNC(cupsGetPPD3);
791 #define DO_FUNC(f) static typeof(f) *p##f
792 CUPS_FUNCS;
793 #undef DO_FUNC
794 static http_status_t (*pcupsGetPPD3)(http_t *,const char *, time_t *, char *, size_t);
796 static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name,
797 time_t *modtime, char *buffer,
798 size_t bufsize )
800 const char *ppd;
802 if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
804 if (!pcupsGetPPD) return HTTP_NOT_FOUND;
806 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
808 *modtime = 0;
809 ppd = pcupsGetPPD( name );
811 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
813 if (!ppd) return HTTP_NOT_FOUND;
815 if (rename( ppd, buffer ) == -1)
817 BOOL res = copy_file( ppd, buffer );
818 unlink( ppd );
819 if (!res) return HTTP_NOT_FOUND;
821 return HTTP_OK;
824 static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
826 time_t modtime = 0;
827 http_status_t http_status;
828 char *unix_name = wine_get_unix_file_name( ppd );
830 TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
832 if (!unix_name) return FALSE;
834 http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
835 unix_name, strlen( unix_name ) + 1 );
836 HeapFree( GetProcessHeap(), 0, unix_name );
838 if (http_status == HTTP_OK) return TRUE;
840 TRACE( "failed to get ppd for printer %s from cups, calling fallback\n", debugstr_a(printer_name) );
841 return get_fallback_ppd( printer_name, ppd );
844 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
846 const char *value;
847 WCHAR *ret;
848 int len;
850 value = pcupsGetOption( name, num_options, options );
851 if (!value) return NULL;
853 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
854 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
855 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
857 return ret;
860 static BOOL CUPS_LoadPrinters(void)
862 int i, nrofdests;
863 BOOL hadprinter = FALSE, haddefault = FALSE;
864 cups_dest_t *dests;
865 PRINTER_INFO_2W pi2;
866 WCHAR *port, *ppd_dir = NULL, *ppd;
867 HKEY hkeyPrinter, hkeyPrinters;
868 char loaderror[256];
869 WCHAR nameW[MAX_PATH];
870 HANDLE added_printer;
872 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
873 if (!cupshandle) {
874 TRACE("%s\n", loaderror);
875 return FALSE;
877 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
879 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
880 CUPS_FUNCS;
881 #undef DO_FUNC
882 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 );
883 CUPS_OPT_FUNCS;
884 #undef DO_FUNC
886 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
887 ERROR_SUCCESS) {
888 ERR("Can't create Printers key\n");
889 return FALSE;
892 nrofdests = pcupsGetDests(&dests);
893 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
894 for (i=0;i<nrofdests;i++) {
895 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
897 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
898 lstrcpyW(port, CUPS_Port);
899 lstrcatW(port, nameW);
901 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
902 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
903 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
904 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
905 and continue */
906 TRACE("Printer already exists\n");
907 /* overwrite old LPR:* port */
908 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
909 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
910 /* flag that the PPD file should be checked for an update */
911 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
912 RegCloseKey(hkeyPrinter);
913 } else {
914 BOOL added_driver = FALSE;
916 if (!ppd_dir) ppd_dir = get_ppd_dir();
917 ppd = get_ppd_filename( ppd_dir, nameW );
918 if (get_cups_ppd( dests[i].name, ppd ))
920 added_driver = add_printer_driver( nameW, ppd );
921 unlink_ppd( ppd );
923 HeapFree( GetProcessHeap(), 0, ppd );
924 if (!added_driver) continue;
926 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
927 pi2.pPrinterName = nameW;
928 pi2.pDatatype = rawW;
929 pi2.pPrintProcessor = WinPrintW;
930 pi2.pDriverName = nameW;
931 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
932 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
933 pi2.pPortName = port;
934 pi2.pParameters = emptyStringW;
935 pi2.pShareName = emptyStringW;
936 pi2.pSepFile = emptyStringW;
938 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
939 if (added_printer) ClosePrinter( added_printer );
940 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
941 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
943 HeapFree( GetProcessHeap(), 0, pi2.pComment );
944 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
946 HeapFree( GetProcessHeap(), 0, port );
948 hadprinter = TRUE;
949 if (dests[i].is_default) {
950 SetDefaultPrinterW(nameW);
951 haddefault = TRUE;
955 if (ppd_dir)
957 RemoveDirectoryW( ppd_dir );
958 HeapFree( GetProcessHeap(), 0, ppd_dir );
961 if (hadprinter && !haddefault) {
962 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
963 SetDefaultPrinterW(nameW);
965 pcupsFreeDests(nrofdests, dests);
966 RegCloseKey(hkeyPrinters);
967 return TRUE;
970 #endif
972 static char *get_queue_name( HANDLE printer, BOOL *cups )
974 WCHAR *port, *name = NULL;
975 DWORD err, needed, type;
976 char *ret = NULL;
977 HKEY key;
979 *cups = FALSE;
981 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
982 if (err) return NULL;
983 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
984 if (err) goto end;
985 port = HeapAlloc( GetProcessHeap(), 0, needed );
986 if (!port) goto end;
987 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
989 if (!strncmpW( port, CUPS_Port, sizeof(CUPS_Port) / sizeof(WCHAR) -1 ))
991 name = port + sizeof(CUPS_Port) / sizeof(WCHAR) - 1;
992 *cups = TRUE;
994 else if (!strncmpW( port, LPR_Port, sizeof(LPR_Port) / sizeof(WCHAR) -1 ))
995 name = port + sizeof(LPR_Port) / sizeof(WCHAR) - 1;
996 if (name)
998 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
999 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1000 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1002 HeapFree( GetProcessHeap(), 0, port );
1003 end:
1004 RegCloseKey( key );
1005 return ret;
1009 static void set_ppd_overrides( HANDLE printer )
1011 WCHAR *wstr = NULL;
1012 int size = 0;
1013 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1014 OSStatus status;
1015 PMPrintSession session = NULL;
1016 PMPageFormat format = NULL;
1017 PMPaper paper;
1018 CFStringRef paper_name;
1019 CFRange range;
1021 status = PMCreateSession( &session );
1022 if (status) goto end;
1024 status = PMCreatePageFormat( &format );
1025 if (status) goto end;
1027 status = PMSessionDefaultPageFormat( session, format );
1028 if (status) goto end;
1030 status = PMGetPageFormatPaper( format, &paper );
1031 if (status) goto end;
1033 status = PMPaperGetPPDPaperName( paper, &paper_name );
1034 if (status) goto end;
1036 range.location = 0;
1037 range.length = CFStringGetLength( paper_name );
1038 size = (range.length + 1) * sizeof(WCHAR);
1040 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1041 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1042 wstr[range.length] = 0;
1044 end:
1045 if (format) PMRelease( format );
1046 if (session) PMRelease( session );
1047 #endif
1049 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1050 HeapFree( GetProcessHeap(), 0, wstr );
1053 static BOOL update_driver( HANDLE printer )
1055 BOOL ret, is_cups;
1056 const WCHAR *name = get_opened_printer_name( printer );
1057 WCHAR *ppd_dir, *ppd;
1058 char *queue_name;
1060 if (!name) return FALSE;
1061 queue_name = get_queue_name( printer, &is_cups );
1062 if (!queue_name) return FALSE;
1064 ppd_dir = get_ppd_dir();
1065 ppd = get_ppd_filename( ppd_dir, name );
1067 #ifdef SONAME_LIBCUPS
1068 if (is_cups)
1069 ret = get_cups_ppd( queue_name, ppd );
1070 else
1071 #endif
1072 ret = get_fallback_ppd( queue_name, ppd );
1074 if (ret)
1076 TRACE( "updating driver %s\n", debugstr_w( name ) );
1077 ret = add_printer_driver( name, ppd );
1078 unlink_ppd( ppd );
1080 HeapFree( GetProcessHeap(), 0, ppd_dir );
1081 HeapFree( GetProcessHeap(), 0, ppd );
1082 HeapFree( GetProcessHeap(), 0, queue_name );
1084 set_ppd_overrides( printer );
1086 /* call into the driver to update the devmode */
1087 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1089 return ret;
1092 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1094 PRINTER_INFO_2A pinfo2a;
1095 const char *r;
1096 size_t name_len;
1097 char *e,*s,*name,*prettyname,*devname;
1098 BOOL ret = FALSE, set_default = FALSE;
1099 char *port = NULL, *env_default;
1100 HKEY hkeyPrinter, hkeyPrinters = NULL;
1101 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1102 HANDLE added_printer;
1104 while (isspace(*pent)) pent++;
1105 r = strchr(pent,':');
1106 if (r)
1107 name_len = r - pent;
1108 else
1109 name_len = strlen(pent);
1110 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1111 memcpy(name, pent, name_len);
1112 name[name_len] = '\0';
1113 if (r)
1114 pent = r;
1115 else
1116 pent = "";
1118 TRACE("name=%s entry=%s\n",name, pent);
1120 if(ispunct(*name)) { /* a tc entry, not a real printer */
1121 TRACE("skipping tc entry\n");
1122 goto end;
1125 if(strstr(pent,":server")) { /* server only version so skip */
1126 TRACE("skipping server entry\n");
1127 goto end;
1130 /* Determine whether this is a postscript printer. */
1132 ret = TRUE;
1133 env_default = getenv("PRINTER");
1134 prettyname = name;
1135 /* Get longest name, usually the one at the right for later display. */
1136 while((s=strchr(prettyname,'|'))) {
1137 *s = '\0';
1138 e = s;
1139 while(isspace(*--e)) *e = '\0';
1140 TRACE("\t%s\n", debugstr_a(prettyname));
1141 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1142 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1145 e = prettyname + strlen(prettyname);
1146 while(isspace(*--e)) *e = '\0';
1147 TRACE("\t%s\n", debugstr_a(prettyname));
1148 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1150 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1151 * if it is too long, we use it as comment below. */
1152 devname = prettyname;
1153 if (strlen(devname)>=CCHDEVICENAME-1)
1154 devname = name;
1155 if (strlen(devname)>=CCHDEVICENAME-1) {
1156 ret = FALSE;
1157 goto end;
1160 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1161 sprintf(port,"LPR:%s",name);
1163 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1164 ERROR_SUCCESS) {
1165 ERR("Can't create Printers key\n");
1166 ret = FALSE;
1167 goto end;
1170 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
1172 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1173 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1174 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1175 and continue */
1176 TRACE("Printer already exists\n");
1177 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1178 /* flag that the PPD file should be checked for an update */
1179 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1180 RegCloseKey(hkeyPrinter);
1181 } else {
1182 static CHAR data_type[] = "RAW",
1183 print_proc[] = "WinPrint",
1184 comment[] = "WINEPS Printer using LPR",
1185 params[] = "<parameters?>",
1186 share_name[] = "<share name?>",
1187 sep_file[] = "<sep file?>";
1188 BOOL added_driver = FALSE;
1190 if (!ppd_dir) ppd_dir = get_ppd_dir();
1191 ppd = get_ppd_filename( ppd_dir, devnameW );
1192 if (get_fallback_ppd( devname, ppd ))
1194 added_driver = add_printer_driver( devnameW, ppd );
1195 unlink_ppd( ppd );
1197 HeapFree( GetProcessHeap(), 0, ppd );
1198 if (!added_driver) goto end;
1200 memset(&pinfo2a,0,sizeof(pinfo2a));
1201 pinfo2a.pPrinterName = devname;
1202 pinfo2a.pDatatype = data_type;
1203 pinfo2a.pPrintProcessor = print_proc;
1204 pinfo2a.pDriverName = devname;
1205 pinfo2a.pComment = comment;
1206 pinfo2a.pLocation = prettyname;
1207 pinfo2a.pPortName = port;
1208 pinfo2a.pParameters = params;
1209 pinfo2a.pShareName = share_name;
1210 pinfo2a.pSepFile = sep_file;
1212 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1213 if (added_printer) ClosePrinter( added_printer );
1214 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1215 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1218 if (isfirst || set_default)
1219 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1221 end:
1222 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1223 if (ppd_dir)
1225 RemoveDirectoryW( ppd_dir );
1226 HeapFree( GetProcessHeap(), 0, ppd_dir );
1228 HeapFree(GetProcessHeap(), 0, port);
1229 HeapFree(GetProcessHeap(), 0, name);
1230 return ret;
1233 static BOOL
1234 PRINTCAP_LoadPrinters(void) {
1235 BOOL hadprinter = FALSE;
1236 char buf[200];
1237 FILE *f;
1238 char *pent = NULL;
1239 BOOL had_bash = FALSE;
1241 f = fopen("/etc/printcap","r");
1242 if (!f)
1243 return FALSE;
1245 while(fgets(buf,sizeof(buf),f)) {
1246 char *start, *end;
1248 end=strchr(buf,'\n');
1249 if (end) *end='\0';
1251 start = buf;
1252 while(isspace(*start)) start++;
1253 if(*start == '#' || *start == '\0')
1254 continue;
1256 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1257 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1258 HeapFree(GetProcessHeap(),0,pent);
1259 pent = NULL;
1262 if (end && *--end == '\\') {
1263 *end = '\0';
1264 had_bash = TRUE;
1265 } else
1266 had_bash = FALSE;
1268 if (pent) {
1269 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1270 strcat(pent,start);
1271 } else {
1272 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1273 strcpy(pent,start);
1277 if(pent) {
1278 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1279 HeapFree(GetProcessHeap(),0,pent);
1281 fclose(f);
1282 return hadprinter;
1285 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1287 if (value)
1288 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1289 (lstrlenW(value) + 1) * sizeof(WCHAR));
1290 else
1291 return ERROR_FILE_NOT_FOUND;
1294 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1296 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1297 DWORD ret = ERROR_FILE_NOT_FOUND;
1299 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1300 and we support these drivers. NT writes DEVMODEW so somehow
1301 we'll need to distinguish between these when we support NT
1302 drivers */
1304 if (dmA)
1306 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1307 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1308 HeapFree( GetProcessHeap(), 0, dmA );
1311 return ret;
1314 /******************************************************************
1315 * get_servername_from_name (internal)
1317 * for an external server, a copy of the serverpart from the full name is returned
1320 static LPWSTR get_servername_from_name(LPCWSTR name)
1322 LPWSTR server;
1323 LPWSTR ptr;
1324 WCHAR buffer[MAX_PATH];
1325 DWORD len;
1327 if (name == NULL) return NULL;
1328 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1330 server = strdupW(&name[2]); /* skip over both backslash */
1331 if (server == NULL) return NULL;
1333 /* strip '\' and the printername */
1334 ptr = strchrW(server, '\\');
1335 if (ptr) ptr[0] = '\0';
1337 TRACE("found %s\n", debugstr_w(server));
1339 len = sizeof(buffer)/sizeof(buffer[0]);
1340 if (GetComputerNameW(buffer, &len)) {
1341 if (lstrcmpW(buffer, server) == 0) {
1342 /* The requested Servername is our computername */
1343 HeapFree(GetProcessHeap(), 0, server);
1344 return NULL;
1347 return server;
1350 /******************************************************************
1351 * get_basename_from_name (internal)
1353 * skip over the serverpart from the full name
1356 static LPCWSTR get_basename_from_name(LPCWSTR name)
1358 if (name == NULL) return NULL;
1359 if ((name[0] == '\\') && (name[1] == '\\')) {
1360 /* skip over the servername and search for the following '\' */
1361 name = strchrW(&name[2], '\\');
1362 if ((name) && (name[1])) {
1363 /* found a separator ('\') followed by a name:
1364 skip over the separator and return the rest */
1365 name++;
1367 else
1369 /* no basename present (we found only a servername) */
1370 return NULL;
1373 return name;
1376 static void free_printer_entry( opened_printer_t *printer )
1378 /* the queue is shared, so don't free that here */
1379 HeapFree( GetProcessHeap(), 0, printer->printername );
1380 HeapFree( GetProcessHeap(), 0, printer->name );
1381 HeapFree( GetProcessHeap(), 0, printer->devmode );
1382 HeapFree( GetProcessHeap(), 0, printer );
1385 /******************************************************************
1386 * get_opened_printer_entry
1387 * Get the first place empty in the opened printer table
1389 * ToDo:
1390 * - pDefault is ignored
1392 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1394 UINT_PTR handle = nb_printer_handles, i;
1395 jobqueue_t *queue = NULL;
1396 opened_printer_t *printer = NULL;
1397 LPWSTR servername;
1398 LPCWSTR printername;
1400 if ((backend == NULL) && !load_backend()) return NULL;
1402 servername = get_servername_from_name(name);
1403 if (servername) {
1404 FIXME("server %s not supported\n", debugstr_w(servername));
1405 HeapFree(GetProcessHeap(), 0, servername);
1406 SetLastError(ERROR_INVALID_PRINTER_NAME);
1407 return NULL;
1410 printername = get_basename_from_name(name);
1411 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1413 /* an empty printername is invalid */
1414 if (printername && (!printername[0])) {
1415 SetLastError(ERROR_INVALID_PARAMETER);
1416 return NULL;
1419 EnterCriticalSection(&printer_handles_cs);
1421 for (i = 0; i < nb_printer_handles; i++)
1423 if (!printer_handles[i])
1425 if(handle == nb_printer_handles)
1426 handle = i;
1428 else
1430 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1431 queue = printer_handles[i]->queue;
1435 if (handle >= nb_printer_handles)
1437 opened_printer_t **new_array;
1438 if (printer_handles)
1439 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1440 (nb_printer_handles + 16) * sizeof(*new_array) );
1441 else
1442 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1443 (nb_printer_handles + 16) * sizeof(*new_array) );
1445 if (!new_array)
1447 handle = 0;
1448 goto end;
1450 printer_handles = new_array;
1451 nb_printer_handles += 16;
1454 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1456 handle = 0;
1457 goto end;
1460 /* get a printer handle from the backend */
1461 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1462 handle = 0;
1463 goto end;
1466 /* clone the base name. This is NULL for the printserver */
1467 printer->printername = strdupW(printername);
1469 /* clone the full name */
1470 printer->name = strdupW(name);
1471 if (name && (!printer->name)) {
1472 handle = 0;
1473 goto end;
1476 if (pDefault && pDefault->pDevMode)
1477 printer->devmode = dup_devmode( pDefault->pDevMode );
1479 if(queue)
1480 printer->queue = queue;
1481 else
1483 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1484 if (!printer->queue) {
1485 handle = 0;
1486 goto end;
1488 list_init(&printer->queue->jobs);
1489 printer->queue->ref = 0;
1491 InterlockedIncrement(&printer->queue->ref);
1493 printer_handles[handle] = printer;
1494 handle++;
1495 end:
1496 LeaveCriticalSection(&printer_handles_cs);
1497 if (!handle && printer) {
1498 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1499 free_printer_entry( printer );
1502 return (HANDLE)handle;
1505 static void old_printer_check( BOOL delete_phase )
1507 PRINTER_INFO_5W* pi;
1508 DWORD needed, type, num, delete, i, size;
1509 const DWORD one = 1;
1510 HKEY key;
1511 HANDLE hprn;
1513 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1514 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1516 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1517 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1518 for (i = 0; i < num; i++)
1520 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1521 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1522 continue;
1524 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1526 if (!delete_phase)
1528 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1529 RegCloseKey( key );
1531 else
1533 delete = 0;
1534 size = sizeof( delete );
1535 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1536 RegCloseKey( key );
1537 if (delete)
1539 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1540 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1542 DeletePrinter( hprn );
1543 ClosePrinter( hprn );
1545 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1549 HeapFree(GetProcessHeap(), 0, pi);
1552 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1553 'M','U','T','E','X','_','_','\0'};
1554 static HANDLE init_mutex;
1556 void WINSPOOL_LoadSystemPrinters(void)
1558 HKEY hkey, hkeyPrinters;
1559 DWORD needed, num, i;
1560 WCHAR PrinterName[256];
1561 BOOL done = FALSE;
1563 /* FIXME: The init code should be moved to spoolsv.exe */
1564 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1565 if (!init_mutex)
1567 ERR( "Failed to create mutex\n" );
1568 return;
1570 if (GetLastError() == ERROR_ALREADY_EXISTS)
1572 WaitForSingleObject( init_mutex, INFINITE );
1573 ReleaseMutex( init_mutex );
1574 TRACE( "Init already done\n" );
1575 return;
1578 /* This ensures that all printer entries have a valid Name value. If causes
1579 problems later if they don't. If one is found to be missed we create one
1580 and set it equal to the name of the key */
1581 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1582 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1583 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1584 for(i = 0; i < num; i++) {
1585 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1586 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1587 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1588 set_reg_szW(hkey, NameW, PrinterName);
1590 RegCloseKey(hkey);
1595 RegCloseKey(hkeyPrinters);
1598 old_printer_check( FALSE );
1600 #ifdef SONAME_LIBCUPS
1601 done = CUPS_LoadPrinters();
1602 #endif
1604 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1605 PRINTCAP_LoadPrinters();
1607 old_printer_check( TRUE );
1609 ReleaseMutex( init_mutex );
1610 return;
1613 /******************************************************************
1614 * get_job
1616 * Get the pointer to the specified job.
1617 * Should hold the printer_handles_cs before calling.
1619 static job_t *get_job(HANDLE hprn, DWORD JobId)
1621 opened_printer_t *printer = get_opened_printer(hprn);
1622 job_t *job;
1624 if(!printer) return NULL;
1625 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1627 if(job->job_id == JobId)
1628 return job;
1630 return NULL;
1633 /***********************************************************
1634 * DEVMODEcpyAtoW
1636 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1638 BOOL Formname;
1639 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1640 DWORD size;
1642 Formname = (dmA->dmSize > off_formname);
1643 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1644 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1645 dmW->dmDeviceName, CCHDEVICENAME);
1646 if(!Formname) {
1647 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1648 dmA->dmSize - CCHDEVICENAME);
1649 } else {
1650 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1651 off_formname - CCHDEVICENAME);
1652 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1653 dmW->dmFormName, CCHFORMNAME);
1654 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1655 (off_formname + CCHFORMNAME));
1657 dmW->dmSize = size;
1658 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1659 dmA->dmDriverExtra);
1660 return dmW;
1663 /******************************************************************
1664 * convert_printerinfo_W_to_A [internal]
1667 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1668 DWORD level, DWORD outlen, DWORD numentries)
1670 DWORD id = 0;
1671 LPSTR ptr;
1672 INT len;
1674 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1676 len = pi_sizeof[level] * numentries;
1677 ptr = (LPSTR) out + len;
1678 outlen -= len;
1680 /* copy the numbers of all PRINTER_INFO_* first */
1681 memcpy(out, pPrintersW, len);
1683 while (id < numentries) {
1684 switch (level) {
1685 case 1:
1687 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1688 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1690 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1691 if (piW->pDescription) {
1692 piA->pDescription = ptr;
1693 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1694 ptr, outlen, NULL, NULL);
1695 ptr += len;
1696 outlen -= len;
1698 if (piW->pName) {
1699 piA->pName = ptr;
1700 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1701 ptr, outlen, NULL, NULL);
1702 ptr += len;
1703 outlen -= len;
1705 if (piW->pComment) {
1706 piA->pComment = ptr;
1707 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1708 ptr, outlen, NULL, NULL);
1709 ptr += len;
1710 outlen -= len;
1712 break;
1715 case 2:
1717 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1718 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1719 LPDEVMODEA dmA;
1721 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1722 if (piW->pServerName) {
1723 piA->pServerName = ptr;
1724 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1725 ptr, outlen, NULL, NULL);
1726 ptr += len;
1727 outlen -= len;
1729 if (piW->pPrinterName) {
1730 piA->pPrinterName = ptr;
1731 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1732 ptr, outlen, NULL, NULL);
1733 ptr += len;
1734 outlen -= len;
1736 if (piW->pShareName) {
1737 piA->pShareName = ptr;
1738 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1739 ptr, outlen, NULL, NULL);
1740 ptr += len;
1741 outlen -= len;
1743 if (piW->pPortName) {
1744 piA->pPortName = ptr;
1745 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1746 ptr, outlen, NULL, NULL);
1747 ptr += len;
1748 outlen -= len;
1750 if (piW->pDriverName) {
1751 piA->pDriverName = ptr;
1752 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1753 ptr, outlen, NULL, NULL);
1754 ptr += len;
1755 outlen -= len;
1757 if (piW->pComment) {
1758 piA->pComment = ptr;
1759 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1760 ptr, outlen, NULL, NULL);
1761 ptr += len;
1762 outlen -= len;
1764 if (piW->pLocation) {
1765 piA->pLocation = ptr;
1766 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1767 ptr, outlen, NULL, NULL);
1768 ptr += len;
1769 outlen -= len;
1772 dmA = DEVMODEdupWtoA(piW->pDevMode);
1773 if (dmA) {
1774 /* align DEVMODEA to a DWORD boundary */
1775 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1776 ptr += len;
1777 outlen -= len;
1779 piA->pDevMode = (LPDEVMODEA) ptr;
1780 len = dmA->dmSize + dmA->dmDriverExtra;
1781 memcpy(ptr, dmA, len);
1782 HeapFree(GetProcessHeap(), 0, dmA);
1784 ptr += len;
1785 outlen -= len;
1788 if (piW->pSepFile) {
1789 piA->pSepFile = ptr;
1790 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1791 ptr, outlen, NULL, NULL);
1792 ptr += len;
1793 outlen -= len;
1795 if (piW->pPrintProcessor) {
1796 piA->pPrintProcessor = ptr;
1797 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1798 ptr, outlen, NULL, NULL);
1799 ptr += len;
1800 outlen -= len;
1802 if (piW->pDatatype) {
1803 piA->pDatatype = ptr;
1804 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1805 ptr, outlen, NULL, NULL);
1806 ptr += len;
1807 outlen -= len;
1809 if (piW->pParameters) {
1810 piA->pParameters = ptr;
1811 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1812 ptr, outlen, NULL, NULL);
1813 ptr += len;
1814 outlen -= len;
1816 if (piW->pSecurityDescriptor) {
1817 piA->pSecurityDescriptor = NULL;
1818 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1820 break;
1823 case 4:
1825 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1826 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1828 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1830 if (piW->pPrinterName) {
1831 piA->pPrinterName = ptr;
1832 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1833 ptr, outlen, NULL, NULL);
1834 ptr += len;
1835 outlen -= len;
1837 if (piW->pServerName) {
1838 piA->pServerName = ptr;
1839 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1840 ptr, outlen, NULL, NULL);
1841 ptr += len;
1842 outlen -= len;
1844 break;
1847 case 5:
1849 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1850 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1852 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1854 if (piW->pPrinterName) {
1855 piA->pPrinterName = ptr;
1856 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1857 ptr, outlen, NULL, NULL);
1858 ptr += len;
1859 outlen -= len;
1861 if (piW->pPortName) {
1862 piA->pPortName = ptr;
1863 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1864 ptr, outlen, NULL, NULL);
1865 ptr += len;
1866 outlen -= len;
1868 break;
1871 case 6: /* 6A and 6W are the same structure */
1872 break;
1874 case 7:
1876 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1877 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1879 TRACE("(%u) #%u\n", level, id);
1880 if (piW->pszObjectGUID) {
1881 piA->pszObjectGUID = ptr;
1882 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1883 ptr, outlen, NULL, NULL);
1884 ptr += len;
1885 outlen -= len;
1887 break;
1890 case 8:
1891 case 9:
1893 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1894 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1895 LPDEVMODEA dmA;
1897 TRACE("(%u) #%u\n", level, id);
1898 dmA = DEVMODEdupWtoA(piW->pDevMode);
1899 if (dmA) {
1900 /* align DEVMODEA to a DWORD boundary */
1901 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1902 ptr += len;
1903 outlen -= len;
1905 piA->pDevMode = (LPDEVMODEA) ptr;
1906 len = dmA->dmSize + dmA->dmDriverExtra;
1907 memcpy(ptr, dmA, len);
1908 HeapFree(GetProcessHeap(), 0, dmA);
1910 ptr += len;
1911 outlen -= len;
1914 break;
1917 default:
1918 FIXME("for level %u\n", level);
1920 pPrintersW += pi_sizeof[level];
1921 out += pi_sizeof[level];
1922 id++;
1926 /******************************************************************
1927 * convert_driverinfo_W_to_A [internal]
1930 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1931 DWORD level, DWORD outlen, DWORD numentries)
1933 DWORD id = 0;
1934 LPSTR ptr;
1935 INT len;
1937 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1939 len = di_sizeof[level] * numentries;
1940 ptr = (LPSTR) out + len;
1941 outlen -= len;
1943 /* copy the numbers of all PRINTER_INFO_* first */
1944 memcpy(out, pDriversW, len);
1946 #define COPY_STRING(fld) \
1947 { if (diW->fld){ \
1948 diA->fld = ptr; \
1949 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1950 ptr += len; outlen -= len;\
1952 #define COPY_MULTIZ_STRING(fld) \
1953 { LPWSTR p = diW->fld; if (p){ \
1954 diA->fld = ptr; \
1955 do {\
1956 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1957 ptr += len; outlen -= len; p += len;\
1959 while(len > 1 && outlen > 0); \
1962 while (id < numentries)
1964 switch (level)
1966 case 1:
1968 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1969 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1971 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1973 COPY_STRING(pName);
1974 break;
1976 case 2:
1978 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1979 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1981 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1983 COPY_STRING(pName);
1984 COPY_STRING(pEnvironment);
1985 COPY_STRING(pDriverPath);
1986 COPY_STRING(pDataFile);
1987 COPY_STRING(pConfigFile);
1988 break;
1990 case 3:
1992 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1993 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1995 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1997 COPY_STRING(pName);
1998 COPY_STRING(pEnvironment);
1999 COPY_STRING(pDriverPath);
2000 COPY_STRING(pDataFile);
2001 COPY_STRING(pConfigFile);
2002 COPY_STRING(pHelpFile);
2003 COPY_MULTIZ_STRING(pDependentFiles);
2004 COPY_STRING(pMonitorName);
2005 COPY_STRING(pDefaultDataType);
2006 break;
2008 case 4:
2010 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2011 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2013 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2015 COPY_STRING(pName);
2016 COPY_STRING(pEnvironment);
2017 COPY_STRING(pDriverPath);
2018 COPY_STRING(pDataFile);
2019 COPY_STRING(pConfigFile);
2020 COPY_STRING(pHelpFile);
2021 COPY_MULTIZ_STRING(pDependentFiles);
2022 COPY_STRING(pMonitorName);
2023 COPY_STRING(pDefaultDataType);
2024 COPY_MULTIZ_STRING(pszzPreviousNames);
2025 break;
2027 case 5:
2029 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2030 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2032 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2034 COPY_STRING(pName);
2035 COPY_STRING(pEnvironment);
2036 COPY_STRING(pDriverPath);
2037 COPY_STRING(pDataFile);
2038 COPY_STRING(pConfigFile);
2039 break;
2041 case 6:
2043 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2044 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2046 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2048 COPY_STRING(pName);
2049 COPY_STRING(pEnvironment);
2050 COPY_STRING(pDriverPath);
2051 COPY_STRING(pDataFile);
2052 COPY_STRING(pConfigFile);
2053 COPY_STRING(pHelpFile);
2054 COPY_MULTIZ_STRING(pDependentFiles);
2055 COPY_STRING(pMonitorName);
2056 COPY_STRING(pDefaultDataType);
2057 COPY_MULTIZ_STRING(pszzPreviousNames);
2058 COPY_STRING(pszMfgName);
2059 COPY_STRING(pszOEMUrl);
2060 COPY_STRING(pszHardwareID);
2061 COPY_STRING(pszProvider);
2062 break;
2064 case 8:
2066 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2067 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2069 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2071 COPY_STRING(pName);
2072 COPY_STRING(pEnvironment);
2073 COPY_STRING(pDriverPath);
2074 COPY_STRING(pDataFile);
2075 COPY_STRING(pConfigFile);
2076 COPY_STRING(pHelpFile);
2077 COPY_MULTIZ_STRING(pDependentFiles);
2078 COPY_STRING(pMonitorName);
2079 COPY_STRING(pDefaultDataType);
2080 COPY_MULTIZ_STRING(pszzPreviousNames);
2081 COPY_STRING(pszMfgName);
2082 COPY_STRING(pszOEMUrl);
2083 COPY_STRING(pszHardwareID);
2084 COPY_STRING(pszProvider);
2085 COPY_STRING(pszPrintProcessor);
2086 COPY_STRING(pszVendorSetup);
2087 COPY_MULTIZ_STRING(pszzColorProfiles);
2088 COPY_STRING(pszInfPath);
2089 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2090 break;
2094 default:
2095 FIXME("for level %u\n", level);
2098 pDriversW += di_sizeof[level];
2099 out += di_sizeof[level];
2100 id++;
2103 #undef COPY_STRING
2104 #undef COPY_MULTIZ_STRING
2108 /***********************************************************
2109 * printer_info_AtoW
2111 static void *printer_info_AtoW( const void *data, DWORD level )
2113 void *ret;
2114 UNICODE_STRING usBuffer;
2116 if (!data) return NULL;
2118 if (level < 1 || level > 9) return NULL;
2120 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2121 if (!ret) return NULL;
2123 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2125 switch (level)
2127 case 2:
2129 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2130 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2132 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2133 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2134 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2135 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2136 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2137 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2138 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2139 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2140 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2141 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2142 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2143 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2144 break;
2147 case 8:
2148 case 9:
2150 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2151 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2153 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2154 break;
2157 default:
2158 FIXME( "Unhandled level %d\n", level );
2159 HeapFree( GetProcessHeap(), 0, ret );
2160 return NULL;
2163 return ret;
2166 /***********************************************************
2167 * free_printer_info
2169 static void free_printer_info( void *data, DWORD level )
2171 if (!data) return;
2173 switch (level)
2175 case 2:
2177 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2179 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2180 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2181 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2182 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2183 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2184 HeapFree( GetProcessHeap(), 0, piW->pComment );
2185 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2186 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2187 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2188 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2189 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2190 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2191 break;
2194 case 8:
2195 case 9:
2197 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2199 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2200 break;
2203 default:
2204 FIXME( "Unhandled level %d\n", level );
2207 HeapFree( GetProcessHeap(), 0, data );
2208 return;
2211 /******************************************************************
2212 * DeviceCapabilities [WINSPOOL.@]
2213 * DeviceCapabilitiesA [WINSPOOL.@]
2216 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2217 LPSTR pOutput, LPDEVMODEA lpdm)
2219 INT ret;
2221 if (!GDI_CallDeviceCapabilities16)
2223 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2224 (LPCSTR)104 );
2225 if (!GDI_CallDeviceCapabilities16) return -1;
2227 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2229 /* If DC_PAPERSIZE map POINT16s to POINTs */
2230 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2231 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2232 POINT *pt = (POINT *)pOutput;
2233 INT i;
2234 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2235 for(i = 0; i < ret; i++, pt++)
2237 pt->x = tmp[i].x;
2238 pt->y = tmp[i].y;
2240 HeapFree( GetProcessHeap(), 0, tmp );
2242 return ret;
2246 /*****************************************************************************
2247 * DeviceCapabilitiesW [WINSPOOL.@]
2249 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2252 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2253 WORD fwCapability, LPWSTR pOutput,
2254 const DEVMODEW *pDevMode)
2256 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2257 LPSTR pDeviceA = strdupWtoA(pDevice);
2258 LPSTR pPortA = strdupWtoA(pPort);
2259 INT ret;
2261 if(pOutput && (fwCapability == DC_BINNAMES ||
2262 fwCapability == DC_FILEDEPENDENCIES ||
2263 fwCapability == DC_PAPERNAMES)) {
2264 /* These need A -> W translation */
2265 INT size = 0, i;
2266 LPSTR pOutputA;
2267 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2268 dmA);
2269 if(ret == -1)
2270 return ret;
2271 switch(fwCapability) {
2272 case DC_BINNAMES:
2273 size = 24;
2274 break;
2275 case DC_PAPERNAMES:
2276 case DC_FILEDEPENDENCIES:
2277 size = 64;
2278 break;
2280 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2281 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2282 dmA);
2283 for(i = 0; i < ret; i++)
2284 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2285 pOutput + (i * size), size);
2286 HeapFree(GetProcessHeap(), 0, pOutputA);
2287 } else {
2288 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2289 (LPSTR)pOutput, dmA);
2291 HeapFree(GetProcessHeap(),0,pPortA);
2292 HeapFree(GetProcessHeap(),0,pDeviceA);
2293 HeapFree(GetProcessHeap(),0,dmA);
2294 return ret;
2297 /******************************************************************
2298 * DocumentPropertiesA [WINSPOOL.@]
2300 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2302 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2303 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2304 LPDEVMODEA pDevModeInput,DWORD fMode )
2306 LPSTR lpName = pDeviceName;
2307 static CHAR port[] = "LPT1:";
2308 LONG ret;
2310 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2311 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2314 if(!pDeviceName) {
2315 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2316 if(!lpNameW) {
2317 ERR("no name from hPrinter?\n");
2318 SetLastError(ERROR_INVALID_HANDLE);
2319 return -1;
2321 lpName = strdupWtoA(lpNameW);
2324 if (!GDI_CallExtDeviceMode16)
2326 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2327 (LPCSTR)102 );
2328 if (!GDI_CallExtDeviceMode16) {
2329 ERR("No CallExtDeviceMode16?\n");
2330 return -1;
2333 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2334 pDevModeInput, NULL, fMode);
2336 if(!pDeviceName)
2337 HeapFree(GetProcessHeap(),0,lpName);
2338 return ret;
2342 /*****************************************************************************
2343 * DocumentPropertiesW (WINSPOOL.@)
2345 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2347 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2348 LPWSTR pDeviceName,
2349 LPDEVMODEW pDevModeOutput,
2350 LPDEVMODEW pDevModeInput, DWORD fMode)
2353 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2354 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2355 LPDEVMODEA pDevModeOutputA = NULL;
2356 LONG ret;
2358 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2359 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2360 fMode);
2361 if(pDevModeOutput) {
2362 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2363 if(ret < 0) return ret;
2364 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2366 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2367 pDevModeInputA, fMode);
2368 if(pDevModeOutput) {
2369 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2370 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2372 if(fMode == 0 && ret > 0)
2373 ret += (CCHDEVICENAME + CCHFORMNAME);
2374 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2375 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2376 return ret;
2379 /*****************************************************************************
2380 * IsValidDevmodeA [WINSPOOL.@]
2382 * Validate a DEVMODE structure and fix errors if possible.
2385 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2387 FIXME("(%p,%ld): stub\n", pDevMode, size);
2389 if(!pDevMode)
2390 return FALSE;
2392 return TRUE;
2395 /*****************************************************************************
2396 * IsValidDevmodeW [WINSPOOL.@]
2398 * Validate a DEVMODE structure and fix errors if possible.
2401 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2403 FIXME("(%p,%ld): stub\n", pDevMode, size);
2405 if(!pDevMode)
2406 return FALSE;
2408 return TRUE;
2411 /******************************************************************
2412 * OpenPrinterA [WINSPOOL.@]
2414 * See OpenPrinterW.
2417 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2418 LPPRINTER_DEFAULTSA pDefault)
2420 UNICODE_STRING lpPrinterNameW;
2421 UNICODE_STRING usBuffer;
2422 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2423 PWSTR pwstrPrinterNameW;
2424 BOOL ret;
2426 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2428 if(pDefault) {
2429 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2430 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2431 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2432 pDefaultW = &DefaultW;
2434 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2435 if(pDefault) {
2436 RtlFreeUnicodeString(&usBuffer);
2437 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2439 RtlFreeUnicodeString(&lpPrinterNameW);
2440 return ret;
2443 /******************************************************************
2444 * OpenPrinterW [WINSPOOL.@]
2446 * Open a Printer / Printserver or a Printer-Object
2448 * PARAMS
2449 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2450 * phPrinter [O] The resulting Handle is stored here
2451 * pDefault [I] PTR to Default Printer Settings or NULL
2453 * RETURNS
2454 * Success: TRUE
2455 * Failure: FALSE
2457 * NOTES
2458 * lpPrinterName is one of:
2459 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2460 *| Printer: "PrinterName"
2461 *| Printer-Object: "PrinterName,Job xxx"
2462 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2463 *| XcvPort: "Servername,XcvPort PortName"
2465 * BUGS
2466 *| Printer-Object not supported
2467 *| pDefaults is ignored
2470 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2473 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2475 if(!phPrinter) {
2476 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2477 SetLastError(ERROR_INVALID_PARAMETER);
2478 return FALSE;
2481 /* Get the unique handle of the printer or Printserver */
2482 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2484 if (*phPrinter)
2486 HKEY key;
2487 DWORD deleting = 0, size = sizeof( deleting ), type;
2488 DWORD status;
2489 WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key );
2490 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2491 WaitForSingleObject( init_mutex, INFINITE );
2492 status = get_dword_from_reg( key, StatusW );
2493 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2494 ReleaseMutex( init_mutex );
2495 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2496 update_driver( *phPrinter );
2497 RegCloseKey( key );
2500 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2501 return (*phPrinter != 0);
2504 /******************************************************************
2505 * AddMonitorA [WINSPOOL.@]
2507 * See AddMonitorW.
2510 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2512 LPWSTR nameW = NULL;
2513 INT len;
2514 BOOL res;
2515 LPMONITOR_INFO_2A mi2a;
2516 MONITOR_INFO_2W mi2w;
2518 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2519 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2520 debugstr_a(mi2a ? mi2a->pName : NULL),
2521 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2522 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2524 if (Level != 2) {
2525 SetLastError(ERROR_INVALID_LEVEL);
2526 return FALSE;
2529 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2530 if (mi2a == NULL) {
2531 return FALSE;
2534 if (pName) {
2535 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2536 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2537 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2540 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2541 if (mi2a->pName) {
2542 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2543 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2544 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2546 if (mi2a->pEnvironment) {
2547 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2548 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2549 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2551 if (mi2a->pDLLName) {
2552 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2553 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2554 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2557 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2559 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2560 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2561 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2563 HeapFree(GetProcessHeap(), 0, nameW);
2564 return (res);
2567 /******************************************************************************
2568 * AddMonitorW [WINSPOOL.@]
2570 * Install a Printmonitor
2572 * PARAMS
2573 * pName [I] Servername or NULL (local Computer)
2574 * Level [I] Structure-Level (Must be 2)
2575 * pMonitors [I] PTR to MONITOR_INFO_2
2577 * RETURNS
2578 * Success: TRUE
2579 * Failure: FALSE
2581 * NOTES
2582 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2585 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2587 LPMONITOR_INFO_2W mi2w;
2589 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2590 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2591 debugstr_w(mi2w ? mi2w->pName : NULL),
2592 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2593 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2595 if ((backend == NULL) && !load_backend()) return FALSE;
2597 if (Level != 2) {
2598 SetLastError(ERROR_INVALID_LEVEL);
2599 return FALSE;
2602 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2603 if (mi2w == NULL) {
2604 return FALSE;
2607 return backend->fpAddMonitor(pName, Level, pMonitors);
2610 /******************************************************************
2611 * DeletePrinterDriverA [WINSPOOL.@]
2614 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2616 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2619 /******************************************************************
2620 * DeletePrinterDriverW [WINSPOOL.@]
2623 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2625 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2628 /******************************************************************
2629 * DeleteMonitorA [WINSPOOL.@]
2631 * See DeleteMonitorW.
2634 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2636 LPWSTR nameW = NULL;
2637 LPWSTR EnvironmentW = NULL;
2638 LPWSTR MonitorNameW = NULL;
2639 BOOL res;
2640 INT len;
2642 if (pName) {
2643 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2644 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2645 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2648 if (pEnvironment) {
2649 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2650 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2651 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2653 if (pMonitorName) {
2654 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2655 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2656 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2659 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2661 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2662 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2663 HeapFree(GetProcessHeap(), 0, nameW);
2664 return (res);
2667 /******************************************************************
2668 * DeleteMonitorW [WINSPOOL.@]
2670 * Delete a specific Printmonitor from a Printing-Environment
2672 * PARAMS
2673 * pName [I] Servername or NULL (local Computer)
2674 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2675 * pMonitorName [I] Name of the Monitor, that should be deleted
2677 * RETURNS
2678 * Success: TRUE
2679 * Failure: FALSE
2681 * NOTES
2682 * pEnvironment is ignored in Windows for the local Computer.
2685 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2688 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2689 debugstr_w(pMonitorName));
2691 if ((backend == NULL) && !load_backend()) return FALSE;
2693 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2697 /******************************************************************
2698 * DeletePortA [WINSPOOL.@]
2700 * See DeletePortW.
2703 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2705 LPWSTR nameW = NULL;
2706 LPWSTR portW = NULL;
2707 INT len;
2708 DWORD res;
2710 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2712 /* convert servername to unicode */
2713 if (pName) {
2714 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2715 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2716 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2719 /* convert portname to unicode */
2720 if (pPortName) {
2721 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2722 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2723 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2726 res = DeletePortW(nameW, hWnd, portW);
2727 HeapFree(GetProcessHeap(), 0, nameW);
2728 HeapFree(GetProcessHeap(), 0, portW);
2729 return res;
2732 /******************************************************************
2733 * DeletePortW [WINSPOOL.@]
2735 * Delete a specific Port
2737 * PARAMS
2738 * pName [I] Servername or NULL (local Computer)
2739 * hWnd [I] Handle to parent Window for the Dialog-Box
2740 * pPortName [I] Name of the Port, that should be deleted
2742 * RETURNS
2743 * Success: TRUE
2744 * Failure: FALSE
2747 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2749 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2751 if ((backend == NULL) && !load_backend()) return FALSE;
2753 if (!pPortName) {
2754 SetLastError(RPC_X_NULL_REF_POINTER);
2755 return FALSE;
2758 return backend->fpDeletePort(pName, hWnd, pPortName);
2761 /******************************************************************************
2762 * WritePrinter [WINSPOOL.@]
2764 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2766 opened_printer_t *printer;
2767 BOOL ret = FALSE;
2769 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2771 EnterCriticalSection(&printer_handles_cs);
2772 printer = get_opened_printer(hPrinter);
2773 if(!printer)
2775 SetLastError(ERROR_INVALID_HANDLE);
2776 goto end;
2779 if(!printer->doc)
2781 SetLastError(ERROR_SPL_NO_STARTDOC);
2782 goto end;
2785 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2786 end:
2787 LeaveCriticalSection(&printer_handles_cs);
2788 return ret;
2791 /*****************************************************************************
2792 * AddFormA [WINSPOOL.@]
2794 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2796 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2797 return 1;
2800 /*****************************************************************************
2801 * AddFormW [WINSPOOL.@]
2803 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2805 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2806 return 1;
2809 /*****************************************************************************
2810 * AddJobA [WINSPOOL.@]
2812 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2814 BOOL ret;
2815 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2816 DWORD needed;
2818 if(Level != 1) {
2819 SetLastError(ERROR_INVALID_LEVEL);
2820 return FALSE;
2823 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2825 if(ret) {
2826 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2827 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2828 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2829 if(*pcbNeeded > cbBuf) {
2830 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2831 ret = FALSE;
2832 } else {
2833 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2834 addjobA->JobId = addjobW->JobId;
2835 addjobA->Path = (char *)(addjobA + 1);
2836 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2839 return ret;
2842 /*****************************************************************************
2843 * AddJobW [WINSPOOL.@]
2845 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2847 opened_printer_t *printer;
2848 job_t *job;
2849 BOOL ret = FALSE;
2850 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2851 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2852 WCHAR path[MAX_PATH], filename[MAX_PATH];
2853 DWORD len;
2854 ADDJOB_INFO_1W *addjob;
2856 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2858 EnterCriticalSection(&printer_handles_cs);
2860 printer = get_opened_printer(hPrinter);
2862 if(!printer) {
2863 SetLastError(ERROR_INVALID_HANDLE);
2864 goto end;
2867 if(Level != 1) {
2868 SetLastError(ERROR_INVALID_LEVEL);
2869 goto end;
2872 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2873 if(!job)
2874 goto end;
2876 job->job_id = InterlockedIncrement(&next_job_id);
2878 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2879 if(path[len - 1] != '\\')
2880 path[len++] = '\\';
2881 memcpy(path + len, spool_path, sizeof(spool_path));
2882 sprintfW(filename, fmtW, path, job->job_id);
2884 len = strlenW(filename);
2885 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2886 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2887 job->portname = NULL;
2888 job->document_title = strdupW(default_doc_title);
2889 job->printer_name = strdupW(printer->name);
2890 job->devmode = dup_devmode( printer->devmode );
2891 list_add_tail(&printer->queue->jobs, &job->entry);
2893 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2894 if(*pcbNeeded <= cbBuf) {
2895 addjob = (ADDJOB_INFO_1W*)pData;
2896 addjob->JobId = job->job_id;
2897 addjob->Path = (WCHAR *)(addjob + 1);
2898 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2899 ret = TRUE;
2900 } else
2901 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2903 end:
2904 LeaveCriticalSection(&printer_handles_cs);
2905 return ret;
2908 /*****************************************************************************
2909 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2911 * Return the PATH for the Print-Processors
2913 * See GetPrintProcessorDirectoryW.
2917 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2918 DWORD level, LPBYTE Info,
2919 DWORD cbBuf, LPDWORD pcbNeeded)
2921 LPWSTR serverW = NULL;
2922 LPWSTR envW = NULL;
2923 BOOL ret;
2924 INT len;
2926 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2927 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2930 if (server) {
2931 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2932 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2933 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2936 if (env) {
2937 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2938 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2939 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2942 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2943 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2945 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2946 cbBuf, pcbNeeded);
2948 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2949 cbBuf, NULL, NULL) > 0;
2952 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2953 HeapFree(GetProcessHeap(), 0, envW);
2954 HeapFree(GetProcessHeap(), 0, serverW);
2955 return ret;
2958 /*****************************************************************************
2959 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2961 * Return the PATH for the Print-Processors
2963 * PARAMS
2964 * server [I] Servername (NT only) or NULL (local Computer)
2965 * env [I] Printing-Environment (see below) or NULL (Default)
2966 * level [I] Structure-Level (must be 1)
2967 * Info [O] PTR to Buffer that receives the Result
2968 * cbBuf [I] Size of Buffer at "Info"
2969 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2970 * required for the Buffer at "Info"
2972 * RETURNS
2973 * Success: TRUE and in pcbNeeded the Bytes used in Info
2974 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2975 * if cbBuf is too small
2977 * Native Values returned in Info on Success:
2978 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2979 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2980 *| win9x(Windows 4.0): "%winsysdir%"
2982 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2984 * BUGS
2985 * Only NULL or "" is supported for server
2988 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2989 DWORD level, LPBYTE Info,
2990 DWORD cbBuf, LPDWORD pcbNeeded)
2993 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2994 Info, cbBuf, pcbNeeded);
2996 if ((backend == NULL) && !load_backend()) return FALSE;
2998 if (level != 1) {
2999 /* (Level != 1) is ignored in win9x */
3000 SetLastError(ERROR_INVALID_LEVEL);
3001 return FALSE;
3004 if (pcbNeeded == NULL) {
3005 /* (pcbNeeded == NULL) is ignored in win9x */
3006 SetLastError(RPC_X_NULL_REF_POINTER);
3007 return FALSE;
3010 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3013 /*****************************************************************************
3014 * WINSPOOL_OpenDriverReg [internal]
3016 * opens the registry for the printer drivers depending on the given input
3017 * variable pEnvironment
3019 * RETURNS:
3020 * the opened hkey on success
3021 * NULL on error
3023 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3025 HKEY retval = NULL;
3026 LPWSTR buffer;
3027 const printenv_t * env;
3029 TRACE("(%s)\n", debugstr_w(pEnvironment));
3031 env = validate_envW(pEnvironment);
3032 if (!env) return NULL;
3034 buffer = HeapAlloc( GetProcessHeap(), 0,
3035 (strlenW(DriversW) + strlenW(env->envname) +
3036 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3037 if(buffer) {
3038 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3039 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3040 HeapFree(GetProcessHeap(), 0, buffer);
3042 return retval;
3045 /*****************************************************************************
3046 * set_devices_and_printerports [internal]
3048 * set the [Devices] and [PrinterPorts] entries for a printer.
3051 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3053 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3054 WCHAR *devline;
3055 HKEY hkey;
3057 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3059 /* FIXME: the driver must change to "winspool" */
3060 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3061 if (devline) {
3062 lstrcpyW(devline, driver_nt);
3063 lstrcatW(devline, commaW);
3064 lstrcatW(devline, pi->pPortName);
3066 TRACE("using %s\n", debugstr_w(devline));
3067 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
3068 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3069 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3070 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3071 RegCloseKey(hkey);
3074 lstrcatW(devline, timeout_15_45);
3075 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
3076 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3077 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3078 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3079 RegCloseKey(hkey);
3081 HeapFree(GetProcessHeap(), 0, devline);
3085 /*****************************************************************************
3086 * AddPrinterW [WINSPOOL.@]
3088 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3090 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3091 LPDEVMODEW dm;
3092 HANDLE retval;
3093 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3094 LONG size;
3096 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3098 if(pName != NULL) {
3099 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3100 SetLastError(ERROR_INVALID_PARAMETER);
3101 return 0;
3103 if(Level != 2) {
3104 ERR("Level = %d, unsupported!\n", Level);
3105 SetLastError(ERROR_INVALID_LEVEL);
3106 return 0;
3108 if(!pPrinter) {
3109 SetLastError(ERROR_INVALID_PARAMETER);
3110 return 0;
3112 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3113 ERROR_SUCCESS) {
3114 ERR("Can't create Printers key\n");
3115 return 0;
3117 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3118 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3119 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3120 RegCloseKey(hkeyPrinter);
3121 RegCloseKey(hkeyPrinters);
3122 return 0;
3124 RegCloseKey(hkeyPrinter);
3126 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3127 if(!hkeyDrivers) {
3128 ERR("Can't create Drivers key\n");
3129 RegCloseKey(hkeyPrinters);
3130 return 0;
3132 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3133 ERROR_SUCCESS) {
3134 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3135 RegCloseKey(hkeyPrinters);
3136 RegCloseKey(hkeyDrivers);
3137 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3138 return 0;
3140 RegCloseKey(hkeyDriver);
3141 RegCloseKey(hkeyDrivers);
3143 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3144 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3145 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3146 RegCloseKey(hkeyPrinters);
3147 return 0;
3150 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3151 ERROR_SUCCESS) {
3152 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3153 SetLastError(ERROR_INVALID_PRINTER_NAME);
3154 RegCloseKey(hkeyPrinters);
3155 return 0;
3158 set_devices_and_printerports(pi);
3160 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3161 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3162 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3163 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3164 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3165 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3166 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3167 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3168 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3169 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3170 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3171 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3172 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3173 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3174 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3175 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3176 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3177 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3179 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3181 if (size < 0)
3183 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3184 size = sizeof(DEVMODEW);
3186 if(pi->pDevMode)
3187 dm = pi->pDevMode;
3188 else
3190 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3191 dm->dmSize = size;
3192 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3194 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3195 HeapFree( GetProcessHeap(), 0, dm );
3196 dm = NULL;
3198 else
3200 /* set devmode to printer name */
3201 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3205 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3206 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3208 RegCloseKey(hkeyPrinter);
3209 RegCloseKey(hkeyPrinters);
3210 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3211 ERR("OpenPrinter failing\n");
3212 return 0;
3214 return retval;
3217 /*****************************************************************************
3218 * AddPrinterA [WINSPOOL.@]
3220 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3222 UNICODE_STRING pNameW;
3223 PWSTR pwstrNameW;
3224 PRINTER_INFO_2W *piW;
3225 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3226 HANDLE ret;
3228 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3229 if(Level != 2) {
3230 ERR("Level = %d, unsupported!\n", Level);
3231 SetLastError(ERROR_INVALID_LEVEL);
3232 return 0;
3234 pwstrNameW = asciitounicode(&pNameW,pName);
3235 piW = printer_info_AtoW( piA, Level );
3237 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3239 free_printer_info( piW, Level );
3240 RtlFreeUnicodeString(&pNameW);
3241 return ret;
3245 /*****************************************************************************
3246 * ClosePrinter [WINSPOOL.@]
3248 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3250 UINT_PTR i = (UINT_PTR)hPrinter;
3251 opened_printer_t *printer = NULL;
3252 BOOL ret = FALSE;
3254 TRACE("(%p)\n", hPrinter);
3256 EnterCriticalSection(&printer_handles_cs);
3258 if ((i > 0) && (i <= nb_printer_handles))
3259 printer = printer_handles[i - 1];
3262 if(printer)
3264 struct list *cursor, *cursor2;
3266 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3268 if (printer->backend_printer) {
3269 backend->fpClosePrinter(printer->backend_printer);
3272 if(printer->doc)
3273 EndDocPrinter(hPrinter);
3275 if(InterlockedDecrement(&printer->queue->ref) == 0)
3277 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3279 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3280 ScheduleJob(hPrinter, job->job_id);
3282 HeapFree(GetProcessHeap(), 0, printer->queue);
3285 free_printer_entry( printer );
3286 printer_handles[i - 1] = NULL;
3287 ret = TRUE;
3289 LeaveCriticalSection(&printer_handles_cs);
3290 return ret;
3293 /*****************************************************************************
3294 * DeleteFormA [WINSPOOL.@]
3296 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3298 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3299 return 1;
3302 /*****************************************************************************
3303 * DeleteFormW [WINSPOOL.@]
3305 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3307 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3308 return 1;
3311 /*****************************************************************************
3312 * DeletePrinter [WINSPOOL.@]
3314 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3316 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3317 HKEY hkeyPrinters, hkey;
3318 WCHAR def[MAX_PATH];
3319 DWORD size = sizeof( def ) / sizeof( def[0] );
3321 if(!lpNameW) {
3322 SetLastError(ERROR_INVALID_HANDLE);
3323 return FALSE;
3325 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3326 RegDeleteTreeW(hkeyPrinters, lpNameW);
3327 RegCloseKey(hkeyPrinters);
3329 WriteProfileStringW(devicesW, lpNameW, NULL);
3330 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3332 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3333 RegDeleteValueW(hkey, lpNameW);
3334 RegCloseKey(hkey);
3337 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3338 RegDeleteValueW(hkey, lpNameW);
3339 RegCloseKey(hkey);
3342 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3344 WriteProfileStringW( windowsW, deviceW, NULL );
3345 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3347 RegDeleteValueW( hkey, deviceW );
3348 RegCloseKey( hkey );
3350 SetDefaultPrinterW( NULL );
3353 return TRUE;
3356 /*****************************************************************************
3357 * SetPrinterA [WINSPOOL.@]
3359 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3361 BYTE *dataW = data;
3362 BOOL ret;
3364 if (level != 0)
3366 dataW = printer_info_AtoW( data, level );
3367 if (!dataW) return FALSE;
3370 ret = SetPrinterW( printer, level, dataW, command );
3372 if (dataW != data) free_printer_info( dataW, level );
3374 return ret;
3377 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3379 set_reg_szW( key, NameW, pi->pPrinterName );
3380 set_reg_szW( key, Share_NameW, pi->pShareName );
3381 set_reg_szW( key, PortW, pi->pPortName );
3382 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3383 set_reg_szW( key, DescriptionW, pi->pComment );
3384 set_reg_szW( key, LocationW, pi->pLocation );
3386 if (pi->pDevMode)
3387 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3389 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3390 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3391 set_reg_szW( key, DatatypeW, pi->pDatatype );
3392 set_reg_szW( key, ParametersW, pi->pParameters );
3394 set_reg_DWORD( key, AttributesW, pi->Attributes );
3395 set_reg_DWORD( key, PriorityW, pi->Priority );
3396 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3397 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3398 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3401 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3403 if (!pi->pDevMode) return FALSE;
3405 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3406 return TRUE;
3409 /******************************************************************************
3410 * SetPrinterW [WINSPOOL.@]
3412 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3414 HKEY key;
3415 BOOL ret = FALSE;
3417 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3419 if (command != 0) FIXME( "Ignoring command %d\n", command );
3421 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3422 return FALSE;
3424 switch (level)
3426 case 2:
3428 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3429 set_printer_2( key, pi2 );
3430 ret = TRUE;
3431 break;
3434 case 9:
3436 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3437 ret = set_printer_9( key, pi );
3438 break;
3441 default:
3442 FIXME( "Unimplemented level %d\n", level );
3443 SetLastError( ERROR_INVALID_LEVEL );
3446 RegCloseKey( key );
3447 return ret;
3450 /*****************************************************************************
3451 * SetJobA [WINSPOOL.@]
3453 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3454 LPBYTE pJob, DWORD Command)
3456 BOOL ret;
3457 LPBYTE JobW;
3458 UNICODE_STRING usBuffer;
3460 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3462 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3463 are all ignored by SetJob, so we don't bother copying them */
3464 switch(Level)
3466 case 0:
3467 JobW = NULL;
3468 break;
3469 case 1:
3471 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3472 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3474 JobW = (LPBYTE)info1W;
3475 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3476 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3477 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3478 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3479 info1W->Status = info1A->Status;
3480 info1W->Priority = info1A->Priority;
3481 info1W->Position = info1A->Position;
3482 info1W->PagesPrinted = info1A->PagesPrinted;
3483 break;
3485 case 2:
3487 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3488 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3490 JobW = (LPBYTE)info2W;
3491 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3492 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3493 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3494 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3495 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3496 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3497 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3498 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3499 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3500 info2W->Status = info2A->Status;
3501 info2W->Priority = info2A->Priority;
3502 info2W->Position = info2A->Position;
3503 info2W->StartTime = info2A->StartTime;
3504 info2W->UntilTime = info2A->UntilTime;
3505 info2W->PagesPrinted = info2A->PagesPrinted;
3506 break;
3508 case 3:
3509 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3510 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3511 break;
3512 default:
3513 SetLastError(ERROR_INVALID_LEVEL);
3514 return FALSE;
3517 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3519 switch(Level)
3521 case 1:
3523 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3524 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3525 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3526 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3527 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3528 break;
3530 case 2:
3532 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3533 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3534 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3535 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3536 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3537 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3538 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3539 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3540 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3541 break;
3544 HeapFree(GetProcessHeap(), 0, JobW);
3546 return ret;
3549 /*****************************************************************************
3550 * SetJobW [WINSPOOL.@]
3552 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3553 LPBYTE pJob, DWORD Command)
3555 BOOL ret = FALSE;
3556 job_t *job;
3558 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3559 FIXME("Ignoring everything other than document title\n");
3561 EnterCriticalSection(&printer_handles_cs);
3562 job = get_job(hPrinter, JobId);
3563 if(!job)
3564 goto end;
3566 switch(Level)
3568 case 0:
3569 break;
3570 case 1:
3572 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3573 HeapFree(GetProcessHeap(), 0, job->document_title);
3574 job->document_title = strdupW(info1->pDocument);
3575 break;
3577 case 2:
3579 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3580 HeapFree(GetProcessHeap(), 0, job->document_title);
3581 job->document_title = strdupW(info2->pDocument);
3582 HeapFree(GetProcessHeap(), 0, job->devmode);
3583 job->devmode = dup_devmode( info2->pDevMode );
3584 break;
3586 case 3:
3587 break;
3588 default:
3589 SetLastError(ERROR_INVALID_LEVEL);
3590 goto end;
3592 ret = TRUE;
3593 end:
3594 LeaveCriticalSection(&printer_handles_cs);
3595 return ret;
3598 /*****************************************************************************
3599 * EndDocPrinter [WINSPOOL.@]
3601 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3603 opened_printer_t *printer;
3604 BOOL ret = FALSE;
3605 TRACE("(%p)\n", hPrinter);
3607 EnterCriticalSection(&printer_handles_cs);
3609 printer = get_opened_printer(hPrinter);
3610 if(!printer)
3612 SetLastError(ERROR_INVALID_HANDLE);
3613 goto end;
3616 if(!printer->doc)
3618 SetLastError(ERROR_SPL_NO_STARTDOC);
3619 goto end;
3622 CloseHandle(printer->doc->hf);
3623 ScheduleJob(hPrinter, printer->doc->job_id);
3624 HeapFree(GetProcessHeap(), 0, printer->doc);
3625 printer->doc = NULL;
3626 ret = TRUE;
3627 end:
3628 LeaveCriticalSection(&printer_handles_cs);
3629 return ret;
3632 /*****************************************************************************
3633 * EndPagePrinter [WINSPOOL.@]
3635 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3637 FIXME("(%p): stub\n", hPrinter);
3638 return TRUE;
3641 /*****************************************************************************
3642 * StartDocPrinterA [WINSPOOL.@]
3644 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3646 UNICODE_STRING usBuffer;
3647 DOC_INFO_2W doc2W;
3648 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3649 DWORD ret;
3651 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3652 or one (DOC_INFO_3) extra DWORDs */
3654 switch(Level) {
3655 case 2:
3656 doc2W.JobId = doc2->JobId;
3657 /* fall through */
3658 case 3:
3659 doc2W.dwMode = doc2->dwMode;
3660 /* fall through */
3661 case 1:
3662 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3663 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3664 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3665 break;
3667 default:
3668 SetLastError(ERROR_INVALID_LEVEL);
3669 return FALSE;
3672 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3674 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3675 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3676 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3678 return ret;
3681 /*****************************************************************************
3682 * StartDocPrinterW [WINSPOOL.@]
3684 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3686 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3687 opened_printer_t *printer;
3688 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3689 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3690 JOB_INFO_1W job_info;
3691 DWORD needed, ret = 0;
3692 HANDLE hf;
3693 WCHAR *filename;
3694 job_t *job;
3696 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3697 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3698 debugstr_w(doc->pDatatype));
3700 if(Level < 1 || Level > 3)
3702 SetLastError(ERROR_INVALID_LEVEL);
3703 return 0;
3706 EnterCriticalSection(&printer_handles_cs);
3707 printer = get_opened_printer(hPrinter);
3708 if(!printer)
3710 SetLastError(ERROR_INVALID_HANDLE);
3711 goto end;
3714 if(printer->doc)
3716 SetLastError(ERROR_INVALID_PRINTER_STATE);
3717 goto end;
3720 /* Even if we're printing to a file we still add a print job, we'll
3721 just ignore the spool file name */
3723 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3725 ERR("AddJob failed gle %u\n", GetLastError());
3726 goto end;
3729 /* use pOutputFile only, when it is a real filename */
3730 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3731 filename = doc->pOutputFile;
3732 else
3733 filename = addjob->Path;
3735 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3736 if(hf == INVALID_HANDLE_VALUE)
3737 goto end;
3739 memset(&job_info, 0, sizeof(job_info));
3740 job_info.pDocument = doc->pDocName;
3741 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3743 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3744 printer->doc->hf = hf;
3745 ret = printer->doc->job_id = addjob->JobId;
3746 job = get_job(hPrinter, ret);
3747 job->portname = strdupW(doc->pOutputFile);
3749 end:
3750 LeaveCriticalSection(&printer_handles_cs);
3752 return ret;
3755 /*****************************************************************************
3756 * StartPagePrinter [WINSPOOL.@]
3758 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3760 FIXME("(%p): stub\n", hPrinter);
3761 return TRUE;
3764 /*****************************************************************************
3765 * GetFormA [WINSPOOL.@]
3767 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3768 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3770 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3771 Level,pForm,cbBuf,pcbNeeded);
3772 return FALSE;
3775 /*****************************************************************************
3776 * GetFormW [WINSPOOL.@]
3778 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3779 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3781 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3782 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3783 return FALSE;
3786 /*****************************************************************************
3787 * SetFormA [WINSPOOL.@]
3789 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3790 LPBYTE pForm)
3792 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3793 return FALSE;
3796 /*****************************************************************************
3797 * SetFormW [WINSPOOL.@]
3799 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3800 LPBYTE pForm)
3802 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3803 return FALSE;
3806 /*****************************************************************************
3807 * ReadPrinter [WINSPOOL.@]
3809 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3810 LPDWORD pNoBytesRead)
3812 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3813 return FALSE;
3816 /*****************************************************************************
3817 * ResetPrinterA [WINSPOOL.@]
3819 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3821 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3822 return FALSE;
3825 /*****************************************************************************
3826 * ResetPrinterW [WINSPOOL.@]
3828 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3830 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3831 return FALSE;
3834 /*****************************************************************************
3835 * get_filename_from_reg [internal]
3837 * Get ValueName from hkey storing result in out
3838 * when the Value in the registry has only a filename, use driverdir as prefix
3839 * outlen is space left in out
3840 * String is stored either as unicode or ascii
3844 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3845 LPBYTE out, DWORD outlen, LPDWORD needed)
3847 WCHAR filename[MAX_PATH];
3848 DWORD size;
3849 DWORD type;
3850 LONG ret;
3851 LPWSTR buffer = filename;
3852 LPWSTR ptr;
3854 *needed = 0;
3855 size = sizeof(filename);
3856 buffer[0] = '\0';
3857 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3858 if (ret == ERROR_MORE_DATA) {
3859 TRACE("need dynamic buffer: %u\n", size);
3860 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3861 if (!buffer) {
3862 /* No Memory is bad */
3863 return FALSE;
3865 buffer[0] = '\0';
3866 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3869 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3870 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3871 return FALSE;
3874 ptr = buffer;
3875 while (ptr) {
3876 /* do we have a full path ? */
3877 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3878 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3880 if (!ret) {
3881 /* we must build the full Path */
3882 *needed += dirlen;
3883 if ((out) && (outlen > dirlen)) {
3884 lstrcpyW((LPWSTR)out, driverdir);
3885 out += dirlen;
3886 outlen -= dirlen;
3888 else
3889 out = NULL;
3892 /* write the filename */
3893 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3894 if ((out) && (outlen >= size)) {
3895 lstrcpyW((LPWSTR)out, ptr);
3896 out += size;
3897 outlen -= size;
3899 else
3900 out = NULL;
3901 *needed += size;
3902 ptr += lstrlenW(ptr)+1;
3903 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3906 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3908 /* write the multisz-termination */
3909 if (type == REG_MULTI_SZ) {
3910 size = sizeof(WCHAR);
3912 *needed += size;
3913 if (out && (outlen >= size)) {
3914 memset (out, 0, size);
3917 return TRUE;
3920 /*****************************************************************************
3921 * WINSPOOL_GetStringFromReg
3923 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3924 * String is stored as unicode.
3926 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3927 DWORD buflen, DWORD *needed)
3929 DWORD sz = buflen, type;
3930 LONG ret;
3932 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3933 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3934 WARN("Got ret = %d\n", ret);
3935 *needed = 0;
3936 return FALSE;
3938 /* add space for terminating '\0' */
3939 sz += sizeof(WCHAR);
3940 *needed = sz;
3942 if (ptr)
3943 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3945 return TRUE;
3948 /*****************************************************************************
3949 * WINSPOOL_GetDefaultDevMode
3951 * Get a default DevMode values for wineps.
3952 * FIXME - use ppd.
3955 static void WINSPOOL_GetDefaultDevMode(
3956 LPBYTE ptr,
3957 DWORD buflen, DWORD *needed)
3959 DEVMODEW dm;
3960 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3962 /* fill default DEVMODE - should be read from ppd... */
3963 ZeroMemory( &dm, sizeof(dm) );
3964 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3965 dm.dmSpecVersion = DM_SPECVERSION;
3966 dm.dmDriverVersion = 1;
3967 dm.dmSize = sizeof(DEVMODEW);
3968 dm.dmDriverExtra = 0;
3969 dm.dmFields =
3970 DM_ORIENTATION | DM_PAPERSIZE |
3971 DM_PAPERLENGTH | DM_PAPERWIDTH |
3972 DM_SCALE |
3973 DM_COPIES |
3974 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3975 DM_YRESOLUTION | DM_TTOPTION;
3977 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3978 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3979 dm.u1.s1.dmPaperLength = 2970;
3980 dm.u1.s1.dmPaperWidth = 2100;
3982 dm.u1.s1.dmScale = 100;
3983 dm.u1.s1.dmCopies = 1;
3984 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3985 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3986 /* dm.dmColor */
3987 /* dm.dmDuplex */
3988 dm.dmYResolution = 300; /* 300dpi */
3989 dm.dmTTOption = DMTT_BITMAP;
3990 /* dm.dmCollate */
3991 /* dm.dmFormName */
3992 /* dm.dmLogPixels */
3993 /* dm.dmBitsPerPel */
3994 /* dm.dmPelsWidth */
3995 /* dm.dmPelsHeight */
3996 /* dm.u2.dmDisplayFlags */
3997 /* dm.dmDisplayFrequency */
3998 /* dm.dmICMMethod */
3999 /* dm.dmICMIntent */
4000 /* dm.dmMediaType */
4001 /* dm.dmDitherType */
4002 /* dm.dmReserved1 */
4003 /* dm.dmReserved2 */
4004 /* dm.dmPanningWidth */
4005 /* dm.dmPanningHeight */
4007 if(buflen >= sizeof(DEVMODEW))
4008 memcpy(ptr, &dm, sizeof(DEVMODEW));
4009 *needed = sizeof(DEVMODEW);
4012 /*****************************************************************************
4013 * WINSPOOL_GetDevModeFromReg
4015 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4016 * DevMode is stored either as unicode or ascii.
4018 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4019 LPBYTE ptr,
4020 DWORD buflen, DWORD *needed)
4022 DWORD sz = buflen, type;
4023 LONG ret;
4025 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4026 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4027 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4028 if (sz < sizeof(DEVMODEA))
4030 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4031 return FALSE;
4033 /* ensures that dmSize is not erratically bogus if registry is invalid */
4034 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4035 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4036 sz += (CCHDEVICENAME + CCHFORMNAME);
4037 if (ptr && (buflen >= sz)) {
4038 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4039 memcpy(ptr, dmW, sz);
4040 HeapFree(GetProcessHeap(),0,dmW);
4042 *needed = sz;
4043 return TRUE;
4046 /*********************************************************************
4047 * WINSPOOL_GetPrinter_1
4049 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4051 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4052 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4054 DWORD size, left = cbBuf;
4055 BOOL space = (cbBuf > 0);
4056 LPBYTE ptr = buf;
4058 *pcbNeeded = 0;
4060 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4061 if(space && size <= left) {
4062 pi1->pName = (LPWSTR)ptr;
4063 ptr += size;
4064 left -= size;
4065 } else
4066 space = FALSE;
4067 *pcbNeeded += size;
4070 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4071 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4072 if(space && size <= left) {
4073 pi1->pDescription = (LPWSTR)ptr;
4074 ptr += size;
4075 left -= size;
4076 } else
4077 space = FALSE;
4078 *pcbNeeded += size;
4081 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4082 if(space && size <= left) {
4083 pi1->pComment = (LPWSTR)ptr;
4084 ptr += size;
4085 left -= size;
4086 } else
4087 space = FALSE;
4088 *pcbNeeded += size;
4091 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4093 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4094 memset(pi1, 0, sizeof(*pi1));
4096 return space;
4098 /*********************************************************************
4099 * WINSPOOL_GetPrinter_2
4101 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4103 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4104 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4106 DWORD size, left = cbBuf;
4107 BOOL space = (cbBuf > 0);
4108 LPBYTE ptr = buf;
4110 *pcbNeeded = 0;
4112 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4113 if(space && size <= left) {
4114 pi2->pPrinterName = (LPWSTR)ptr;
4115 ptr += size;
4116 left -= size;
4117 } else
4118 space = FALSE;
4119 *pcbNeeded += size;
4121 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4122 if(space && size <= left) {
4123 pi2->pShareName = (LPWSTR)ptr;
4124 ptr += size;
4125 left -= size;
4126 } else
4127 space = FALSE;
4128 *pcbNeeded += size;
4130 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4131 if(space && size <= left) {
4132 pi2->pPortName = (LPWSTR)ptr;
4133 ptr += size;
4134 left -= size;
4135 } else
4136 space = FALSE;
4137 *pcbNeeded += size;
4139 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4140 if(space && size <= left) {
4141 pi2->pDriverName = (LPWSTR)ptr;
4142 ptr += size;
4143 left -= size;
4144 } else
4145 space = FALSE;
4146 *pcbNeeded += size;
4148 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4149 if(space && size <= left) {
4150 pi2->pComment = (LPWSTR)ptr;
4151 ptr += size;
4152 left -= size;
4153 } else
4154 space = FALSE;
4155 *pcbNeeded += size;
4157 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4158 if(space && size <= left) {
4159 pi2->pLocation = (LPWSTR)ptr;
4160 ptr += size;
4161 left -= size;
4162 } else
4163 space = FALSE;
4164 *pcbNeeded += size;
4166 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4167 if(space && size <= left) {
4168 pi2->pDevMode = (LPDEVMODEW)ptr;
4169 ptr += size;
4170 left -= size;
4171 } else
4172 space = FALSE;
4173 *pcbNeeded += size;
4175 else
4177 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4178 if(space && size <= left) {
4179 pi2->pDevMode = (LPDEVMODEW)ptr;
4180 ptr += size;
4181 left -= size;
4182 } else
4183 space = FALSE;
4184 *pcbNeeded += size;
4186 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4187 if(space && size <= left) {
4188 pi2->pSepFile = (LPWSTR)ptr;
4189 ptr += size;
4190 left -= size;
4191 } else
4192 space = FALSE;
4193 *pcbNeeded += size;
4195 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4196 if(space && size <= left) {
4197 pi2->pPrintProcessor = (LPWSTR)ptr;
4198 ptr += size;
4199 left -= size;
4200 } else
4201 space = FALSE;
4202 *pcbNeeded += size;
4204 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4205 if(space && size <= left) {
4206 pi2->pDatatype = (LPWSTR)ptr;
4207 ptr += size;
4208 left -= size;
4209 } else
4210 space = FALSE;
4211 *pcbNeeded += size;
4213 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4214 if(space && size <= left) {
4215 pi2->pParameters = (LPWSTR)ptr;
4216 ptr += size;
4217 left -= size;
4218 } else
4219 space = FALSE;
4220 *pcbNeeded += size;
4222 if(pi2) {
4223 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4224 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4225 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4226 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4227 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4230 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4231 memset(pi2, 0, sizeof(*pi2));
4233 return space;
4236 /*********************************************************************
4237 * WINSPOOL_GetPrinter_4
4239 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4241 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4242 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4244 DWORD size, left = cbBuf;
4245 BOOL space = (cbBuf > 0);
4246 LPBYTE ptr = buf;
4248 *pcbNeeded = 0;
4250 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4251 if(space && size <= left) {
4252 pi4->pPrinterName = (LPWSTR)ptr;
4253 ptr += size;
4254 left -= size;
4255 } else
4256 space = FALSE;
4257 *pcbNeeded += size;
4259 if(pi4) {
4260 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4263 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4264 memset(pi4, 0, sizeof(*pi4));
4266 return space;
4269 /*********************************************************************
4270 * WINSPOOL_GetPrinter_5
4272 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4274 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4275 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4277 DWORD size, left = cbBuf;
4278 BOOL space = (cbBuf > 0);
4279 LPBYTE ptr = buf;
4281 *pcbNeeded = 0;
4283 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4284 if(space && size <= left) {
4285 pi5->pPrinterName = (LPWSTR)ptr;
4286 ptr += size;
4287 left -= size;
4288 } else
4289 space = FALSE;
4290 *pcbNeeded += size;
4292 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4293 if(space && size <= left) {
4294 pi5->pPortName = (LPWSTR)ptr;
4295 ptr += size;
4296 left -= size;
4297 } else
4298 space = FALSE;
4299 *pcbNeeded += size;
4301 if(pi5) {
4302 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4303 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4304 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4307 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4308 memset(pi5, 0, sizeof(*pi5));
4310 return space;
4313 /*********************************************************************
4314 * WINSPOOL_GetPrinter_7
4316 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4318 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4319 DWORD cbBuf, LPDWORD pcbNeeded)
4321 DWORD size, left = cbBuf;
4322 BOOL space = (cbBuf > 0);
4323 LPBYTE ptr = buf;
4325 *pcbNeeded = 0;
4327 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4329 ptr = NULL;
4330 size = sizeof(pi7->pszObjectGUID);
4332 if (space && size <= left) {
4333 pi7->pszObjectGUID = (LPWSTR)ptr;
4334 ptr += size;
4335 left -= size;
4336 } else
4337 space = FALSE;
4338 *pcbNeeded += size;
4339 if (pi7) {
4340 /* We do not have a Directory Service */
4341 pi7->dwAction = DSPRINT_UNPUBLISH;
4344 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4345 memset(pi7, 0, sizeof(*pi7));
4347 return space;
4350 /*********************************************************************
4351 * WINSPOOL_GetPrinter_9
4353 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4355 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4356 DWORD cbBuf, LPDWORD pcbNeeded)
4358 DWORD size;
4359 BOOL space = (cbBuf > 0);
4361 *pcbNeeded = 0;
4363 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4364 if(space && size <= cbBuf) {
4365 pi9->pDevMode = (LPDEVMODEW)buf;
4366 } else
4367 space = FALSE;
4368 *pcbNeeded += size;
4370 else
4372 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4373 if(space && size <= cbBuf) {
4374 pi9->pDevMode = (LPDEVMODEW)buf;
4375 } else
4376 space = FALSE;
4377 *pcbNeeded += size;
4380 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4381 memset(pi9, 0, sizeof(*pi9));
4383 return space;
4386 /*****************************************************************************
4387 * GetPrinterW [WINSPOOL.@]
4389 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4390 DWORD cbBuf, LPDWORD pcbNeeded)
4392 DWORD size, needed = 0, err;
4393 LPBYTE ptr = NULL;
4394 HKEY hkeyPrinter;
4395 BOOL ret;
4397 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4399 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4400 if (err)
4402 SetLastError( err );
4403 return FALSE;
4406 switch(Level) {
4407 case 2:
4409 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4411 size = sizeof(PRINTER_INFO_2W);
4412 if(size <= cbBuf) {
4413 ptr = pPrinter + size;
4414 cbBuf -= size;
4415 memset(pPrinter, 0, size);
4416 } else {
4417 pi2 = NULL;
4418 cbBuf = 0;
4420 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4421 needed += size;
4422 break;
4425 case 4:
4427 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4429 size = sizeof(PRINTER_INFO_4W);
4430 if(size <= cbBuf) {
4431 ptr = pPrinter + size;
4432 cbBuf -= size;
4433 memset(pPrinter, 0, size);
4434 } else {
4435 pi4 = NULL;
4436 cbBuf = 0;
4438 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4439 needed += size;
4440 break;
4444 case 5:
4446 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4448 size = sizeof(PRINTER_INFO_5W);
4449 if(size <= cbBuf) {
4450 ptr = pPrinter + size;
4451 cbBuf -= size;
4452 memset(pPrinter, 0, size);
4453 } else {
4454 pi5 = NULL;
4455 cbBuf = 0;
4458 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4459 needed += size;
4460 break;
4464 case 6:
4466 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4468 size = sizeof(PRINTER_INFO_6);
4469 if (size <= cbBuf) {
4470 /* FIXME: We do not update the status yet */
4471 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4472 ret = TRUE;
4473 } else {
4474 ret = FALSE;
4477 needed += size;
4478 break;
4481 case 7:
4483 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4485 size = sizeof(PRINTER_INFO_7W);
4486 if (size <= cbBuf) {
4487 ptr = pPrinter + size;
4488 cbBuf -= size;
4489 memset(pPrinter, 0, size);
4490 } else {
4491 pi7 = NULL;
4492 cbBuf = 0;
4495 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4496 needed += size;
4497 break;
4501 case 8:
4502 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4503 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4504 /* fall through */
4505 case 9:
4507 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4509 size = sizeof(PRINTER_INFO_9W);
4510 if(size <= cbBuf) {
4511 ptr = pPrinter + size;
4512 cbBuf -= size;
4513 memset(pPrinter, 0, size);
4514 } else {
4515 pi9 = NULL;
4516 cbBuf = 0;
4519 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4520 needed += size;
4521 break;
4525 default:
4526 FIXME("Unimplemented level %d\n", Level);
4527 SetLastError(ERROR_INVALID_LEVEL);
4528 RegCloseKey(hkeyPrinter);
4529 return FALSE;
4532 RegCloseKey(hkeyPrinter);
4534 TRACE("returning %d needed = %d\n", ret, needed);
4535 if(pcbNeeded) *pcbNeeded = needed;
4536 if(!ret)
4537 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4538 return ret;
4541 /*****************************************************************************
4542 * GetPrinterA [WINSPOOL.@]
4544 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4545 DWORD cbBuf, LPDWORD pcbNeeded)
4547 BOOL ret;
4548 LPBYTE buf = NULL;
4550 if (cbBuf)
4551 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4553 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4554 if (ret)
4555 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4556 HeapFree(GetProcessHeap(), 0, buf);
4558 return ret;
4561 /*****************************************************************************
4562 * WINSPOOL_EnumPrintersW
4564 * Implementation of EnumPrintersW
4566 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4567 DWORD dwLevel, LPBYTE lpbPrinters,
4568 DWORD cbBuf, LPDWORD lpdwNeeded,
4569 LPDWORD lpdwReturned)
4572 HKEY hkeyPrinters, hkeyPrinter;
4573 WCHAR PrinterName[255];
4574 DWORD needed = 0, number = 0;
4575 DWORD used, i, left;
4576 PBYTE pi, buf;
4578 if(lpbPrinters)
4579 memset(lpbPrinters, 0, cbBuf);
4580 if(lpdwReturned)
4581 *lpdwReturned = 0;
4582 if(lpdwNeeded)
4583 *lpdwNeeded = 0;
4585 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4586 if(dwType == PRINTER_ENUM_DEFAULT)
4587 return TRUE;
4589 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4590 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4591 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4592 if (!dwType) {
4593 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4594 return TRUE;
4599 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4600 FIXME("dwType = %08x\n", dwType);
4601 SetLastError(ERROR_INVALID_FLAGS);
4602 return FALSE;
4605 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4606 ERROR_SUCCESS) {
4607 ERR("Can't create Printers key\n");
4608 return FALSE;
4611 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4612 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4613 RegCloseKey(hkeyPrinters);
4614 ERR("Can't query Printers key\n");
4615 return FALSE;
4617 TRACE("Found %d printers\n", number);
4619 switch(dwLevel) {
4620 case 1:
4621 used = number * sizeof(PRINTER_INFO_1W);
4622 break;
4623 case 2:
4624 used = number * sizeof(PRINTER_INFO_2W);
4625 break;
4626 case 4:
4627 used = number * sizeof(PRINTER_INFO_4W);
4628 break;
4629 case 5:
4630 used = number * sizeof(PRINTER_INFO_5W);
4631 break;
4633 default:
4634 SetLastError(ERROR_INVALID_LEVEL);
4635 RegCloseKey(hkeyPrinters);
4636 return FALSE;
4638 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4640 for(i = 0; i < number; i++) {
4641 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4642 ERROR_SUCCESS) {
4643 ERR("Can't enum key number %d\n", i);
4644 RegCloseKey(hkeyPrinters);
4645 return FALSE;
4647 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4648 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4649 ERROR_SUCCESS) {
4650 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4651 RegCloseKey(hkeyPrinters);
4652 return FALSE;
4655 if(cbBuf > used) {
4656 buf = lpbPrinters + used;
4657 left = cbBuf - used;
4658 } else {
4659 buf = NULL;
4660 left = 0;
4663 switch(dwLevel) {
4664 case 1:
4665 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4666 left, &needed);
4667 used += needed;
4668 if(pi) pi += sizeof(PRINTER_INFO_1W);
4669 break;
4670 case 2:
4671 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4672 left, &needed);
4673 used += needed;
4674 if(pi) pi += sizeof(PRINTER_INFO_2W);
4675 break;
4676 case 4:
4677 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4678 left, &needed);
4679 used += needed;
4680 if(pi) pi += sizeof(PRINTER_INFO_4W);
4681 break;
4682 case 5:
4683 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4684 left, &needed);
4685 used += needed;
4686 if(pi) pi += sizeof(PRINTER_INFO_5W);
4687 break;
4688 default:
4689 ERR("Shouldn't be here!\n");
4690 RegCloseKey(hkeyPrinter);
4691 RegCloseKey(hkeyPrinters);
4692 return FALSE;
4694 RegCloseKey(hkeyPrinter);
4696 RegCloseKey(hkeyPrinters);
4698 if(lpdwNeeded)
4699 *lpdwNeeded = used;
4701 if(used > cbBuf) {
4702 if(lpbPrinters)
4703 memset(lpbPrinters, 0, cbBuf);
4704 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4705 return FALSE;
4707 if(lpdwReturned)
4708 *lpdwReturned = number;
4709 SetLastError(ERROR_SUCCESS);
4710 return TRUE;
4714 /******************************************************************
4715 * EnumPrintersW [WINSPOOL.@]
4717 * Enumerates the available printers, print servers and print
4718 * providers, depending on the specified flags, name and level.
4720 * RETURNS:
4722 * If level is set to 1:
4723 * Returns an array of PRINTER_INFO_1 data structures in the
4724 * lpbPrinters buffer.
4726 * If level is set to 2:
4727 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4728 * Returns an array of PRINTER_INFO_2 data structures in the
4729 * lpbPrinters buffer. Note that according to MSDN also an
4730 * OpenPrinter should be performed on every remote printer.
4732 * If level is set to 4 (officially WinNT only):
4733 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4734 * Fast: Only the registry is queried to retrieve printer names,
4735 * no connection to the driver is made.
4736 * Returns an array of PRINTER_INFO_4 data structures in the
4737 * lpbPrinters buffer.
4739 * If level is set to 5 (officially WinNT4/Win9x only):
4740 * Fast: Only the registry is queried to retrieve printer names,
4741 * no connection to the driver is made.
4742 * Returns an array of PRINTER_INFO_5 data structures in the
4743 * lpbPrinters buffer.
4745 * If level set to 3 or 6+:
4746 * returns zero (failure!)
4748 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4749 * for information.
4751 * BUGS:
4752 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4753 * - Only levels 2, 4 and 5 are implemented at the moment.
4754 * - 16-bit printer drivers are not enumerated.
4755 * - Returned amount of bytes used/needed does not match the real Windoze
4756 * implementation (as in this implementation, all strings are part
4757 * of the buffer, whereas Win32 keeps them somewhere else)
4758 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4760 * NOTE:
4761 * - In a regular Wine installation, no registry settings for printers
4762 * exist, which makes this function return an empty list.
4764 BOOL WINAPI EnumPrintersW(
4765 DWORD dwType, /* [in] Types of print objects to enumerate */
4766 LPWSTR lpszName, /* [in] name of objects to enumerate */
4767 DWORD dwLevel, /* [in] type of printer info structure */
4768 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4769 DWORD cbBuf, /* [in] max size of buffer in bytes */
4770 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4771 LPDWORD lpdwReturned /* [out] number of entries returned */
4774 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4775 lpdwNeeded, lpdwReturned);
4778 /******************************************************************
4779 * EnumPrintersA [WINSPOOL.@]
4781 * See EnumPrintersW
4784 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4785 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4787 BOOL ret;
4788 UNICODE_STRING pNameU;
4789 LPWSTR pNameW;
4790 LPBYTE pPrintersW;
4792 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4793 pPrinters, cbBuf, pcbNeeded, pcReturned);
4795 pNameW = asciitounicode(&pNameU, pName);
4797 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4798 MS Office need this */
4799 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4801 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4803 RtlFreeUnicodeString(&pNameU);
4804 if (ret) {
4805 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4807 HeapFree(GetProcessHeap(), 0, pPrintersW);
4808 return ret;
4811 /*****************************************************************************
4812 * WINSPOOL_GetDriverInfoFromReg [internal]
4814 * Enters the information from the registry into the DRIVER_INFO struct
4816 * RETURNS
4817 * zero if the printer driver does not exist in the registry
4818 * (only if Level > 1) otherwise nonzero
4820 static BOOL WINSPOOL_GetDriverInfoFromReg(
4821 HKEY hkeyDrivers,
4822 LPWSTR DriverName,
4823 const printenv_t * env,
4824 DWORD Level,
4825 LPBYTE ptr, /* DRIVER_INFO */
4826 LPBYTE pDriverStrings, /* strings buffer */
4827 DWORD cbBuf, /* size of string buffer */
4828 LPDWORD pcbNeeded) /* space needed for str. */
4830 DWORD size, tmp;
4831 HKEY hkeyDriver;
4832 WCHAR driverdir[MAX_PATH];
4833 DWORD dirlen;
4834 LPBYTE strPtr = pDriverStrings;
4835 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4837 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4838 debugstr_w(DriverName), env,
4839 Level, di, pDriverStrings, cbBuf);
4841 if (di) ZeroMemory(di, di_sizeof[Level]);
4843 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4844 if (*pcbNeeded <= cbBuf)
4845 strcpyW((LPWSTR)strPtr, DriverName);
4847 /* pName for level 1 has a different offset! */
4848 if (Level == 1) {
4849 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4850 return TRUE;
4853 /* .cVersion and .pName for level > 1 */
4854 if (di) {
4855 di->cVersion = env->driverversion;
4856 di->pName = (LPWSTR) strPtr;
4857 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4860 /* Reserve Space for the largest subdir and a Backslash*/
4861 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4862 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4863 /* Should never Fail */
4864 return FALSE;
4866 lstrcatW(driverdir, env->versionsubdir);
4867 lstrcatW(driverdir, backslashW);
4869 /* dirlen must not include the terminating zero */
4870 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4872 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4873 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4874 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4875 return FALSE;
4878 /* pEnvironment */
4879 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4881 *pcbNeeded += size;
4882 if (*pcbNeeded <= cbBuf) {
4883 lstrcpyW((LPWSTR)strPtr, env->envname);
4884 if (di) di->pEnvironment = (LPWSTR)strPtr;
4885 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4888 /* .pDriverPath is the Graphics rendering engine.
4889 The full Path is required to avoid a crash in some apps */
4890 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4891 *pcbNeeded += size;
4892 if (*pcbNeeded <= cbBuf)
4893 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4895 if (di) di->pDriverPath = (LPWSTR)strPtr;
4896 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4899 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4900 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4901 *pcbNeeded += size;
4902 if (*pcbNeeded <= cbBuf)
4903 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4905 if (di) di->pDataFile = (LPWSTR)strPtr;
4906 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4909 /* .pConfigFile is the Driver user Interface */
4910 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4911 *pcbNeeded += size;
4912 if (*pcbNeeded <= cbBuf)
4913 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4915 if (di) di->pConfigFile = (LPWSTR)strPtr;
4916 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4919 if (Level == 2 ) {
4920 RegCloseKey(hkeyDriver);
4921 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4922 return TRUE;
4925 if (Level == 5 ) {
4926 RegCloseKey(hkeyDriver);
4927 FIXME("level 5: incomplete\n");
4928 return TRUE;
4931 /* .pHelpFile */
4932 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4933 *pcbNeeded += size;
4934 if (*pcbNeeded <= cbBuf)
4935 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4937 if (di) di->pHelpFile = (LPWSTR)strPtr;
4938 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4941 /* .pDependentFiles */
4942 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4943 *pcbNeeded += size;
4944 if (*pcbNeeded <= cbBuf)
4945 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4947 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4948 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4950 else if (GetVersion() & 0x80000000) {
4951 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4952 size = 2 * sizeof(WCHAR);
4953 *pcbNeeded += size;
4954 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4956 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4957 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4960 /* .pMonitorName is the optional Language Monitor */
4961 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4962 *pcbNeeded += size;
4963 if (*pcbNeeded <= cbBuf)
4964 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4966 if (di) di->pMonitorName = (LPWSTR)strPtr;
4967 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4970 /* .pDefaultDataType */
4971 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4972 *pcbNeeded += size;
4973 if(*pcbNeeded <= cbBuf)
4974 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4976 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4977 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4980 if (Level == 3 ) {
4981 RegCloseKey(hkeyDriver);
4982 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4983 return TRUE;
4986 /* .pszzPreviousNames */
4987 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4988 *pcbNeeded += size;
4989 if(*pcbNeeded <= cbBuf)
4990 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4992 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4993 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4996 if (Level == 4 ) {
4997 RegCloseKey(hkeyDriver);
4998 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4999 return TRUE;
5002 /* support is missing, but not important enough for a FIXME */
5003 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5005 /* .pszMfgName */
5006 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5007 *pcbNeeded += size;
5008 if(*pcbNeeded <= cbBuf)
5009 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5011 if (di) di->pszMfgName = (LPWSTR)strPtr;
5012 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5015 /* .pszOEMUrl */
5016 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5017 *pcbNeeded += size;
5018 if(*pcbNeeded <= cbBuf)
5019 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5021 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5022 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5025 /* .pszHardwareID */
5026 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5027 *pcbNeeded += size;
5028 if(*pcbNeeded <= cbBuf)
5029 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5031 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5032 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5035 /* .pszProvider */
5036 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5037 *pcbNeeded += size;
5038 if(*pcbNeeded <= cbBuf)
5039 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5041 if (di) di->pszProvider = (LPWSTR)strPtr;
5042 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5045 if (Level == 6 ) {
5046 RegCloseKey(hkeyDriver);
5047 return TRUE;
5050 /* support is missing, but not important enough for a FIXME */
5051 TRACE("level 8: incomplete\n");
5053 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5054 RegCloseKey(hkeyDriver);
5055 return TRUE;
5058 /*****************************************************************************
5059 * GetPrinterDriverW [WINSPOOL.@]
5061 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5062 DWORD Level, LPBYTE pDriverInfo,
5063 DWORD cbBuf, LPDWORD pcbNeeded)
5065 LPCWSTR name;
5066 WCHAR DriverName[100];
5067 DWORD ret, type, size, needed = 0;
5068 LPBYTE ptr = NULL;
5069 HKEY hkeyPrinter, hkeyDrivers;
5070 const printenv_t * env;
5072 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5073 Level,pDriverInfo,cbBuf, pcbNeeded);
5075 if (cbBuf > 0)
5076 ZeroMemory(pDriverInfo, cbBuf);
5078 if (!(name = get_opened_printer_name(hPrinter))) {
5079 SetLastError(ERROR_INVALID_HANDLE);
5080 return FALSE;
5083 if (Level < 1 || Level == 7 || Level > 8) {
5084 SetLastError(ERROR_INVALID_LEVEL);
5085 return FALSE;
5088 env = validate_envW(pEnvironment);
5089 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5091 ret = open_printer_reg_key( name, &hkeyPrinter );
5092 if (ret)
5094 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5095 SetLastError( ret );
5096 return FALSE;
5099 size = sizeof(DriverName);
5100 DriverName[0] = 0;
5101 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5102 (LPBYTE)DriverName, &size);
5103 RegCloseKey(hkeyPrinter);
5104 if(ret != ERROR_SUCCESS) {
5105 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5106 return FALSE;
5109 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5110 if(!hkeyDrivers) {
5111 ERR("Can't create Drivers key\n");
5112 return FALSE;
5115 size = di_sizeof[Level];
5116 if ((size <= cbBuf) && pDriverInfo)
5117 ptr = pDriverInfo + size;
5119 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5120 env, Level, pDriverInfo, ptr,
5121 (cbBuf < size) ? 0 : cbBuf - size,
5122 &needed)) {
5123 RegCloseKey(hkeyDrivers);
5124 return FALSE;
5127 RegCloseKey(hkeyDrivers);
5129 if(pcbNeeded) *pcbNeeded = size + needed;
5130 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5131 if(cbBuf >= size + needed) return TRUE;
5132 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5133 return FALSE;
5136 /*****************************************************************************
5137 * GetPrinterDriverA [WINSPOOL.@]
5139 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5140 DWORD Level, LPBYTE pDriverInfo,
5141 DWORD cbBuf, LPDWORD pcbNeeded)
5143 BOOL ret;
5144 UNICODE_STRING pEnvW;
5145 PWSTR pwstrEnvW;
5146 LPBYTE buf = NULL;
5148 if (cbBuf)
5150 ZeroMemory(pDriverInfo, cbBuf);
5151 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5154 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5155 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5156 cbBuf, pcbNeeded);
5157 if (ret)
5158 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5160 HeapFree(GetProcessHeap(), 0, buf);
5162 RtlFreeUnicodeString(&pEnvW);
5163 return ret;
5166 /*****************************************************************************
5167 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5169 * Return the PATH for the Printer-Drivers (UNICODE)
5171 * PARAMS
5172 * pName [I] Servername (NT only) or NULL (local Computer)
5173 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5174 * Level [I] Structure-Level (must be 1)
5175 * pDriverDirectory [O] PTR to Buffer that receives the Result
5176 * cbBuf [I] Size of Buffer at pDriverDirectory
5177 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5178 * required for pDriverDirectory
5180 * RETURNS
5181 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5182 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5183 * if cbBuf is too small
5185 * Native Values returned in pDriverDirectory on Success:
5186 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5187 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5188 *| win9x(Windows 4.0): "%winsysdir%"
5190 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5192 * FIXME
5193 *- Only NULL or "" is supported for pName
5196 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5197 DWORD Level, LPBYTE pDriverDirectory,
5198 DWORD cbBuf, LPDWORD pcbNeeded)
5200 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5201 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5203 if ((backend == NULL) && !load_backend()) return FALSE;
5205 if (Level != 1) {
5206 /* (Level != 1) is ignored in win9x */
5207 SetLastError(ERROR_INVALID_LEVEL);
5208 return FALSE;
5210 if (pcbNeeded == NULL) {
5211 /* (pcbNeeded == NULL) is ignored in win9x */
5212 SetLastError(RPC_X_NULL_REF_POINTER);
5213 return FALSE;
5216 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5217 pDriverDirectory, cbBuf, pcbNeeded);
5222 /*****************************************************************************
5223 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5225 * Return the PATH for the Printer-Drivers (ANSI)
5227 * See GetPrinterDriverDirectoryW.
5229 * NOTES
5230 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5233 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5234 DWORD Level, LPBYTE pDriverDirectory,
5235 DWORD cbBuf, LPDWORD pcbNeeded)
5237 UNICODE_STRING nameW, environmentW;
5238 BOOL ret;
5239 DWORD pcbNeededW;
5240 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5241 WCHAR *driverDirectoryW = NULL;
5243 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5244 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5246 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5248 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5249 else nameW.Buffer = NULL;
5250 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5251 else environmentW.Buffer = NULL;
5253 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5254 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5255 if (ret) {
5256 DWORD needed;
5257 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5258 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5259 if(pcbNeeded)
5260 *pcbNeeded = needed;
5261 ret = (needed <= cbBuf) ? TRUE : FALSE;
5262 } else
5263 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5265 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5267 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5268 RtlFreeUnicodeString(&environmentW);
5269 RtlFreeUnicodeString(&nameW);
5271 return ret;
5274 /*****************************************************************************
5275 * AddPrinterDriverA [WINSPOOL.@]
5277 * See AddPrinterDriverW.
5280 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5282 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5283 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5286 /******************************************************************************
5287 * AddPrinterDriverW (WINSPOOL.@)
5289 * Install a Printer Driver
5291 * PARAMS
5292 * pName [I] Servername or NULL (local Computer)
5293 * level [I] Level for the supplied DRIVER_INFO_*W struct
5294 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5296 * RESULTS
5297 * Success: TRUE
5298 * Failure: FALSE
5301 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5303 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5304 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5307 /*****************************************************************************
5308 * AddPrintProcessorA [WINSPOOL.@]
5310 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5311 LPSTR pPrintProcessorName)
5313 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5314 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5315 return FALSE;
5318 /*****************************************************************************
5319 * AddPrintProcessorW [WINSPOOL.@]
5321 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5322 LPWSTR pPrintProcessorName)
5324 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5325 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5326 return TRUE;
5329 /*****************************************************************************
5330 * AddPrintProvidorA [WINSPOOL.@]
5332 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5334 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5335 return FALSE;
5338 /*****************************************************************************
5339 * AddPrintProvidorW [WINSPOOL.@]
5341 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5343 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5344 return FALSE;
5347 /*****************************************************************************
5348 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5350 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5351 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5353 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5354 pDevModeOutput, pDevModeInput);
5355 return 0;
5358 /*****************************************************************************
5359 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5361 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5362 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5364 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5365 pDevModeOutput, pDevModeInput);
5366 return 0;
5369 /*****************************************************************************
5370 * PrinterProperties [WINSPOOL.@]
5372 * Displays a dialog to set the properties of the printer.
5374 * RETURNS
5375 * nonzero on success or zero on failure
5377 * BUGS
5378 * implemented as stub only
5380 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5381 HANDLE hPrinter /* [in] handle to printer object */
5383 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5384 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5385 return FALSE;
5388 /*****************************************************************************
5389 * EnumJobsA [WINSPOOL.@]
5392 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5393 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5394 LPDWORD pcReturned)
5396 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5397 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5399 if(pcbNeeded) *pcbNeeded = 0;
5400 if(pcReturned) *pcReturned = 0;
5401 return FALSE;
5405 /*****************************************************************************
5406 * EnumJobsW [WINSPOOL.@]
5409 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5410 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5411 LPDWORD pcReturned)
5413 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5414 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5416 if(pcbNeeded) *pcbNeeded = 0;
5417 if(pcReturned) *pcReturned = 0;
5418 return FALSE;
5421 /*****************************************************************************
5422 * WINSPOOL_EnumPrinterDrivers [internal]
5424 * Delivers information about all printer drivers installed on the
5425 * localhost or a given server
5427 * RETURNS
5428 * nonzero on success or zero on failure. If the buffer for the returned
5429 * information is too small the function will return an error
5431 * BUGS
5432 * - only implemented for localhost, foreign hosts will return an error
5434 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5435 DWORD Level, LPBYTE pDriverInfo,
5436 DWORD driver_index,
5437 DWORD cbBuf, LPDWORD pcbNeeded,
5438 LPDWORD pcFound, DWORD data_offset)
5440 { HKEY hkeyDrivers;
5441 DWORD i, size = 0;
5442 const printenv_t * env;
5444 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5445 debugstr_w(pName), debugstr_w(pEnvironment),
5446 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5448 env = validate_envW(pEnvironment);
5449 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5451 *pcFound = 0;
5453 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5454 if(!hkeyDrivers) {
5455 ERR("Can't open Drivers key\n");
5456 return FALSE;
5459 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5460 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5461 RegCloseKey(hkeyDrivers);
5462 ERR("Can't query Drivers key\n");
5463 return FALSE;
5465 TRACE("Found %d Drivers\n", *pcFound);
5467 /* get size of single struct
5468 * unicode and ascii structure have the same size
5470 size = di_sizeof[Level];
5472 if (data_offset == 0)
5473 data_offset = size * (*pcFound);
5474 *pcbNeeded = data_offset;
5476 for( i = 0; i < *pcFound; i++) {
5477 WCHAR DriverNameW[255];
5478 PBYTE table_ptr = NULL;
5479 PBYTE data_ptr = NULL;
5480 DWORD needed = 0;
5482 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5483 != ERROR_SUCCESS) {
5484 ERR("Can't enum key number %d\n", i);
5485 RegCloseKey(hkeyDrivers);
5486 return FALSE;
5489 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5490 table_ptr = pDriverInfo + (driver_index + i) * size;
5491 if (pDriverInfo && *pcbNeeded <= cbBuf)
5492 data_ptr = pDriverInfo + *pcbNeeded;
5494 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5495 env, Level, table_ptr, data_ptr,
5496 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5497 &needed)) {
5498 RegCloseKey(hkeyDrivers);
5499 return FALSE;
5502 *pcbNeeded += needed;
5505 RegCloseKey(hkeyDrivers);
5507 if(cbBuf < *pcbNeeded){
5508 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5509 return FALSE;
5512 return TRUE;
5515 /*****************************************************************************
5516 * EnumPrinterDriversW [WINSPOOL.@]
5518 * see function EnumPrinterDrivers for RETURNS, BUGS
5520 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5521 LPBYTE pDriverInfo, DWORD cbBuf,
5522 LPDWORD pcbNeeded, LPDWORD pcReturned)
5524 static const WCHAR allW[] = {'a','l','l',0};
5525 BOOL ret;
5526 DWORD found;
5528 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5530 SetLastError(RPC_X_NULL_REF_POINTER);
5531 return FALSE;
5534 /* check for local drivers */
5535 if((pName) && (pName[0])) {
5536 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5537 SetLastError(ERROR_ACCESS_DENIED);
5538 return FALSE;
5541 /* check input parameter */
5542 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5543 SetLastError(ERROR_INVALID_LEVEL);
5544 return FALSE;
5547 if(pDriverInfo && cbBuf > 0)
5548 memset( pDriverInfo, 0, cbBuf);
5550 /* Exception: pull all printers */
5551 if (pEnvironment && !strcmpW(pEnvironment, allW))
5553 DWORD i, needed, bufsize = cbBuf;
5554 DWORD total_needed = 0;
5555 DWORD total_found = 0;
5556 DWORD data_offset;
5558 /* Precompute the overall total; we need this to know
5559 where pointers end and data begins (i.e. data_offset) */
5560 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5562 needed = found = 0;
5563 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5564 NULL, 0, 0, &needed, &found, 0);
5565 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5566 total_needed += needed;
5567 total_found += found;
5570 data_offset = di_sizeof[Level] * total_found;
5572 *pcReturned = 0;
5573 *pcbNeeded = 0;
5574 total_found = 0;
5575 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5577 needed = found = 0;
5578 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5579 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5580 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5581 else if (ret)
5582 *pcReturned += found;
5583 *pcbNeeded = needed;
5584 data_offset = needed;
5585 total_found += found;
5587 return ret;
5590 /* Normal behavior */
5591 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5592 0, cbBuf, pcbNeeded, &found, 0);
5593 if (ret)
5594 *pcReturned = found;
5596 return ret;
5599 /*****************************************************************************
5600 * EnumPrinterDriversA [WINSPOOL.@]
5602 * see function EnumPrinterDrivers for RETURNS, BUGS
5604 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5605 LPBYTE pDriverInfo, DWORD cbBuf,
5606 LPDWORD pcbNeeded, LPDWORD pcReturned)
5608 BOOL ret;
5609 UNICODE_STRING pNameW, pEnvironmentW;
5610 PWSTR pwstrNameW, pwstrEnvironmentW;
5611 LPBYTE buf = NULL;
5613 if (cbBuf)
5614 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5616 pwstrNameW = asciitounicode(&pNameW, pName);
5617 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5619 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5620 buf, cbBuf, pcbNeeded, pcReturned);
5621 if (ret)
5622 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5624 HeapFree(GetProcessHeap(), 0, buf);
5626 RtlFreeUnicodeString(&pNameW);
5627 RtlFreeUnicodeString(&pEnvironmentW);
5629 return ret;
5632 /******************************************************************************
5633 * EnumPortsA (WINSPOOL.@)
5635 * See EnumPortsW.
5638 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5639 LPDWORD pcbNeeded, LPDWORD pcReturned)
5641 BOOL res;
5642 LPBYTE bufferW = NULL;
5643 LPWSTR nameW = NULL;
5644 DWORD needed = 0;
5645 DWORD numentries = 0;
5646 INT len;
5648 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5649 cbBuf, pcbNeeded, pcReturned);
5651 /* convert servername to unicode */
5652 if (pName) {
5653 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5654 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5655 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5657 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5658 needed = cbBuf * sizeof(WCHAR);
5659 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5660 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5662 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5663 if (pcbNeeded) needed = *pcbNeeded;
5664 /* HeapReAlloc return NULL, when bufferW was NULL */
5665 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5666 HeapAlloc(GetProcessHeap(), 0, needed);
5668 /* Try again with the large Buffer */
5669 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5671 needed = pcbNeeded ? *pcbNeeded : 0;
5672 numentries = pcReturned ? *pcReturned : 0;
5675 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5676 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5678 if (res) {
5679 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5680 DWORD entrysize = 0;
5681 DWORD index;
5682 LPSTR ptr;
5683 LPPORT_INFO_2W pi2w;
5684 LPPORT_INFO_2A pi2a;
5686 needed = 0;
5687 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5689 /* First pass: calculate the size for all Entries */
5690 pi2w = (LPPORT_INFO_2W) bufferW;
5691 pi2a = (LPPORT_INFO_2A) pPorts;
5692 index = 0;
5693 while (index < numentries) {
5694 index++;
5695 needed += entrysize; /* PORT_INFO_?A */
5696 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5698 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5699 NULL, 0, NULL, NULL);
5700 if (Level > 1) {
5701 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5702 NULL, 0, NULL, NULL);
5703 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5704 NULL, 0, NULL, NULL);
5706 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5707 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5708 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5711 /* check for errors and quit on failure */
5712 if (cbBuf < needed) {
5713 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5714 res = FALSE;
5715 goto cleanup;
5717 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5718 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5719 cbBuf -= len ; /* free Bytes in the user-Buffer */
5720 pi2w = (LPPORT_INFO_2W) bufferW;
5721 pi2a = (LPPORT_INFO_2A) pPorts;
5722 index = 0;
5723 /* Second Pass: Fill the User Buffer (if we have one) */
5724 while ((index < numentries) && pPorts) {
5725 index++;
5726 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5727 pi2a->pPortName = ptr;
5728 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5729 ptr, cbBuf , NULL, NULL);
5730 ptr += len;
5731 cbBuf -= len;
5732 if (Level > 1) {
5733 pi2a->pMonitorName = ptr;
5734 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5735 ptr, cbBuf, NULL, NULL);
5736 ptr += len;
5737 cbBuf -= len;
5739 pi2a->pDescription = ptr;
5740 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5741 ptr, cbBuf, NULL, NULL);
5742 ptr += len;
5743 cbBuf -= len;
5745 pi2a->fPortType = pi2w->fPortType;
5746 pi2a->Reserved = 0; /* documented: "must be zero" */
5749 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5750 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5751 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5755 cleanup:
5756 if (pcbNeeded) *pcbNeeded = needed;
5757 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5759 HeapFree(GetProcessHeap(), 0, nameW);
5760 HeapFree(GetProcessHeap(), 0, bufferW);
5762 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5763 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5765 return (res);
5769 /******************************************************************************
5770 * EnumPortsW (WINSPOOL.@)
5772 * Enumerate available Ports
5774 * PARAMS
5775 * pName [I] Servername or NULL (local Computer)
5776 * Level [I] Structure-Level (1 or 2)
5777 * pPorts [O] PTR to Buffer that receives the Result
5778 * cbBuf [I] Size of Buffer at pPorts
5779 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5780 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5782 * RETURNS
5783 * Success: TRUE
5784 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5787 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5790 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5791 cbBuf, pcbNeeded, pcReturned);
5793 if ((backend == NULL) && !load_backend()) return FALSE;
5795 /* Level is not checked in win9x */
5796 if (!Level || (Level > 2)) {
5797 WARN("level (%d) is ignored in win9x\n", Level);
5798 SetLastError(ERROR_INVALID_LEVEL);
5799 return FALSE;
5801 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5802 SetLastError(RPC_X_NULL_REF_POINTER);
5803 return FALSE;
5806 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5809 /******************************************************************************
5810 * GetDefaultPrinterW (WINSPOOL.@)
5812 * FIXME
5813 * This function must read the value from data 'device' of key
5814 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5816 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5818 BOOL retval = TRUE;
5819 DWORD insize, len;
5820 WCHAR *buffer, *ptr;
5822 if (!namesize)
5824 SetLastError(ERROR_INVALID_PARAMETER);
5825 return FALSE;
5828 /* make the buffer big enough for the stuff from the profile/registry,
5829 * the content must fit into the local buffer to compute the correct
5830 * size even if the extern buffer is too small or not given.
5831 * (20 for ,driver,port) */
5832 insize = *namesize;
5833 len = max(100, (insize + 20));
5834 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5836 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5838 SetLastError (ERROR_FILE_NOT_FOUND);
5839 retval = FALSE;
5840 goto end;
5842 TRACE("%s\n", debugstr_w(buffer));
5844 if ((ptr = strchrW(buffer, ',')) == NULL)
5846 SetLastError(ERROR_INVALID_NAME);
5847 retval = FALSE;
5848 goto end;
5851 *ptr = 0;
5852 *namesize = strlenW(buffer) + 1;
5853 if(!name || (*namesize > insize))
5855 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5856 retval = FALSE;
5857 goto end;
5859 strcpyW(name, buffer);
5861 end:
5862 HeapFree( GetProcessHeap(), 0, buffer);
5863 return retval;
5867 /******************************************************************************
5868 * GetDefaultPrinterA (WINSPOOL.@)
5870 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5872 BOOL retval = TRUE;
5873 DWORD insize = 0;
5874 WCHAR *bufferW = NULL;
5876 if (!namesize)
5878 SetLastError(ERROR_INVALID_PARAMETER);
5879 return FALSE;
5882 if(name && *namesize) {
5883 insize = *namesize;
5884 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5887 if(!GetDefaultPrinterW( bufferW, namesize)) {
5888 retval = FALSE;
5889 goto end;
5892 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5893 NULL, NULL);
5894 if (!*namesize)
5896 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5897 retval = FALSE;
5899 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5901 end:
5902 HeapFree( GetProcessHeap(), 0, bufferW);
5903 return retval;
5907 /******************************************************************************
5908 * SetDefaultPrinterW (WINSPOOL.204)
5910 * Set the Name of the Default Printer
5912 * PARAMS
5913 * pszPrinter [I] Name of the Printer or NULL
5915 * RETURNS
5916 * Success: True
5917 * Failure: FALSE
5919 * NOTES
5920 * When the Parameter is NULL or points to an Empty String and
5921 * a Default Printer was already present, then this Function changes nothing.
5922 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5923 * the First enumerated local Printer is used.
5926 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5928 WCHAR default_printer[MAX_PATH];
5929 LPWSTR buffer = NULL;
5930 HKEY hreg;
5931 DWORD size;
5932 DWORD namelen;
5933 LONG lres;
5935 TRACE("(%s)\n", debugstr_w(pszPrinter));
5936 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5938 default_printer[0] = '\0';
5939 size = sizeof(default_printer)/sizeof(WCHAR);
5941 /* if we have a default Printer, do nothing. */
5942 if (GetDefaultPrinterW(default_printer, &size))
5943 return TRUE;
5945 pszPrinter = NULL;
5946 /* we have no default Printer: search local Printers and use the first */
5947 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5949 default_printer[0] = '\0';
5950 size = sizeof(default_printer)/sizeof(WCHAR);
5951 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5953 pszPrinter = default_printer;
5954 TRACE("using %s\n", debugstr_w(pszPrinter));
5956 RegCloseKey(hreg);
5959 if (pszPrinter == NULL) {
5960 TRACE("no local printer found\n");
5961 SetLastError(ERROR_FILE_NOT_FOUND);
5962 return FALSE;
5966 /* "pszPrinter" is never empty or NULL here. */
5967 namelen = lstrlenW(pszPrinter);
5968 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5969 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5970 if (!buffer ||
5971 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5972 HeapFree(GetProcessHeap(), 0, buffer);
5973 SetLastError(ERROR_FILE_NOT_FOUND);
5974 return FALSE;
5977 /* read the devices entry for the printer (driver,port) to build the string for the
5978 default device entry (printer,driver,port) */
5979 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5980 buffer[namelen] = ',';
5981 namelen++; /* move index to the start of the driver */
5983 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5984 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5985 if (!lres) {
5986 TRACE("set device to %s\n", debugstr_w(buffer));
5988 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5989 TRACE("failed to set the device entry: %d\n", GetLastError());
5990 lres = ERROR_INVALID_PRINTER_NAME;
5993 /* remove the next section, when INIFileMapping is implemented */
5995 HKEY hdev;
5996 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5997 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5998 RegCloseKey(hdev);
6002 else
6004 if (lres != ERROR_FILE_NOT_FOUND)
6005 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6007 SetLastError(ERROR_INVALID_PRINTER_NAME);
6010 RegCloseKey(hreg);
6011 HeapFree(GetProcessHeap(), 0, buffer);
6012 return (lres == ERROR_SUCCESS);
6015 /******************************************************************************
6016 * SetDefaultPrinterA (WINSPOOL.202)
6018 * See SetDefaultPrinterW.
6021 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6023 LPWSTR bufferW = NULL;
6024 BOOL res;
6026 TRACE("(%s)\n", debugstr_a(pszPrinter));
6027 if(pszPrinter) {
6028 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6029 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6030 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6032 res = SetDefaultPrinterW(bufferW);
6033 HeapFree(GetProcessHeap(), 0, bufferW);
6034 return res;
6037 /******************************************************************************
6038 * SetPrinterDataExA (WINSPOOL.@)
6040 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6041 LPCSTR pValueName, DWORD Type,
6042 LPBYTE pData, DWORD cbData)
6044 HKEY hkeyPrinter, hkeySubkey;
6045 DWORD ret;
6047 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6048 debugstr_a(pValueName), Type, pData, cbData);
6050 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6051 != ERROR_SUCCESS)
6052 return ret;
6054 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6055 != ERROR_SUCCESS) {
6056 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6057 RegCloseKey(hkeyPrinter);
6058 return ret;
6060 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6061 RegCloseKey(hkeySubkey);
6062 RegCloseKey(hkeyPrinter);
6063 return ret;
6066 /******************************************************************************
6067 * SetPrinterDataExW (WINSPOOL.@)
6069 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6070 LPCWSTR pValueName, DWORD Type,
6071 LPBYTE pData, DWORD cbData)
6073 HKEY hkeyPrinter, hkeySubkey;
6074 DWORD ret;
6076 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6077 debugstr_w(pValueName), Type, pData, cbData);
6079 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6080 != ERROR_SUCCESS)
6081 return ret;
6083 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6084 != ERROR_SUCCESS) {
6085 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6086 RegCloseKey(hkeyPrinter);
6087 return ret;
6089 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6090 RegCloseKey(hkeySubkey);
6091 RegCloseKey(hkeyPrinter);
6092 return ret;
6095 /******************************************************************************
6096 * SetPrinterDataA (WINSPOOL.@)
6098 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6099 LPBYTE pData, DWORD cbData)
6101 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6102 pData, cbData);
6105 /******************************************************************************
6106 * SetPrinterDataW (WINSPOOL.@)
6108 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6109 LPBYTE pData, DWORD cbData)
6111 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6112 pData, cbData);
6115 /******************************************************************************
6116 * GetPrinterDataExA (WINSPOOL.@)
6118 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6119 LPCSTR pValueName, LPDWORD pType,
6120 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6122 opened_printer_t *printer;
6123 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6124 DWORD ret;
6126 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6127 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6129 printer = get_opened_printer(hPrinter);
6130 if(!printer) return ERROR_INVALID_HANDLE;
6132 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6133 if (ret) return ret;
6135 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6137 if (printer->name) {
6139 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6140 if (ret) {
6141 RegCloseKey(hkeyPrinters);
6142 return ret;
6144 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6145 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6146 RegCloseKey(hkeyPrinter);
6147 RegCloseKey(hkeyPrinters);
6148 return ret;
6151 *pcbNeeded = nSize;
6152 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6153 0, pType, pData, pcbNeeded);
6155 if (!ret && !pData) ret = ERROR_MORE_DATA;
6157 RegCloseKey(hkeySubkey);
6158 RegCloseKey(hkeyPrinter);
6159 RegCloseKey(hkeyPrinters);
6161 TRACE("--> %d\n", ret);
6162 return ret;
6165 /******************************************************************************
6166 * GetPrinterDataExW (WINSPOOL.@)
6168 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6169 LPCWSTR pValueName, LPDWORD pType,
6170 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6172 opened_printer_t *printer;
6173 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6174 DWORD ret;
6176 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6177 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6179 printer = get_opened_printer(hPrinter);
6180 if(!printer) return ERROR_INVALID_HANDLE;
6182 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6183 if (ret) return ret;
6185 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6187 if (printer->name) {
6189 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6190 if (ret) {
6191 RegCloseKey(hkeyPrinters);
6192 return ret;
6194 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6195 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6196 RegCloseKey(hkeyPrinter);
6197 RegCloseKey(hkeyPrinters);
6198 return ret;
6201 *pcbNeeded = nSize;
6202 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6203 0, pType, pData, pcbNeeded);
6205 if (!ret && !pData) ret = ERROR_MORE_DATA;
6207 RegCloseKey(hkeySubkey);
6208 RegCloseKey(hkeyPrinter);
6209 RegCloseKey(hkeyPrinters);
6211 TRACE("--> %d\n", ret);
6212 return ret;
6215 /******************************************************************************
6216 * GetPrinterDataA (WINSPOOL.@)
6218 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6219 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6221 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6222 pData, nSize, pcbNeeded);
6225 /******************************************************************************
6226 * GetPrinterDataW (WINSPOOL.@)
6228 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6229 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6231 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6232 pData, nSize, pcbNeeded);
6235 /*******************************************************************************
6236 * EnumPrinterDataExW [WINSPOOL.@]
6238 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6239 LPBYTE pEnumValues, DWORD cbEnumValues,
6240 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6242 HKEY hkPrinter, hkSubKey;
6243 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6244 cbValueNameLen, cbMaxValueLen, cbValueLen,
6245 cbBufSize, dwType;
6246 LPWSTR lpValueName;
6247 HANDLE hHeap;
6248 PBYTE lpValue;
6249 PPRINTER_ENUM_VALUESW ppev;
6251 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6253 if (pKeyName == NULL || *pKeyName == 0)
6254 return ERROR_INVALID_PARAMETER;
6256 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6257 if (ret != ERROR_SUCCESS)
6259 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6260 hPrinter, ret);
6261 return ret;
6264 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6265 if (ret != ERROR_SUCCESS)
6267 r = RegCloseKey (hkPrinter);
6268 if (r != ERROR_SUCCESS)
6269 WARN ("RegCloseKey returned %i\n", r);
6270 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6271 debugstr_w (pKeyName), ret);
6272 return ret;
6275 ret = RegCloseKey (hkPrinter);
6276 if (ret != ERROR_SUCCESS)
6278 ERR ("RegCloseKey returned %i\n", ret);
6279 r = RegCloseKey (hkSubKey);
6280 if (r != ERROR_SUCCESS)
6281 WARN ("RegCloseKey returned %i\n", r);
6282 return ret;
6285 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6286 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6287 if (ret != ERROR_SUCCESS)
6289 r = RegCloseKey (hkSubKey);
6290 if (r != ERROR_SUCCESS)
6291 WARN ("RegCloseKey returned %i\n", r);
6292 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6293 return ret;
6296 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6297 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6299 if (cValues == 0) /* empty key */
6301 r = RegCloseKey (hkSubKey);
6302 if (r != ERROR_SUCCESS)
6303 WARN ("RegCloseKey returned %i\n", r);
6304 *pcbEnumValues = *pnEnumValues = 0;
6305 return ERROR_SUCCESS;
6308 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6310 hHeap = GetProcessHeap ();
6311 if (hHeap == NULL)
6313 ERR ("GetProcessHeap failed\n");
6314 r = RegCloseKey (hkSubKey);
6315 if (r != ERROR_SUCCESS)
6316 WARN ("RegCloseKey returned %i\n", r);
6317 return ERROR_OUTOFMEMORY;
6320 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6321 if (lpValueName == NULL)
6323 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6324 r = RegCloseKey (hkSubKey);
6325 if (r != ERROR_SUCCESS)
6326 WARN ("RegCloseKey returned %i\n", r);
6327 return ERROR_OUTOFMEMORY;
6330 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6331 if (lpValue == NULL)
6333 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6334 if (HeapFree (hHeap, 0, lpValueName) == 0)
6335 WARN ("HeapFree failed with code %i\n", GetLastError ());
6336 r = RegCloseKey (hkSubKey);
6337 if (r != ERROR_SUCCESS)
6338 WARN ("RegCloseKey returned %i\n", r);
6339 return ERROR_OUTOFMEMORY;
6342 TRACE ("pass 1: calculating buffer required for all names and values\n");
6344 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6346 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6348 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6350 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6351 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6352 NULL, NULL, lpValue, &cbValueLen);
6353 if (ret != ERROR_SUCCESS)
6355 if (HeapFree (hHeap, 0, lpValue) == 0)
6356 WARN ("HeapFree failed with code %i\n", GetLastError ());
6357 if (HeapFree (hHeap, 0, lpValueName) == 0)
6358 WARN ("HeapFree failed with code %i\n", GetLastError ());
6359 r = RegCloseKey (hkSubKey);
6360 if (r != ERROR_SUCCESS)
6361 WARN ("RegCloseKey returned %i\n", r);
6362 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6363 return ret;
6366 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6367 debugstr_w (lpValueName), dwIndex,
6368 cbValueNameLen + 1, cbValueLen);
6370 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6371 cbBufSize += cbValueLen;
6374 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6376 *pcbEnumValues = cbBufSize;
6377 *pnEnumValues = cValues;
6379 if (cbEnumValues < cbBufSize) /* buffer too small */
6381 if (HeapFree (hHeap, 0, lpValue) == 0)
6382 WARN ("HeapFree failed with code %i\n", GetLastError ());
6383 if (HeapFree (hHeap, 0, lpValueName) == 0)
6384 WARN ("HeapFree failed with code %i\n", GetLastError ());
6385 r = RegCloseKey (hkSubKey);
6386 if (r != ERROR_SUCCESS)
6387 WARN ("RegCloseKey returned %i\n", r);
6388 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6389 return ERROR_MORE_DATA;
6392 TRACE ("pass 2: copying all names and values to buffer\n");
6394 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6395 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6397 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6399 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6400 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6401 NULL, &dwType, lpValue, &cbValueLen);
6402 if (ret != ERROR_SUCCESS)
6404 if (HeapFree (hHeap, 0, lpValue) == 0)
6405 WARN ("HeapFree failed with code %i\n", GetLastError ());
6406 if (HeapFree (hHeap, 0, lpValueName) == 0)
6407 WARN ("HeapFree failed with code %i\n", GetLastError ());
6408 r = RegCloseKey (hkSubKey);
6409 if (r != ERROR_SUCCESS)
6410 WARN ("RegCloseKey returned %i\n", r);
6411 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6412 return ret;
6415 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6416 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6417 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6418 pEnumValues += cbValueNameLen;
6420 /* return # of *bytes* (including trailing \0), not # of chars */
6421 ppev[dwIndex].cbValueName = cbValueNameLen;
6423 ppev[dwIndex].dwType = dwType;
6425 memcpy (pEnumValues, lpValue, cbValueLen);
6426 ppev[dwIndex].pData = pEnumValues;
6427 pEnumValues += cbValueLen;
6429 ppev[dwIndex].cbData = cbValueLen;
6431 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6432 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6435 if (HeapFree (hHeap, 0, lpValue) == 0)
6437 ret = GetLastError ();
6438 ERR ("HeapFree failed with code %i\n", ret);
6439 if (HeapFree (hHeap, 0, lpValueName) == 0)
6440 WARN ("HeapFree failed with code %i\n", GetLastError ());
6441 r = RegCloseKey (hkSubKey);
6442 if (r != ERROR_SUCCESS)
6443 WARN ("RegCloseKey returned %i\n", r);
6444 return ret;
6447 if (HeapFree (hHeap, 0, lpValueName) == 0)
6449 ret = GetLastError ();
6450 ERR ("HeapFree failed with code %i\n", ret);
6451 r = RegCloseKey (hkSubKey);
6452 if (r != ERROR_SUCCESS)
6453 WARN ("RegCloseKey returned %i\n", r);
6454 return ret;
6457 ret = RegCloseKey (hkSubKey);
6458 if (ret != ERROR_SUCCESS)
6460 ERR ("RegCloseKey returned %i\n", ret);
6461 return ret;
6464 return ERROR_SUCCESS;
6467 /*******************************************************************************
6468 * EnumPrinterDataExA [WINSPOOL.@]
6470 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6471 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6472 * what Windows 2000 SP1 does.
6475 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6476 LPBYTE pEnumValues, DWORD cbEnumValues,
6477 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6479 INT len;
6480 LPWSTR pKeyNameW;
6481 DWORD ret, dwIndex, dwBufSize;
6482 HANDLE hHeap;
6483 LPSTR pBuffer;
6485 TRACE ("%p %s\n", hPrinter, pKeyName);
6487 if (pKeyName == NULL || *pKeyName == 0)
6488 return ERROR_INVALID_PARAMETER;
6490 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6491 if (len == 0)
6493 ret = GetLastError ();
6494 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6495 return ret;
6498 hHeap = GetProcessHeap ();
6499 if (hHeap == NULL)
6501 ERR ("GetProcessHeap failed\n");
6502 return ERROR_OUTOFMEMORY;
6505 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6506 if (pKeyNameW == NULL)
6508 ERR ("Failed to allocate %i bytes from process heap\n",
6509 (LONG)(len * sizeof (WCHAR)));
6510 return ERROR_OUTOFMEMORY;
6513 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6515 ret = GetLastError ();
6516 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6517 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6518 WARN ("HeapFree failed with code %i\n", GetLastError ());
6519 return ret;
6522 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6523 pcbEnumValues, pnEnumValues);
6524 if (ret != ERROR_SUCCESS)
6526 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6527 WARN ("HeapFree failed with code %i\n", GetLastError ());
6528 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6529 return ret;
6532 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6534 ret = GetLastError ();
6535 ERR ("HeapFree failed with code %i\n", ret);
6536 return ret;
6539 if (*pnEnumValues == 0) /* empty key */
6540 return ERROR_SUCCESS;
6542 dwBufSize = 0;
6543 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6545 PPRINTER_ENUM_VALUESW ppev =
6546 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6548 if (dwBufSize < ppev->cbValueName)
6549 dwBufSize = ppev->cbValueName;
6551 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6552 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6553 dwBufSize = ppev->cbData;
6556 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6558 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6559 if (pBuffer == NULL)
6561 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6562 return ERROR_OUTOFMEMORY;
6565 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6567 PPRINTER_ENUM_VALUESW ppev =
6568 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6570 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6571 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6572 NULL);
6573 if (len == 0)
6575 ret = GetLastError ();
6576 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6577 if (HeapFree (hHeap, 0, pBuffer) == 0)
6578 WARN ("HeapFree failed with code %i\n", GetLastError ());
6579 return ret;
6582 memcpy (ppev->pValueName, pBuffer, len);
6584 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6586 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6587 ppev->dwType != REG_MULTI_SZ)
6588 continue;
6590 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6591 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6592 if (len == 0)
6594 ret = GetLastError ();
6595 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6596 if (HeapFree (hHeap, 0, pBuffer) == 0)
6597 WARN ("HeapFree failed with code %i\n", GetLastError ());
6598 return ret;
6601 memcpy (ppev->pData, pBuffer, len);
6603 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6604 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6607 if (HeapFree (hHeap, 0, pBuffer) == 0)
6609 ret = GetLastError ();
6610 ERR ("HeapFree failed with code %i\n", ret);
6611 return ret;
6614 return ERROR_SUCCESS;
6617 /******************************************************************************
6618 * AbortPrinter (WINSPOOL.@)
6620 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6622 FIXME("(%p), stub!\n", hPrinter);
6623 return TRUE;
6626 /******************************************************************************
6627 * AddPortA (WINSPOOL.@)
6629 * See AddPortW.
6632 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6634 LPWSTR nameW = NULL;
6635 LPWSTR monitorW = NULL;
6636 DWORD len;
6637 BOOL res;
6639 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6641 if (pName) {
6642 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6643 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6644 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6647 if (pMonitorName) {
6648 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6649 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6650 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6652 res = AddPortW(nameW, hWnd, monitorW);
6653 HeapFree(GetProcessHeap(), 0, nameW);
6654 HeapFree(GetProcessHeap(), 0, monitorW);
6655 return res;
6658 /******************************************************************************
6659 * AddPortW (WINSPOOL.@)
6661 * Add a Port for a specific Monitor
6663 * PARAMS
6664 * pName [I] Servername or NULL (local Computer)
6665 * hWnd [I] Handle to parent Window for the Dialog-Box
6666 * pMonitorName [I] Name of the Monitor that manage the Port
6668 * RETURNS
6669 * Success: TRUE
6670 * Failure: FALSE
6673 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6675 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6677 if ((backend == NULL) && !load_backend()) return FALSE;
6679 if (!pMonitorName) {
6680 SetLastError(RPC_X_NULL_REF_POINTER);
6681 return FALSE;
6684 return backend->fpAddPort(pName, hWnd, pMonitorName);
6687 /******************************************************************************
6688 * AddPortExA (WINSPOOL.@)
6690 * See AddPortExW.
6693 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6695 PORT_INFO_2W pi2W;
6696 PORT_INFO_2A * pi2A;
6697 LPWSTR nameW = NULL;
6698 LPWSTR monitorW = NULL;
6699 DWORD len;
6700 BOOL res;
6702 pi2A = (PORT_INFO_2A *) pBuffer;
6704 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6705 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6707 if ((level < 1) || (level > 2)) {
6708 SetLastError(ERROR_INVALID_LEVEL);
6709 return FALSE;
6712 if (!pi2A) {
6713 SetLastError(ERROR_INVALID_PARAMETER);
6714 return FALSE;
6717 if (pName) {
6718 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6719 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6720 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6723 if (pMonitorName) {
6724 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6725 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6726 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6729 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6731 if (pi2A->pPortName) {
6732 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6733 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6734 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6737 if (level > 1) {
6738 if (pi2A->pMonitorName) {
6739 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6740 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6741 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6744 if (pi2A->pDescription) {
6745 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6746 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6747 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6749 pi2W.fPortType = pi2A->fPortType;
6750 pi2W.Reserved = pi2A->Reserved;
6753 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6755 HeapFree(GetProcessHeap(), 0, nameW);
6756 HeapFree(GetProcessHeap(), 0, monitorW);
6757 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6758 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6759 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6760 return res;
6764 /******************************************************************************
6765 * AddPortExW (WINSPOOL.@)
6767 * Add a Port for a specific Monitor, without presenting a user interface
6769 * PARAMS
6770 * pName [I] Servername or NULL (local Computer)
6771 * level [I] Structure-Level (1 or 2) for pBuffer
6772 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6773 * pMonitorName [I] Name of the Monitor that manage the Port
6775 * RETURNS
6776 * Success: TRUE
6777 * Failure: FALSE
6780 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6782 PORT_INFO_2W * pi2;
6784 pi2 = (PORT_INFO_2W *) pBuffer;
6786 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6787 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6788 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6789 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6791 if ((backend == NULL) && !load_backend()) return FALSE;
6793 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6794 SetLastError(ERROR_INVALID_PARAMETER);
6795 return FALSE;
6798 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6801 /******************************************************************************
6802 * AddPrinterConnectionA (WINSPOOL.@)
6804 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6806 FIXME("%s\n", debugstr_a(pName));
6807 return FALSE;
6810 /******************************************************************************
6811 * AddPrinterConnectionW (WINSPOOL.@)
6813 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6815 FIXME("%s\n", debugstr_w(pName));
6816 return FALSE;
6819 /******************************************************************************
6820 * AddPrinterDriverExW (WINSPOOL.@)
6822 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6824 * PARAMS
6825 * pName [I] Servername or NULL (local Computer)
6826 * level [I] Level for the supplied DRIVER_INFO_*W struct
6827 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6828 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6830 * RESULTS
6831 * Success: TRUE
6832 * Failure: FALSE
6835 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6837 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6839 if ((backend == NULL) && !load_backend()) return FALSE;
6841 if (level < 2 || level == 5 || level == 7 || level > 8) {
6842 SetLastError(ERROR_INVALID_LEVEL);
6843 return FALSE;
6846 if (!pDriverInfo) {
6847 SetLastError(ERROR_INVALID_PARAMETER);
6848 return FALSE;
6851 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6854 /******************************************************************************
6855 * AddPrinterDriverExA (WINSPOOL.@)
6857 * See AddPrinterDriverExW.
6860 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6862 DRIVER_INFO_8A *diA;
6863 DRIVER_INFO_8W diW;
6864 LPWSTR nameW = NULL;
6865 DWORD lenA;
6866 DWORD len;
6867 DWORD res = FALSE;
6869 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6871 diA = (DRIVER_INFO_8A *) pDriverInfo;
6872 ZeroMemory(&diW, sizeof(diW));
6874 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6875 SetLastError(ERROR_INVALID_LEVEL);
6876 return FALSE;
6879 if (diA == NULL) {
6880 SetLastError(ERROR_INVALID_PARAMETER);
6881 return FALSE;
6884 /* convert servername to unicode */
6885 if (pName) {
6886 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6887 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6888 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6891 /* common fields */
6892 diW.cVersion = diA->cVersion;
6894 if (diA->pName) {
6895 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6896 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6897 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6900 if (diA->pEnvironment) {
6901 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6902 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6903 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6906 if (diA->pDriverPath) {
6907 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6908 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6909 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6912 if (diA->pDataFile) {
6913 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6914 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6915 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6918 if (diA->pConfigFile) {
6919 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6920 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6921 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6924 if ((Level > 2) && diA->pDependentFiles) {
6925 lenA = multi_sz_lenA(diA->pDependentFiles);
6926 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6927 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6928 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6931 if ((Level > 2) && diA->pMonitorName) {
6932 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6933 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6934 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6937 if ((Level > 3) && diA->pDefaultDataType) {
6938 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6939 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6940 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6943 if ((Level > 3) && diA->pszzPreviousNames) {
6944 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6945 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6946 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6947 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6950 if ((Level > 5) && diA->pszMfgName) {
6951 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6952 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6953 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6956 if ((Level > 5) && diA->pszOEMUrl) {
6957 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6958 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6959 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6962 if ((Level > 5) && diA->pszHardwareID) {
6963 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6964 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6965 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6968 if ((Level > 5) && diA->pszProvider) {
6969 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6970 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6971 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6974 if (Level > 7) {
6975 FIXME("level %u is incomplete\n", Level);
6978 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6979 TRACE("got %u with %u\n", res, GetLastError());
6980 HeapFree(GetProcessHeap(), 0, nameW);
6981 HeapFree(GetProcessHeap(), 0, diW.pName);
6982 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6983 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6984 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6985 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6986 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6987 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6988 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6989 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6990 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6991 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6992 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6993 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6995 TRACE("=> %u with %u\n", res, GetLastError());
6996 return res;
6999 /******************************************************************************
7000 * ConfigurePortA (WINSPOOL.@)
7002 * See ConfigurePortW.
7005 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7007 LPWSTR nameW = NULL;
7008 LPWSTR portW = NULL;
7009 INT len;
7010 DWORD res;
7012 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7014 /* convert servername to unicode */
7015 if (pName) {
7016 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7017 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7018 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7021 /* convert portname to unicode */
7022 if (pPortName) {
7023 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7024 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7025 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7028 res = ConfigurePortW(nameW, hWnd, portW);
7029 HeapFree(GetProcessHeap(), 0, nameW);
7030 HeapFree(GetProcessHeap(), 0, portW);
7031 return res;
7034 /******************************************************************************
7035 * ConfigurePortW (WINSPOOL.@)
7037 * Display the Configuration-Dialog for a specific Port
7039 * PARAMS
7040 * pName [I] Servername or NULL (local Computer)
7041 * hWnd [I] Handle to parent Window for the Dialog-Box
7042 * pPortName [I] Name of the Port, that should be configured
7044 * RETURNS
7045 * Success: TRUE
7046 * Failure: FALSE
7049 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7052 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7054 if ((backend == NULL) && !load_backend()) return FALSE;
7056 if (!pPortName) {
7057 SetLastError(RPC_X_NULL_REF_POINTER);
7058 return FALSE;
7061 return backend->fpConfigurePort(pName, hWnd, pPortName);
7064 /******************************************************************************
7065 * ConnectToPrinterDlg (WINSPOOL.@)
7067 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7069 FIXME("%p %x\n", hWnd, Flags);
7070 return NULL;
7073 /******************************************************************************
7074 * DeletePrinterConnectionA (WINSPOOL.@)
7076 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7078 FIXME("%s\n", debugstr_a(pName));
7079 return TRUE;
7082 /******************************************************************************
7083 * DeletePrinterConnectionW (WINSPOOL.@)
7085 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7087 FIXME("%s\n", debugstr_w(pName));
7088 return TRUE;
7091 /******************************************************************************
7092 * DeletePrinterDriverExW (WINSPOOL.@)
7094 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7095 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7097 HKEY hkey_drivers;
7098 BOOL ret = FALSE;
7100 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7101 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7103 if(pName && pName[0])
7105 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7106 SetLastError(ERROR_INVALID_PARAMETER);
7107 return FALSE;
7110 if(dwDeleteFlag)
7112 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7113 SetLastError(ERROR_INVALID_PARAMETER);
7114 return FALSE;
7117 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7119 if(!hkey_drivers)
7121 ERR("Can't open drivers key\n");
7122 return FALSE;
7125 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7126 ret = TRUE;
7128 RegCloseKey(hkey_drivers);
7130 return ret;
7133 /******************************************************************************
7134 * DeletePrinterDriverExA (WINSPOOL.@)
7136 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7137 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7139 UNICODE_STRING NameW, EnvW, DriverW;
7140 BOOL ret;
7142 asciitounicode(&NameW, pName);
7143 asciitounicode(&EnvW, pEnvironment);
7144 asciitounicode(&DriverW, pDriverName);
7146 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7148 RtlFreeUnicodeString(&DriverW);
7149 RtlFreeUnicodeString(&EnvW);
7150 RtlFreeUnicodeString(&NameW);
7152 return ret;
7155 /******************************************************************************
7156 * DeletePrinterDataExW (WINSPOOL.@)
7158 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7159 LPCWSTR pValueName)
7161 FIXME("%p %s %s\n", hPrinter,
7162 debugstr_w(pKeyName), debugstr_w(pValueName));
7163 return ERROR_INVALID_PARAMETER;
7166 /******************************************************************************
7167 * DeletePrinterDataExA (WINSPOOL.@)
7169 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7170 LPCSTR pValueName)
7172 FIXME("%p %s %s\n", hPrinter,
7173 debugstr_a(pKeyName), debugstr_a(pValueName));
7174 return ERROR_INVALID_PARAMETER;
7177 /******************************************************************************
7178 * DeletePrintProcessorA (WINSPOOL.@)
7180 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7182 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7183 debugstr_a(pPrintProcessorName));
7184 return TRUE;
7187 /******************************************************************************
7188 * DeletePrintProcessorW (WINSPOOL.@)
7190 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7192 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7193 debugstr_w(pPrintProcessorName));
7194 return TRUE;
7197 /******************************************************************************
7198 * DeletePrintProvidorA (WINSPOOL.@)
7200 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7202 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7203 debugstr_a(pPrintProviderName));
7204 return TRUE;
7207 /******************************************************************************
7208 * DeletePrintProvidorW (WINSPOOL.@)
7210 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7212 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7213 debugstr_w(pPrintProviderName));
7214 return TRUE;
7217 /******************************************************************************
7218 * EnumFormsA (WINSPOOL.@)
7220 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7221 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7223 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7224 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7225 return FALSE;
7228 /******************************************************************************
7229 * EnumFormsW (WINSPOOL.@)
7231 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7232 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7234 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7235 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7236 return FALSE;
7239 /*****************************************************************************
7240 * EnumMonitorsA [WINSPOOL.@]
7242 * See EnumMonitorsW.
7245 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7246 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7248 BOOL res;
7249 LPBYTE bufferW = NULL;
7250 LPWSTR nameW = NULL;
7251 DWORD needed = 0;
7252 DWORD numentries = 0;
7253 INT len;
7255 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7256 cbBuf, pcbNeeded, pcReturned);
7258 /* convert servername to unicode */
7259 if (pName) {
7260 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7261 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7262 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7264 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7265 needed = cbBuf * sizeof(WCHAR);
7266 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7267 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7269 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7270 if (pcbNeeded) needed = *pcbNeeded;
7271 /* HeapReAlloc return NULL, when bufferW was NULL */
7272 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7273 HeapAlloc(GetProcessHeap(), 0, needed);
7275 /* Try again with the large Buffer */
7276 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7278 numentries = pcReturned ? *pcReturned : 0;
7279 needed = 0;
7281 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7282 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7284 if (res) {
7285 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7286 DWORD entrysize = 0;
7287 DWORD index;
7288 LPSTR ptr;
7289 LPMONITOR_INFO_2W mi2w;
7290 LPMONITOR_INFO_2A mi2a;
7292 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7293 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7295 /* First pass: calculate the size for all Entries */
7296 mi2w = (LPMONITOR_INFO_2W) bufferW;
7297 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7298 index = 0;
7299 while (index < numentries) {
7300 index++;
7301 needed += entrysize; /* MONITOR_INFO_?A */
7302 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7304 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7305 NULL, 0, NULL, NULL);
7306 if (Level > 1) {
7307 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7308 NULL, 0, NULL, NULL);
7309 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7310 NULL, 0, NULL, NULL);
7312 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7313 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7314 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7317 /* check for errors and quit on failure */
7318 if (cbBuf < needed) {
7319 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7320 res = FALSE;
7321 goto emA_cleanup;
7323 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7324 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7325 cbBuf -= len ; /* free Bytes in the user-Buffer */
7326 mi2w = (LPMONITOR_INFO_2W) bufferW;
7327 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7328 index = 0;
7329 /* Second Pass: Fill the User Buffer (if we have one) */
7330 while ((index < numentries) && pMonitors) {
7331 index++;
7332 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7333 mi2a->pName = ptr;
7334 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7335 ptr, cbBuf , NULL, NULL);
7336 ptr += len;
7337 cbBuf -= len;
7338 if (Level > 1) {
7339 mi2a->pEnvironment = ptr;
7340 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7341 ptr, cbBuf, NULL, NULL);
7342 ptr += len;
7343 cbBuf -= len;
7345 mi2a->pDLLName = ptr;
7346 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7347 ptr, cbBuf, NULL, NULL);
7348 ptr += len;
7349 cbBuf -= len;
7351 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7352 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7353 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7356 emA_cleanup:
7357 if (pcbNeeded) *pcbNeeded = needed;
7358 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7360 HeapFree(GetProcessHeap(), 0, nameW);
7361 HeapFree(GetProcessHeap(), 0, bufferW);
7363 TRACE("returning %d with %d (%d byte for %d entries)\n",
7364 (res), GetLastError(), needed, numentries);
7366 return (res);
7370 /*****************************************************************************
7371 * EnumMonitorsW [WINSPOOL.@]
7373 * Enumerate available Port-Monitors
7375 * PARAMS
7376 * pName [I] Servername or NULL (local Computer)
7377 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7378 * pMonitors [O] PTR to Buffer that receives the Result
7379 * cbBuf [I] Size of Buffer at pMonitors
7380 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7381 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7383 * RETURNS
7384 * Success: TRUE
7385 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7388 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7389 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7392 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7393 cbBuf, pcbNeeded, pcReturned);
7395 if ((backend == NULL) && !load_backend()) return FALSE;
7397 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7398 SetLastError(RPC_X_NULL_REF_POINTER);
7399 return FALSE;
7402 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7405 /******************************************************************************
7406 * SpoolerInit (WINSPOOL.@)
7408 * Initialize the Spooler
7410 * RETURNS
7411 * Success: TRUE
7412 * Failure: FALSE
7414 * NOTES
7415 * The function fails on windows, when the spooler service is not running
7418 BOOL WINAPI SpoolerInit(void)
7421 if ((backend == NULL) && !load_backend()) return FALSE;
7422 return TRUE;
7425 /******************************************************************************
7426 * XcvDataW (WINSPOOL.@)
7428 * Execute commands in the Printmonitor DLL
7430 * PARAMS
7431 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7432 * pszDataName [i] Name of the command to execute
7433 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7434 * cbInputData [i] Size in Bytes of Buffer at pInputData
7435 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7436 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7437 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7438 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7440 * RETURNS
7441 * Success: TRUE
7442 * Failure: FALSE
7444 * NOTES
7445 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7446 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7448 * Minimal List of commands, that a Printmonitor DLL should support:
7450 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7451 *| "AddPort" : Add a Port
7452 *| "DeletePort": Delete a Port
7454 * Many Printmonitors support additional commands. Examples for localspl.dll:
7455 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7456 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7459 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7460 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7461 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7463 opened_printer_t *printer;
7465 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7466 pInputData, cbInputData, pOutputData,
7467 cbOutputData, pcbOutputNeeded, pdwStatus);
7469 if ((backend == NULL) && !load_backend()) return FALSE;
7471 printer = get_opened_printer(hXcv);
7472 if (!printer || (!printer->backend_printer)) {
7473 SetLastError(ERROR_INVALID_HANDLE);
7474 return FALSE;
7477 if (!pcbOutputNeeded) {
7478 SetLastError(ERROR_INVALID_PARAMETER);
7479 return FALSE;
7482 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7483 SetLastError(RPC_X_NULL_REF_POINTER);
7484 return FALSE;
7487 *pcbOutputNeeded = 0;
7489 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7490 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7494 /*****************************************************************************
7495 * EnumPrinterDataA [WINSPOOL.@]
7498 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7499 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7500 DWORD cbData, LPDWORD pcbData )
7502 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7503 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7504 return ERROR_NO_MORE_ITEMS;
7507 /*****************************************************************************
7508 * EnumPrinterDataW [WINSPOOL.@]
7511 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7512 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7513 DWORD cbData, LPDWORD pcbData )
7515 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7516 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7517 return ERROR_NO_MORE_ITEMS;
7520 /*****************************************************************************
7521 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7524 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7525 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7526 LPDWORD pcbNeeded, LPDWORD pcReturned)
7528 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7529 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7530 pcbNeeded, pcReturned);
7531 return FALSE;
7534 /*****************************************************************************
7535 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7538 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7539 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7540 LPDWORD pcbNeeded, LPDWORD pcReturned)
7542 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7543 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7544 pcbNeeded, pcReturned);
7545 return FALSE;
7548 /*****************************************************************************
7549 * EnumPrintProcessorsA [WINSPOOL.@]
7551 * See EnumPrintProcessorsW.
7554 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7555 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7557 BOOL res;
7558 LPBYTE bufferW = NULL;
7559 LPWSTR nameW = NULL;
7560 LPWSTR envW = NULL;
7561 DWORD needed = 0;
7562 DWORD numentries = 0;
7563 INT len;
7565 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7566 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7568 /* convert names to unicode */
7569 if (pName) {
7570 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7571 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7572 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7574 if (pEnvironment) {
7575 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7576 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7577 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7580 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7581 needed = cbBuf * sizeof(WCHAR);
7582 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7583 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7585 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7586 if (pcbNeeded) needed = *pcbNeeded;
7587 /* HeapReAlloc return NULL, when bufferW was NULL */
7588 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7589 HeapAlloc(GetProcessHeap(), 0, needed);
7591 /* Try again with the large Buffer */
7592 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7594 numentries = pcReturned ? *pcReturned : 0;
7595 needed = 0;
7597 if (res) {
7598 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7599 DWORD index;
7600 LPSTR ptr;
7601 PPRINTPROCESSOR_INFO_1W ppiw;
7602 PPRINTPROCESSOR_INFO_1A ppia;
7604 /* First pass: calculate the size for all Entries */
7605 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7606 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7607 index = 0;
7608 while (index < numentries) {
7609 index++;
7610 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7611 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7613 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7614 NULL, 0, NULL, NULL);
7616 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7617 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7620 /* check for errors and quit on failure */
7621 if (cbBuf < needed) {
7622 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7623 res = FALSE;
7624 goto epp_cleanup;
7627 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7628 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7629 cbBuf -= len ; /* free Bytes in the user-Buffer */
7630 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7631 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7632 index = 0;
7633 /* Second Pass: Fill the User Buffer (if we have one) */
7634 while ((index < numentries) && pPPInfo) {
7635 index++;
7636 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7637 ppia->pName = ptr;
7638 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7639 ptr, cbBuf , NULL, NULL);
7640 ptr += len;
7641 cbBuf -= len;
7643 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7644 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7648 epp_cleanup:
7649 if (pcbNeeded) *pcbNeeded = needed;
7650 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7652 HeapFree(GetProcessHeap(), 0, nameW);
7653 HeapFree(GetProcessHeap(), 0, envW);
7654 HeapFree(GetProcessHeap(), 0, bufferW);
7656 TRACE("returning %d with %d (%d byte for %d entries)\n",
7657 (res), GetLastError(), needed, numentries);
7659 return (res);
7662 /*****************************************************************************
7663 * EnumPrintProcessorsW [WINSPOOL.@]
7665 * Enumerate available Print Processors
7667 * PARAMS
7668 * pName [I] Servername or NULL (local Computer)
7669 * pEnvironment [I] Printing-Environment or NULL (Default)
7670 * Level [I] Structure-Level (Only 1 is allowed)
7671 * pPPInfo [O] PTR to Buffer that receives the Result
7672 * cbBuf [I] Size of Buffer at pPPInfo
7673 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7674 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7676 * RETURNS
7677 * Success: TRUE
7678 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7681 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7682 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7685 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7686 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7688 if ((backend == NULL) && !load_backend()) return FALSE;
7690 if (!pcbNeeded || !pcReturned) {
7691 SetLastError(RPC_X_NULL_REF_POINTER);
7692 return FALSE;
7695 if (!pPPInfo && (cbBuf > 0)) {
7696 SetLastError(ERROR_INVALID_USER_BUFFER);
7697 return FALSE;
7700 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7701 cbBuf, pcbNeeded, pcReturned);
7704 /*****************************************************************************
7705 * ExtDeviceMode [WINSPOOL.@]
7708 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7709 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7710 DWORD fMode)
7712 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7713 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7714 debugstr_a(pProfile), fMode);
7715 return -1;
7718 /*****************************************************************************
7719 * FindClosePrinterChangeNotification [WINSPOOL.@]
7722 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7724 FIXME("Stub: %p\n", hChange);
7725 return TRUE;
7728 /*****************************************************************************
7729 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7732 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7733 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7735 FIXME("Stub: %p %x %x %p\n",
7736 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7737 return INVALID_HANDLE_VALUE;
7740 /*****************************************************************************
7741 * FindNextPrinterChangeNotification [WINSPOOL.@]
7744 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7745 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7747 FIXME("Stub: %p %p %p %p\n",
7748 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7749 return FALSE;
7752 /*****************************************************************************
7753 * FreePrinterNotifyInfo [WINSPOOL.@]
7756 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7758 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7759 return TRUE;
7762 /*****************************************************************************
7763 * string_to_buf
7765 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7766 * ansi depending on the unicode parameter.
7768 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7770 if(!str)
7772 *size = 0;
7773 return TRUE;
7776 if(unicode)
7778 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7779 if(*size <= cb)
7781 memcpy(ptr, str, *size);
7782 return TRUE;
7784 return FALSE;
7786 else
7788 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7789 if(*size <= cb)
7791 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7792 return TRUE;
7794 return FALSE;
7798 /*****************************************************************************
7799 * get_job_info_1
7801 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7802 LPDWORD pcbNeeded, BOOL unicode)
7804 DWORD size, left = cbBuf;
7805 BOOL space = (cbBuf > 0);
7806 LPBYTE ptr = buf;
7808 *pcbNeeded = 0;
7810 if(space)
7812 ji1->JobId = job->job_id;
7815 string_to_buf(job->document_title, ptr, left, &size, unicode);
7816 if(space && size <= left)
7818 ji1->pDocument = (LPWSTR)ptr;
7819 ptr += size;
7820 left -= size;
7822 else
7823 space = FALSE;
7824 *pcbNeeded += size;
7826 if (job->printer_name)
7828 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7829 if(space && size <= left)
7831 ji1->pPrinterName = (LPWSTR)ptr;
7832 ptr += size;
7833 left -= size;
7835 else
7836 space = FALSE;
7837 *pcbNeeded += size;
7840 return space;
7843 /*****************************************************************************
7844 * get_job_info_2
7846 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7847 LPDWORD pcbNeeded, BOOL unicode)
7849 DWORD size, left = cbBuf;
7850 DWORD shift;
7851 BOOL space = (cbBuf > 0);
7852 LPBYTE ptr = buf;
7853 LPDEVMODEA dmA = NULL;
7854 LPDEVMODEW devmode;
7856 *pcbNeeded = 0;
7858 if(space)
7860 ji2->JobId = job->job_id;
7863 string_to_buf(job->document_title, ptr, left, &size, unicode);
7864 if(space && size <= left)
7866 ji2->pDocument = (LPWSTR)ptr;
7867 ptr += size;
7868 left -= size;
7870 else
7871 space = FALSE;
7872 *pcbNeeded += size;
7874 if (job->printer_name)
7876 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7877 if(space && size <= left)
7879 ji2->pPrinterName = (LPWSTR)ptr;
7880 ptr += size;
7881 left -= size;
7883 else
7884 space = FALSE;
7885 *pcbNeeded += size;
7888 if (job->devmode)
7890 if (!unicode)
7892 dmA = DEVMODEdupWtoA(job->devmode);
7893 devmode = (LPDEVMODEW) dmA;
7894 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7896 else
7898 devmode = job->devmode;
7899 size = devmode->dmSize + devmode->dmDriverExtra;
7902 if (!devmode)
7903 FIXME("Can't convert DEVMODE W to A\n");
7904 else
7906 /* align DEVMODE to a DWORD boundary */
7907 shift = (4 - (*pcbNeeded & 3)) & 3;
7908 size += shift;
7910 if (size <= left)
7912 ptr += shift;
7913 memcpy(ptr, devmode, size-shift);
7914 ji2->pDevMode = (LPDEVMODEW)ptr;
7915 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7916 ptr += size-shift;
7917 left -= size;
7919 else
7920 space = FALSE;
7921 *pcbNeeded +=size;
7925 return space;
7928 /*****************************************************************************
7929 * get_job_info
7931 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7932 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7934 BOOL ret = FALSE;
7935 DWORD needed = 0, size;
7936 job_t *job;
7937 LPBYTE ptr = pJob;
7939 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7941 EnterCriticalSection(&printer_handles_cs);
7942 job = get_job(hPrinter, JobId);
7943 if(!job)
7944 goto end;
7946 switch(Level)
7948 case 1:
7949 size = sizeof(JOB_INFO_1W);
7950 if(cbBuf >= size)
7952 cbBuf -= size;
7953 ptr += size;
7954 memset(pJob, 0, size);
7956 else
7957 cbBuf = 0;
7958 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7959 needed += size;
7960 break;
7962 case 2:
7963 size = sizeof(JOB_INFO_2W);
7964 if(cbBuf >= size)
7966 cbBuf -= size;
7967 ptr += size;
7968 memset(pJob, 0, size);
7970 else
7971 cbBuf = 0;
7972 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7973 needed += size;
7974 break;
7976 case 3:
7977 size = sizeof(JOB_INFO_3);
7978 if(cbBuf >= size)
7980 cbBuf -= size;
7981 memset(pJob, 0, size);
7982 ret = TRUE;
7984 else
7985 cbBuf = 0;
7986 needed = size;
7987 break;
7989 default:
7990 SetLastError(ERROR_INVALID_LEVEL);
7991 goto end;
7993 if(pcbNeeded)
7994 *pcbNeeded = needed;
7995 end:
7996 LeaveCriticalSection(&printer_handles_cs);
7997 return ret;
8000 /*****************************************************************************
8001 * GetJobA [WINSPOOL.@]
8004 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8005 DWORD cbBuf, LPDWORD pcbNeeded)
8007 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8010 /*****************************************************************************
8011 * GetJobW [WINSPOOL.@]
8014 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8015 DWORD cbBuf, LPDWORD pcbNeeded)
8017 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8020 /*****************************************************************************
8021 * schedule_pipe
8023 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8025 #ifdef HAVE_FORK
8026 char *unixname, *cmdA;
8027 DWORD len;
8028 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8029 BOOL ret = FALSE;
8030 char buf[1024];
8031 pid_t pid, wret;
8032 int status;
8034 if(!(unixname = wine_get_unix_file_name(filename)))
8035 return FALSE;
8037 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8038 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8039 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8041 TRACE("printing with: %s\n", cmdA);
8043 if((file_fd = open(unixname, O_RDONLY)) == -1)
8044 goto end;
8046 if (pipe(fds))
8048 ERR("pipe() failed!\n");
8049 goto end;
8052 if ((pid = fork()) == 0)
8054 close(0);
8055 dup2(fds[0], 0);
8056 close(fds[1]);
8058 /* reset signals that we previously set to SIG_IGN */
8059 signal(SIGPIPE, SIG_DFL);
8061 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8062 _exit(1);
8064 else if (pid == -1)
8066 ERR("fork() failed!\n");
8067 goto end;
8070 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8071 write(fds[1], buf, no_read);
8073 close(fds[1]);
8074 fds[1] = -1;
8076 /* reap child */
8077 do {
8078 wret = waitpid(pid, &status, 0);
8079 } while (wret < 0 && errno == EINTR);
8080 if (wret < 0)
8082 ERR("waitpid() failed!\n");
8083 goto end;
8085 if (!WIFEXITED(status) || WEXITSTATUS(status))
8087 ERR("child process failed! %d\n", status);
8088 goto end;
8091 ret = TRUE;
8093 end:
8094 if(file_fd != -1) close(file_fd);
8095 if(fds[0] != -1) close(fds[0]);
8096 if(fds[1] != -1) close(fds[1]);
8098 HeapFree(GetProcessHeap(), 0, cmdA);
8099 HeapFree(GetProcessHeap(), 0, unixname);
8100 return ret;
8101 #else
8102 return FALSE;
8103 #endif
8106 /*****************************************************************************
8107 * schedule_lpr
8109 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8111 WCHAR *cmd;
8112 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8113 BOOL r;
8115 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8116 sprintfW(cmd, fmtW, printer_name);
8118 r = schedule_pipe(cmd, filename);
8120 HeapFree(GetProcessHeap(), 0, cmd);
8121 return r;
8124 #ifdef SONAME_LIBCUPS
8125 /*****************************************************************************
8126 * get_cups_jobs_ticket_options
8128 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8129 * The CUPS scheduler only looks for these in Print-File requests, and since
8130 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8131 * parsed.
8133 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8135 FILE *fp = fopen( file, "r" );
8136 char buf[257]; /* DSC max of 256 + '\0' */
8137 const char *ps_adobe = "%!PS-Adobe-";
8138 const char *cups_job = "%cupsJobTicket:";
8140 if (!fp) return num_options;
8141 if (!fgets( buf, sizeof(buf), fp )) goto end;
8142 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8143 while (fgets( buf, sizeof(buf), fp ))
8145 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8146 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8149 end:
8150 fclose( fp );
8151 return num_options;
8153 #endif
8155 /*****************************************************************************
8156 * schedule_cups
8158 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8160 #ifdef SONAME_LIBCUPS
8161 if(pcupsPrintFile)
8163 char *unixname, *queue, *unix_doc_title;
8164 DWORD len;
8165 BOOL ret;
8166 int num_options = 0, i;
8167 cups_option_t *options = NULL;
8169 if(!(unixname = wine_get_unix_file_name(filename)))
8170 return FALSE;
8172 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8173 queue = HeapAlloc(GetProcessHeap(), 0, len);
8174 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8176 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8177 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8178 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8180 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8182 TRACE( "printing via cups with options:\n" );
8183 for (i = 0; i < num_options; i++)
8184 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8186 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8188 pcupsFreeOptions( num_options, options );
8190 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8191 HeapFree(GetProcessHeap(), 0, queue);
8192 HeapFree(GetProcessHeap(), 0, unixname);
8193 return ret;
8195 else
8196 #endif
8198 return schedule_lpr(printer_name, filename);
8202 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8204 LPWSTR filename;
8206 switch(msg)
8208 case WM_INITDIALOG:
8209 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8210 return TRUE;
8212 case WM_COMMAND:
8213 if(HIWORD(wparam) == BN_CLICKED)
8215 if(LOWORD(wparam) == IDOK)
8217 HANDLE hf;
8218 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8219 LPWSTR *output;
8221 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8222 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8224 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8226 WCHAR caption[200], message[200];
8227 int mb_ret;
8229 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8230 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8231 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8232 if(mb_ret == IDCANCEL)
8234 HeapFree(GetProcessHeap(), 0, filename);
8235 return TRUE;
8238 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8239 if(hf == INVALID_HANDLE_VALUE)
8241 WCHAR caption[200], message[200];
8243 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8244 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8245 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8246 HeapFree(GetProcessHeap(), 0, filename);
8247 return TRUE;
8249 CloseHandle(hf);
8250 DeleteFileW(filename);
8251 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8252 *output = filename;
8253 EndDialog(hwnd, IDOK);
8254 return TRUE;
8256 if(LOWORD(wparam) == IDCANCEL)
8258 EndDialog(hwnd, IDCANCEL);
8259 return TRUE;
8262 return FALSE;
8264 return FALSE;
8267 /*****************************************************************************
8268 * get_filename
8270 static BOOL get_filename(LPWSTR *filename)
8272 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8273 file_dlg_proc, (LPARAM)filename) == IDOK;
8276 /*****************************************************************************
8277 * schedule_file
8279 static BOOL schedule_file(LPCWSTR filename)
8281 LPWSTR output = NULL;
8283 if(get_filename(&output))
8285 BOOL r;
8286 TRACE("copy to %s\n", debugstr_w(output));
8287 r = CopyFileW(filename, output, FALSE);
8288 HeapFree(GetProcessHeap(), 0, output);
8289 return r;
8291 return FALSE;
8294 /*****************************************************************************
8295 * schedule_unixfile
8297 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8299 int in_fd, out_fd, no_read;
8300 char buf[1024];
8301 BOOL ret = FALSE;
8302 char *unixname, *outputA;
8303 DWORD len;
8305 if(!(unixname = wine_get_unix_file_name(filename)))
8306 return FALSE;
8308 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8309 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8310 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8312 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8313 in_fd = open(unixname, O_RDONLY);
8314 if(out_fd == -1 || in_fd == -1)
8315 goto end;
8317 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8318 write(out_fd, buf, no_read);
8320 ret = TRUE;
8321 end:
8322 if(in_fd != -1) close(in_fd);
8323 if(out_fd != -1) close(out_fd);
8324 HeapFree(GetProcessHeap(), 0, outputA);
8325 HeapFree(GetProcessHeap(), 0, unixname);
8326 return ret;
8329 /*****************************************************************************
8330 * ScheduleJob [WINSPOOL.@]
8333 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8335 opened_printer_t *printer;
8336 BOOL ret = FALSE;
8337 struct list *cursor, *cursor2;
8339 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8340 EnterCriticalSection(&printer_handles_cs);
8341 printer = get_opened_printer(hPrinter);
8342 if(!printer)
8343 goto end;
8345 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8347 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8348 HANDLE hf;
8350 if(job->job_id != dwJobID) continue;
8352 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8353 if(hf != INVALID_HANDLE_VALUE)
8355 PRINTER_INFO_5W *pi5 = NULL;
8356 LPWSTR portname = job->portname;
8357 DWORD needed;
8358 HKEY hkey;
8359 WCHAR output[1024];
8360 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8361 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8363 if (!portname)
8365 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8366 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8367 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8368 portname = pi5->pPortName;
8370 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8371 debugstr_w(portname));
8373 output[0] = 0;
8375 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8376 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8378 DWORD type, count = sizeof(output);
8379 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8380 RegCloseKey(hkey);
8382 if(output[0] == '|')
8384 ret = schedule_pipe(output + 1, job->filename);
8386 else if(output[0])
8388 ret = schedule_unixfile(output, job->filename);
8390 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8392 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8394 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8396 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8398 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8400 ret = schedule_file(job->filename);
8402 else
8404 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8406 HeapFree(GetProcessHeap(), 0, pi5);
8407 CloseHandle(hf);
8408 DeleteFileW(job->filename);
8410 list_remove(cursor);
8411 HeapFree(GetProcessHeap(), 0, job->document_title);
8412 HeapFree(GetProcessHeap(), 0, job->printer_name);
8413 HeapFree(GetProcessHeap(), 0, job->portname);
8414 HeapFree(GetProcessHeap(), 0, job->filename);
8415 HeapFree(GetProcessHeap(), 0, job->devmode);
8416 HeapFree(GetProcessHeap(), 0, job);
8417 break;
8419 end:
8420 LeaveCriticalSection(&printer_handles_cs);
8421 return ret;
8424 /*****************************************************************************
8425 * StartDocDlgA [WINSPOOL.@]
8427 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8429 UNICODE_STRING usBuffer;
8430 DOCINFOW docW;
8431 LPWSTR retW;
8432 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8433 LPSTR ret = NULL;
8435 docW.cbSize = sizeof(docW);
8436 if (doc->lpszDocName)
8438 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8439 if (!(docW.lpszDocName = docnameW)) return NULL;
8441 if (doc->lpszOutput)
8443 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8444 if (!(docW.lpszOutput = outputW)) return NULL;
8446 if (doc->lpszDatatype)
8448 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8449 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8451 docW.fwType = doc->fwType;
8453 retW = StartDocDlgW(hPrinter, &docW);
8455 if(retW)
8457 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8458 ret = HeapAlloc(GetProcessHeap(), 0, len);
8459 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8460 HeapFree(GetProcessHeap(), 0, retW);
8463 HeapFree(GetProcessHeap(), 0, datatypeW);
8464 HeapFree(GetProcessHeap(), 0, outputW);
8465 HeapFree(GetProcessHeap(), 0, docnameW);
8467 return ret;
8470 /*****************************************************************************
8471 * StartDocDlgW [WINSPOOL.@]
8473 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8474 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8475 * port is "FILE:". Also returns the full path if passed a relative path.
8477 * The caller should free the returned string from the process heap.
8479 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8481 LPWSTR ret = NULL;
8482 DWORD len, attr;
8484 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8486 PRINTER_INFO_5W *pi5;
8487 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8488 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8489 return NULL;
8490 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8491 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8492 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8494 HeapFree(GetProcessHeap(), 0, pi5);
8495 return NULL;
8497 HeapFree(GetProcessHeap(), 0, pi5);
8500 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8502 LPWSTR name;
8504 if (get_filename(&name))
8506 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8508 HeapFree(GetProcessHeap(), 0, name);
8509 return NULL;
8511 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8512 GetFullPathNameW(name, len, ret, NULL);
8513 HeapFree(GetProcessHeap(), 0, name);
8515 return ret;
8518 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8519 return NULL;
8521 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8522 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8524 attr = GetFileAttributesW(ret);
8525 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8527 HeapFree(GetProcessHeap(), 0, ret);
8528 ret = NULL;
8530 return ret;