msvcp: Sync num_get<>::_Getifld.
[wine.git] / dlls / winspool.drv / info.c
blob7509a8e7c01d76dccabbb9931e820dbbaf462aef
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 cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
862 WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
863 cups_ptype_t ret = 0;
865 if (type && *type)
867 ret = (cups_ptype_t)strtoulW( type, &end, 10 );
868 if (*end) ret = 0;
870 HeapFree( GetProcessHeap(), 0, type );
871 return ret;
874 static BOOL CUPS_LoadPrinters(void)
876 int i, nrofdests;
877 BOOL hadprinter = FALSE, haddefault = FALSE;
878 cups_dest_t *dests;
879 PRINTER_INFO_2W pi2;
880 WCHAR *port, *ppd_dir = NULL, *ppd;
881 HKEY hkeyPrinter, hkeyPrinters;
882 char loaderror[256];
883 WCHAR nameW[MAX_PATH];
884 HANDLE added_printer;
885 cups_ptype_t printer_type;
887 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
888 if (!cupshandle) {
889 TRACE("%s\n", loaderror);
890 return FALSE;
892 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
894 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
895 CUPS_FUNCS;
896 #undef DO_FUNC
897 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 );
898 CUPS_OPT_FUNCS;
899 #undef DO_FUNC
901 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
902 ERROR_SUCCESS) {
903 ERR("Can't create Printers key\n");
904 return FALSE;
907 nrofdests = pcupsGetDests(&dests);
908 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
909 for (i=0;i<nrofdests;i++) {
910 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
911 printer_type = get_cups_printer_type( dests + i );
913 TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
915 if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
917 TRACE( "skipping scanner-only device\n" );
918 continue;
921 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
922 lstrcpyW(port, CUPS_Port);
923 lstrcatW(port, nameW);
925 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
926 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
927 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
928 and continue */
929 TRACE("Printer already exists\n");
930 /* overwrite old LPR:* port */
931 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
932 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
933 /* flag that the PPD file should be checked for an update */
934 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
935 RegCloseKey(hkeyPrinter);
936 } else {
937 BOOL added_driver = FALSE;
939 if (!ppd_dir) ppd_dir = get_ppd_dir();
940 ppd = get_ppd_filename( ppd_dir, nameW );
941 if (get_cups_ppd( dests[i].name, ppd ))
943 added_driver = add_printer_driver( nameW, ppd );
944 unlink_ppd( ppd );
946 HeapFree( GetProcessHeap(), 0, ppd );
947 if (!added_driver) continue;
949 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
950 pi2.pPrinterName = nameW;
951 pi2.pDatatype = rawW;
952 pi2.pPrintProcessor = WinPrintW;
953 pi2.pDriverName = nameW;
954 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
955 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
956 pi2.pPortName = port;
957 pi2.pParameters = emptyStringW;
958 pi2.pShareName = emptyStringW;
959 pi2.pSepFile = emptyStringW;
961 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
962 if (added_printer) ClosePrinter( added_printer );
963 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
964 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
966 HeapFree( GetProcessHeap(), 0, pi2.pComment );
967 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
969 HeapFree( GetProcessHeap(), 0, port );
971 hadprinter = TRUE;
972 if (dests[i].is_default) {
973 SetDefaultPrinterW(nameW);
974 haddefault = TRUE;
978 if (ppd_dir)
980 RemoveDirectoryW( ppd_dir );
981 HeapFree( GetProcessHeap(), 0, ppd_dir );
984 if (hadprinter && !haddefault) {
985 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
986 SetDefaultPrinterW(nameW);
988 pcupsFreeDests(nrofdests, dests);
989 RegCloseKey(hkeyPrinters);
990 return TRUE;
993 #endif
995 static char *get_queue_name( HANDLE printer, BOOL *cups )
997 WCHAR *port, *name = NULL;
998 DWORD err, needed, type;
999 char *ret = NULL;
1000 HKEY key;
1002 *cups = FALSE;
1004 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1005 if (err) return NULL;
1006 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1007 if (err) goto end;
1008 port = HeapAlloc( GetProcessHeap(), 0, needed );
1009 if (!port) goto end;
1010 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1012 if (!strncmpW( port, CUPS_Port, sizeof(CUPS_Port) / sizeof(WCHAR) -1 ))
1014 name = port + sizeof(CUPS_Port) / sizeof(WCHAR) - 1;
1015 *cups = TRUE;
1017 else if (!strncmpW( port, LPR_Port, sizeof(LPR_Port) / sizeof(WCHAR) -1 ))
1018 name = port + sizeof(LPR_Port) / sizeof(WCHAR) - 1;
1019 if (name)
1021 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1022 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1023 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1025 HeapFree( GetProcessHeap(), 0, port );
1026 end:
1027 RegCloseKey( key );
1028 return ret;
1032 static void set_ppd_overrides( HANDLE printer )
1034 WCHAR *wstr = NULL;
1035 int size = 0;
1036 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1037 OSStatus status;
1038 PMPrintSession session = NULL;
1039 PMPageFormat format = NULL;
1040 PMPaper paper;
1041 CFStringRef paper_name;
1042 CFRange range;
1044 status = PMCreateSession( &session );
1045 if (status) goto end;
1047 status = PMCreatePageFormat( &format );
1048 if (status) goto end;
1050 status = PMSessionDefaultPageFormat( session, format );
1051 if (status) goto end;
1053 status = PMGetPageFormatPaper( format, &paper );
1054 if (status) goto end;
1056 status = PMPaperGetPPDPaperName( paper, &paper_name );
1057 if (status) goto end;
1059 range.location = 0;
1060 range.length = CFStringGetLength( paper_name );
1061 size = (range.length + 1) * sizeof(WCHAR);
1063 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1064 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1065 wstr[range.length] = 0;
1067 end:
1068 if (format) PMRelease( format );
1069 if (session) PMRelease( session );
1070 #endif
1072 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1073 HeapFree( GetProcessHeap(), 0, wstr );
1076 static BOOL update_driver( HANDLE printer )
1078 BOOL ret, is_cups;
1079 const WCHAR *name = get_opened_printer_name( printer );
1080 WCHAR *ppd_dir, *ppd;
1081 char *queue_name;
1083 if (!name) return FALSE;
1084 queue_name = get_queue_name( printer, &is_cups );
1085 if (!queue_name) return FALSE;
1087 ppd_dir = get_ppd_dir();
1088 ppd = get_ppd_filename( ppd_dir, name );
1090 #ifdef SONAME_LIBCUPS
1091 if (is_cups)
1092 ret = get_cups_ppd( queue_name, ppd );
1093 else
1094 #endif
1095 ret = get_fallback_ppd( queue_name, ppd );
1097 if (ret)
1099 TRACE( "updating driver %s\n", debugstr_w( name ) );
1100 ret = add_printer_driver( name, ppd );
1101 unlink_ppd( ppd );
1103 HeapFree( GetProcessHeap(), 0, ppd_dir );
1104 HeapFree( GetProcessHeap(), 0, ppd );
1105 HeapFree( GetProcessHeap(), 0, queue_name );
1107 set_ppd_overrides( printer );
1109 /* call into the driver to update the devmode */
1110 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1112 return ret;
1115 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1117 PRINTER_INFO_2A pinfo2a;
1118 const char *r;
1119 size_t name_len;
1120 char *e,*s,*name,*prettyname,*devname;
1121 BOOL ret = FALSE, set_default = FALSE;
1122 char *port = NULL, *env_default;
1123 HKEY hkeyPrinter, hkeyPrinters = NULL;
1124 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1125 HANDLE added_printer;
1127 while (isspace(*pent)) pent++;
1128 r = strchr(pent,':');
1129 if (r)
1130 name_len = r - pent;
1131 else
1132 name_len = strlen(pent);
1133 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1134 memcpy(name, pent, name_len);
1135 name[name_len] = '\0';
1136 if (r)
1137 pent = r;
1138 else
1139 pent = "";
1141 TRACE("name=%s entry=%s\n",name, pent);
1143 if(ispunct(*name)) { /* a tc entry, not a real printer */
1144 TRACE("skipping tc entry\n");
1145 goto end;
1148 if(strstr(pent,":server")) { /* server only version so skip */
1149 TRACE("skipping server entry\n");
1150 goto end;
1153 /* Determine whether this is a postscript printer. */
1155 ret = TRUE;
1156 env_default = getenv("PRINTER");
1157 prettyname = name;
1158 /* Get longest name, usually the one at the right for later display. */
1159 while((s=strchr(prettyname,'|'))) {
1160 *s = '\0';
1161 e = s;
1162 while(isspace(*--e)) *e = '\0';
1163 TRACE("\t%s\n", debugstr_a(prettyname));
1164 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1165 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1168 e = prettyname + strlen(prettyname);
1169 while(isspace(*--e)) *e = '\0';
1170 TRACE("\t%s\n", debugstr_a(prettyname));
1171 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1173 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1174 * if it is too long, we use it as comment below. */
1175 devname = prettyname;
1176 if (strlen(devname)>=CCHDEVICENAME-1)
1177 devname = name;
1178 if (strlen(devname)>=CCHDEVICENAME-1) {
1179 ret = FALSE;
1180 goto end;
1183 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1184 sprintf(port,"LPR:%s",name);
1186 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1187 ERROR_SUCCESS) {
1188 ERR("Can't create Printers key\n");
1189 ret = FALSE;
1190 goto end;
1193 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
1195 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1196 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1197 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1198 and continue */
1199 TRACE("Printer already exists\n");
1200 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1201 /* flag that the PPD file should be checked for an update */
1202 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1203 RegCloseKey(hkeyPrinter);
1204 } else {
1205 static CHAR data_type[] = "RAW",
1206 print_proc[] = "WinPrint",
1207 comment[] = "WINEPS Printer using LPR",
1208 params[] = "<parameters?>",
1209 share_name[] = "<share name?>",
1210 sep_file[] = "<sep file?>";
1211 BOOL added_driver = FALSE;
1213 if (!ppd_dir) ppd_dir = get_ppd_dir();
1214 ppd = get_ppd_filename( ppd_dir, devnameW );
1215 if (get_fallback_ppd( devname, ppd ))
1217 added_driver = add_printer_driver( devnameW, ppd );
1218 unlink_ppd( ppd );
1220 HeapFree( GetProcessHeap(), 0, ppd );
1221 if (!added_driver) goto end;
1223 memset(&pinfo2a,0,sizeof(pinfo2a));
1224 pinfo2a.pPrinterName = devname;
1225 pinfo2a.pDatatype = data_type;
1226 pinfo2a.pPrintProcessor = print_proc;
1227 pinfo2a.pDriverName = devname;
1228 pinfo2a.pComment = comment;
1229 pinfo2a.pLocation = prettyname;
1230 pinfo2a.pPortName = port;
1231 pinfo2a.pParameters = params;
1232 pinfo2a.pShareName = share_name;
1233 pinfo2a.pSepFile = sep_file;
1235 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1236 if (added_printer) ClosePrinter( added_printer );
1237 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1238 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1241 if (isfirst || set_default)
1242 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1244 end:
1245 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1246 if (ppd_dir)
1248 RemoveDirectoryW( ppd_dir );
1249 HeapFree( GetProcessHeap(), 0, ppd_dir );
1251 HeapFree(GetProcessHeap(), 0, port);
1252 HeapFree(GetProcessHeap(), 0, name);
1253 return ret;
1256 static BOOL
1257 PRINTCAP_LoadPrinters(void) {
1258 BOOL hadprinter = FALSE;
1259 char buf[200];
1260 FILE *f;
1261 char *pent = NULL;
1262 BOOL had_bash = FALSE;
1264 f = fopen("/etc/printcap","r");
1265 if (!f)
1266 return FALSE;
1268 while(fgets(buf,sizeof(buf),f)) {
1269 char *start, *end;
1271 end=strchr(buf,'\n');
1272 if (end) *end='\0';
1274 start = buf;
1275 while(isspace(*start)) start++;
1276 if(*start == '#' || *start == '\0')
1277 continue;
1279 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1280 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1281 HeapFree(GetProcessHeap(),0,pent);
1282 pent = NULL;
1285 if (end && *--end == '\\') {
1286 *end = '\0';
1287 had_bash = TRUE;
1288 } else
1289 had_bash = FALSE;
1291 if (pent) {
1292 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1293 strcat(pent,start);
1294 } else {
1295 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1296 strcpy(pent,start);
1300 if(pent) {
1301 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1302 HeapFree(GetProcessHeap(),0,pent);
1304 fclose(f);
1305 return hadprinter;
1308 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1310 if (value)
1311 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1312 (lstrlenW(value) + 1) * sizeof(WCHAR));
1313 else
1314 return ERROR_FILE_NOT_FOUND;
1317 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1319 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1320 DWORD ret = ERROR_FILE_NOT_FOUND;
1322 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1323 and we support these drivers. NT writes DEVMODEW so somehow
1324 we'll need to distinguish between these when we support NT
1325 drivers */
1327 if (dmA)
1329 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1330 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1331 HeapFree( GetProcessHeap(), 0, dmA );
1334 return ret;
1337 /******************************************************************
1338 * get_servername_from_name (internal)
1340 * for an external server, a copy of the serverpart from the full name is returned
1343 static LPWSTR get_servername_from_name(LPCWSTR name)
1345 LPWSTR server;
1346 LPWSTR ptr;
1347 WCHAR buffer[MAX_PATH];
1348 DWORD len;
1350 if (name == NULL) return NULL;
1351 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1353 server = strdupW(&name[2]); /* skip over both backslash */
1354 if (server == NULL) return NULL;
1356 /* strip '\' and the printername */
1357 ptr = strchrW(server, '\\');
1358 if (ptr) ptr[0] = '\0';
1360 TRACE("found %s\n", debugstr_w(server));
1362 len = sizeof(buffer)/sizeof(buffer[0]);
1363 if (GetComputerNameW(buffer, &len)) {
1364 if (lstrcmpW(buffer, server) == 0) {
1365 /* The requested Servername is our computername */
1366 HeapFree(GetProcessHeap(), 0, server);
1367 return NULL;
1370 return server;
1373 /******************************************************************
1374 * get_basename_from_name (internal)
1376 * skip over the serverpart from the full name
1379 static LPCWSTR get_basename_from_name(LPCWSTR name)
1381 if (name == NULL) return NULL;
1382 if ((name[0] == '\\') && (name[1] == '\\')) {
1383 /* skip over the servername and search for the following '\' */
1384 name = strchrW(&name[2], '\\');
1385 if ((name) && (name[1])) {
1386 /* found a separator ('\') followed by a name:
1387 skip over the separator and return the rest */
1388 name++;
1390 else
1392 /* no basename present (we found only a servername) */
1393 return NULL;
1396 return name;
1399 static void free_printer_entry( opened_printer_t *printer )
1401 /* the queue is shared, so don't free that here */
1402 HeapFree( GetProcessHeap(), 0, printer->printername );
1403 HeapFree( GetProcessHeap(), 0, printer->name );
1404 HeapFree( GetProcessHeap(), 0, printer->devmode );
1405 HeapFree( GetProcessHeap(), 0, printer );
1408 /******************************************************************
1409 * get_opened_printer_entry
1410 * Get the first place empty in the opened printer table
1412 * ToDo:
1413 * - pDefault is ignored
1415 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1417 UINT_PTR handle = nb_printer_handles, i;
1418 jobqueue_t *queue = NULL;
1419 opened_printer_t *printer = NULL;
1420 LPWSTR servername;
1421 LPCWSTR printername;
1423 if ((backend == NULL) && !load_backend()) return NULL;
1425 servername = get_servername_from_name(name);
1426 if (servername) {
1427 FIXME("server %s not supported\n", debugstr_w(servername));
1428 HeapFree(GetProcessHeap(), 0, servername);
1429 SetLastError(ERROR_INVALID_PRINTER_NAME);
1430 return NULL;
1433 printername = get_basename_from_name(name);
1434 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1436 /* an empty printername is invalid */
1437 if (printername && (!printername[0])) {
1438 SetLastError(ERROR_INVALID_PARAMETER);
1439 return NULL;
1442 EnterCriticalSection(&printer_handles_cs);
1444 for (i = 0; i < nb_printer_handles; i++)
1446 if (!printer_handles[i])
1448 if(handle == nb_printer_handles)
1449 handle = i;
1451 else
1453 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1454 queue = printer_handles[i]->queue;
1458 if (handle >= nb_printer_handles)
1460 opened_printer_t **new_array;
1461 if (printer_handles)
1462 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1463 (nb_printer_handles + 16) * sizeof(*new_array) );
1464 else
1465 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1466 (nb_printer_handles + 16) * sizeof(*new_array) );
1468 if (!new_array)
1470 handle = 0;
1471 goto end;
1473 printer_handles = new_array;
1474 nb_printer_handles += 16;
1477 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1479 handle = 0;
1480 goto end;
1483 /* get a printer handle from the backend */
1484 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1485 handle = 0;
1486 goto end;
1489 /* clone the base name. This is NULL for the printserver */
1490 printer->printername = strdupW(printername);
1492 /* clone the full name */
1493 printer->name = strdupW(name);
1494 if (name && (!printer->name)) {
1495 handle = 0;
1496 goto end;
1499 if (pDefault && pDefault->pDevMode)
1500 printer->devmode = dup_devmode( pDefault->pDevMode );
1502 if(queue)
1503 printer->queue = queue;
1504 else
1506 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1507 if (!printer->queue) {
1508 handle = 0;
1509 goto end;
1511 list_init(&printer->queue->jobs);
1512 printer->queue->ref = 0;
1514 InterlockedIncrement(&printer->queue->ref);
1516 printer_handles[handle] = printer;
1517 handle++;
1518 end:
1519 LeaveCriticalSection(&printer_handles_cs);
1520 if (!handle && printer) {
1521 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1522 free_printer_entry( printer );
1525 return (HANDLE)handle;
1528 static void old_printer_check( BOOL delete_phase )
1530 PRINTER_INFO_5W* pi;
1531 DWORD needed, type, num, delete, i, size;
1532 const DWORD one = 1;
1533 HKEY key;
1534 HANDLE hprn;
1536 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1537 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1539 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1540 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1541 for (i = 0; i < num; i++)
1543 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1544 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1545 continue;
1547 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1549 if (!delete_phase)
1551 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1552 RegCloseKey( key );
1554 else
1556 delete = 0;
1557 size = sizeof( delete );
1558 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1559 RegCloseKey( key );
1560 if (delete)
1562 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1563 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1565 DeletePrinter( hprn );
1566 ClosePrinter( hprn );
1568 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1572 HeapFree(GetProcessHeap(), 0, pi);
1575 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1576 'M','U','T','E','X','_','_','\0'};
1577 static HANDLE init_mutex;
1579 void WINSPOOL_LoadSystemPrinters(void)
1581 HKEY hkey, hkeyPrinters;
1582 DWORD needed, num, i;
1583 WCHAR PrinterName[256];
1584 BOOL done = FALSE;
1586 /* FIXME: The init code should be moved to spoolsv.exe */
1587 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1588 if (!init_mutex)
1590 ERR( "Failed to create mutex\n" );
1591 return;
1593 if (GetLastError() == ERROR_ALREADY_EXISTS)
1595 WaitForSingleObject( init_mutex, INFINITE );
1596 ReleaseMutex( init_mutex );
1597 TRACE( "Init already done\n" );
1598 return;
1601 /* This ensures that all printer entries have a valid Name value. If causes
1602 problems later if they don't. If one is found to be missed we create one
1603 and set it equal to the name of the key */
1604 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1605 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1606 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1607 for(i = 0; i < num; i++) {
1608 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1609 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1610 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1611 set_reg_szW(hkey, NameW, PrinterName);
1613 RegCloseKey(hkey);
1618 RegCloseKey(hkeyPrinters);
1621 old_printer_check( FALSE );
1623 #ifdef SONAME_LIBCUPS
1624 done = CUPS_LoadPrinters();
1625 #endif
1627 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1628 PRINTCAP_LoadPrinters();
1630 old_printer_check( TRUE );
1632 ReleaseMutex( init_mutex );
1633 return;
1636 /******************************************************************
1637 * get_job
1639 * Get the pointer to the specified job.
1640 * Should hold the printer_handles_cs before calling.
1642 static job_t *get_job(HANDLE hprn, DWORD JobId)
1644 opened_printer_t *printer = get_opened_printer(hprn);
1645 job_t *job;
1647 if(!printer) return NULL;
1648 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1650 if(job->job_id == JobId)
1651 return job;
1653 return NULL;
1656 /***********************************************************
1657 * DEVMODEcpyAtoW
1659 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1661 BOOL Formname;
1662 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1663 DWORD size;
1665 Formname = (dmA->dmSize > off_formname);
1666 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1667 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1668 dmW->dmDeviceName, CCHDEVICENAME);
1669 if(!Formname) {
1670 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1671 dmA->dmSize - CCHDEVICENAME);
1672 } else {
1673 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1674 off_formname - CCHDEVICENAME);
1675 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1676 dmW->dmFormName, CCHFORMNAME);
1677 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1678 (off_formname + CCHFORMNAME));
1680 dmW->dmSize = size;
1681 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1682 dmA->dmDriverExtra);
1683 return dmW;
1686 /******************************************************************
1687 * convert_printerinfo_W_to_A [internal]
1690 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1691 DWORD level, DWORD outlen, DWORD numentries)
1693 DWORD id = 0;
1694 LPSTR ptr;
1695 INT len;
1697 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1699 len = pi_sizeof[level] * numentries;
1700 ptr = (LPSTR) out + len;
1701 outlen -= len;
1703 /* copy the numbers of all PRINTER_INFO_* first */
1704 memcpy(out, pPrintersW, len);
1706 while (id < numentries) {
1707 switch (level) {
1708 case 1:
1710 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1711 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1713 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1714 if (piW->pDescription) {
1715 piA->pDescription = ptr;
1716 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1717 ptr, outlen, NULL, NULL);
1718 ptr += len;
1719 outlen -= len;
1721 if (piW->pName) {
1722 piA->pName = ptr;
1723 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1724 ptr, outlen, NULL, NULL);
1725 ptr += len;
1726 outlen -= len;
1728 if (piW->pComment) {
1729 piA->pComment = ptr;
1730 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1731 ptr, outlen, NULL, NULL);
1732 ptr += len;
1733 outlen -= len;
1735 break;
1738 case 2:
1740 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1741 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1742 LPDEVMODEA dmA;
1744 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1745 if (piW->pServerName) {
1746 piA->pServerName = ptr;
1747 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1748 ptr, outlen, NULL, NULL);
1749 ptr += len;
1750 outlen -= len;
1752 if (piW->pPrinterName) {
1753 piA->pPrinterName = ptr;
1754 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1755 ptr, outlen, NULL, NULL);
1756 ptr += len;
1757 outlen -= len;
1759 if (piW->pShareName) {
1760 piA->pShareName = ptr;
1761 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1762 ptr, outlen, NULL, NULL);
1763 ptr += len;
1764 outlen -= len;
1766 if (piW->pPortName) {
1767 piA->pPortName = ptr;
1768 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1769 ptr, outlen, NULL, NULL);
1770 ptr += len;
1771 outlen -= len;
1773 if (piW->pDriverName) {
1774 piA->pDriverName = ptr;
1775 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1776 ptr, outlen, NULL, NULL);
1777 ptr += len;
1778 outlen -= len;
1780 if (piW->pComment) {
1781 piA->pComment = ptr;
1782 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1783 ptr, outlen, NULL, NULL);
1784 ptr += len;
1785 outlen -= len;
1787 if (piW->pLocation) {
1788 piA->pLocation = ptr;
1789 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1790 ptr, outlen, NULL, NULL);
1791 ptr += len;
1792 outlen -= len;
1795 dmA = DEVMODEdupWtoA(piW->pDevMode);
1796 if (dmA) {
1797 /* align DEVMODEA to a DWORD boundary */
1798 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1799 ptr += len;
1800 outlen -= len;
1802 piA->pDevMode = (LPDEVMODEA) ptr;
1803 len = dmA->dmSize + dmA->dmDriverExtra;
1804 memcpy(ptr, dmA, len);
1805 HeapFree(GetProcessHeap(), 0, dmA);
1807 ptr += len;
1808 outlen -= len;
1811 if (piW->pSepFile) {
1812 piA->pSepFile = ptr;
1813 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1814 ptr, outlen, NULL, NULL);
1815 ptr += len;
1816 outlen -= len;
1818 if (piW->pPrintProcessor) {
1819 piA->pPrintProcessor = ptr;
1820 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1821 ptr, outlen, NULL, NULL);
1822 ptr += len;
1823 outlen -= len;
1825 if (piW->pDatatype) {
1826 piA->pDatatype = ptr;
1827 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1828 ptr, outlen, NULL, NULL);
1829 ptr += len;
1830 outlen -= len;
1832 if (piW->pParameters) {
1833 piA->pParameters = ptr;
1834 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1835 ptr, outlen, NULL, NULL);
1836 ptr += len;
1837 outlen -= len;
1839 if (piW->pSecurityDescriptor) {
1840 piA->pSecurityDescriptor = NULL;
1841 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1843 break;
1846 case 4:
1848 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1849 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1851 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1853 if (piW->pPrinterName) {
1854 piA->pPrinterName = ptr;
1855 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1856 ptr, outlen, NULL, NULL);
1857 ptr += len;
1858 outlen -= len;
1860 if (piW->pServerName) {
1861 piA->pServerName = ptr;
1862 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1863 ptr, outlen, NULL, NULL);
1864 ptr += len;
1865 outlen -= len;
1867 break;
1870 case 5:
1872 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1873 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1875 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1877 if (piW->pPrinterName) {
1878 piA->pPrinterName = ptr;
1879 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1880 ptr, outlen, NULL, NULL);
1881 ptr += len;
1882 outlen -= len;
1884 if (piW->pPortName) {
1885 piA->pPortName = ptr;
1886 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1887 ptr, outlen, NULL, NULL);
1888 ptr += len;
1889 outlen -= len;
1891 break;
1894 case 6: /* 6A and 6W are the same structure */
1895 break;
1897 case 7:
1899 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1900 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1902 TRACE("(%u) #%u\n", level, id);
1903 if (piW->pszObjectGUID) {
1904 piA->pszObjectGUID = ptr;
1905 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1906 ptr, outlen, NULL, NULL);
1907 ptr += len;
1908 outlen -= len;
1910 break;
1913 case 8:
1914 case 9:
1916 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1917 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1918 LPDEVMODEA dmA;
1920 TRACE("(%u) #%u\n", level, id);
1921 dmA = DEVMODEdupWtoA(piW->pDevMode);
1922 if (dmA) {
1923 /* align DEVMODEA to a DWORD boundary */
1924 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1925 ptr += len;
1926 outlen -= len;
1928 piA->pDevMode = (LPDEVMODEA) ptr;
1929 len = dmA->dmSize + dmA->dmDriverExtra;
1930 memcpy(ptr, dmA, len);
1931 HeapFree(GetProcessHeap(), 0, dmA);
1933 ptr += len;
1934 outlen -= len;
1937 break;
1940 default:
1941 FIXME("for level %u\n", level);
1943 pPrintersW += pi_sizeof[level];
1944 out += pi_sizeof[level];
1945 id++;
1949 /******************************************************************
1950 * convert_driverinfo_W_to_A [internal]
1953 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1954 DWORD level, DWORD outlen, DWORD numentries)
1956 DWORD id = 0;
1957 LPSTR ptr;
1958 INT len;
1960 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1962 len = di_sizeof[level] * numentries;
1963 ptr = (LPSTR) out + len;
1964 outlen -= len;
1966 /* copy the numbers of all PRINTER_INFO_* first */
1967 memcpy(out, pDriversW, len);
1969 #define COPY_STRING(fld) \
1970 { if (diW->fld){ \
1971 diA->fld = ptr; \
1972 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1973 ptr += len; outlen -= len;\
1975 #define COPY_MULTIZ_STRING(fld) \
1976 { LPWSTR p = diW->fld; if (p){ \
1977 diA->fld = ptr; \
1978 do {\
1979 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1980 ptr += len; outlen -= len; p += len;\
1982 while(len > 1 && outlen > 0); \
1985 while (id < numentries)
1987 switch (level)
1989 case 1:
1991 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1992 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1994 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1996 COPY_STRING(pName);
1997 break;
1999 case 2:
2001 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2002 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2004 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2006 COPY_STRING(pName);
2007 COPY_STRING(pEnvironment);
2008 COPY_STRING(pDriverPath);
2009 COPY_STRING(pDataFile);
2010 COPY_STRING(pConfigFile);
2011 break;
2013 case 3:
2015 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2016 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2018 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2020 COPY_STRING(pName);
2021 COPY_STRING(pEnvironment);
2022 COPY_STRING(pDriverPath);
2023 COPY_STRING(pDataFile);
2024 COPY_STRING(pConfigFile);
2025 COPY_STRING(pHelpFile);
2026 COPY_MULTIZ_STRING(pDependentFiles);
2027 COPY_STRING(pMonitorName);
2028 COPY_STRING(pDefaultDataType);
2029 break;
2031 case 4:
2033 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2034 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2036 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2038 COPY_STRING(pName);
2039 COPY_STRING(pEnvironment);
2040 COPY_STRING(pDriverPath);
2041 COPY_STRING(pDataFile);
2042 COPY_STRING(pConfigFile);
2043 COPY_STRING(pHelpFile);
2044 COPY_MULTIZ_STRING(pDependentFiles);
2045 COPY_STRING(pMonitorName);
2046 COPY_STRING(pDefaultDataType);
2047 COPY_MULTIZ_STRING(pszzPreviousNames);
2048 break;
2050 case 5:
2052 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2053 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2055 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2057 COPY_STRING(pName);
2058 COPY_STRING(pEnvironment);
2059 COPY_STRING(pDriverPath);
2060 COPY_STRING(pDataFile);
2061 COPY_STRING(pConfigFile);
2062 break;
2064 case 6:
2066 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2067 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) 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 break;
2087 case 8:
2089 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2090 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2092 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2094 COPY_STRING(pName);
2095 COPY_STRING(pEnvironment);
2096 COPY_STRING(pDriverPath);
2097 COPY_STRING(pDataFile);
2098 COPY_STRING(pConfigFile);
2099 COPY_STRING(pHelpFile);
2100 COPY_MULTIZ_STRING(pDependentFiles);
2101 COPY_STRING(pMonitorName);
2102 COPY_STRING(pDefaultDataType);
2103 COPY_MULTIZ_STRING(pszzPreviousNames);
2104 COPY_STRING(pszMfgName);
2105 COPY_STRING(pszOEMUrl);
2106 COPY_STRING(pszHardwareID);
2107 COPY_STRING(pszProvider);
2108 COPY_STRING(pszPrintProcessor);
2109 COPY_STRING(pszVendorSetup);
2110 COPY_MULTIZ_STRING(pszzColorProfiles);
2111 COPY_STRING(pszInfPath);
2112 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2113 break;
2117 default:
2118 FIXME("for level %u\n", level);
2121 pDriversW += di_sizeof[level];
2122 out += di_sizeof[level];
2123 id++;
2126 #undef COPY_STRING
2127 #undef COPY_MULTIZ_STRING
2131 /***********************************************************
2132 * printer_info_AtoW
2134 static void *printer_info_AtoW( const void *data, DWORD level )
2136 void *ret;
2137 UNICODE_STRING usBuffer;
2139 if (!data) return NULL;
2141 if (level < 1 || level > 9) return NULL;
2143 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2144 if (!ret) return NULL;
2146 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2148 switch (level)
2150 case 2:
2152 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2153 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2155 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2156 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2157 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2158 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2159 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2160 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2161 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2162 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2163 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2164 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2165 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2166 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2167 break;
2170 case 8:
2171 case 9:
2173 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2174 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2176 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2177 break;
2180 default:
2181 FIXME( "Unhandled level %d\n", level );
2182 HeapFree( GetProcessHeap(), 0, ret );
2183 return NULL;
2186 return ret;
2189 /***********************************************************
2190 * free_printer_info
2192 static void free_printer_info( void *data, DWORD level )
2194 if (!data) return;
2196 switch (level)
2198 case 2:
2200 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2202 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2203 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2204 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2205 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2206 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2207 HeapFree( GetProcessHeap(), 0, piW->pComment );
2208 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2209 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2210 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2211 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2212 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2213 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2214 break;
2217 case 8:
2218 case 9:
2220 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2222 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2223 break;
2226 default:
2227 FIXME( "Unhandled level %d\n", level );
2230 HeapFree( GetProcessHeap(), 0, data );
2231 return;
2234 /******************************************************************
2235 * DeviceCapabilities [WINSPOOL.@]
2236 * DeviceCapabilitiesA [WINSPOOL.@]
2239 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2240 LPSTR pOutput, LPDEVMODEA lpdm)
2242 INT ret;
2244 if (!GDI_CallDeviceCapabilities16)
2246 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2247 (LPCSTR)104 );
2248 if (!GDI_CallDeviceCapabilities16) return -1;
2250 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2252 /* If DC_PAPERSIZE map POINT16s to POINTs */
2253 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2254 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2255 POINT *pt = (POINT *)pOutput;
2256 INT i;
2257 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2258 for(i = 0; i < ret; i++, pt++)
2260 pt->x = tmp[i].x;
2261 pt->y = tmp[i].y;
2263 HeapFree( GetProcessHeap(), 0, tmp );
2265 return ret;
2269 /*****************************************************************************
2270 * DeviceCapabilitiesW [WINSPOOL.@]
2272 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2275 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2276 WORD fwCapability, LPWSTR pOutput,
2277 const DEVMODEW *pDevMode)
2279 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2280 LPSTR pDeviceA = strdupWtoA(pDevice);
2281 LPSTR pPortA = strdupWtoA(pPort);
2282 INT ret;
2284 if(pOutput && (fwCapability == DC_BINNAMES ||
2285 fwCapability == DC_FILEDEPENDENCIES ||
2286 fwCapability == DC_PAPERNAMES)) {
2287 /* These need A -> W translation */
2288 INT size = 0, i;
2289 LPSTR pOutputA;
2290 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2291 dmA);
2292 if(ret == -1)
2293 return ret;
2294 switch(fwCapability) {
2295 case DC_BINNAMES:
2296 size = 24;
2297 break;
2298 case DC_PAPERNAMES:
2299 case DC_FILEDEPENDENCIES:
2300 size = 64;
2301 break;
2303 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2304 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2305 dmA);
2306 for(i = 0; i < ret; i++)
2307 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2308 pOutput + (i * size), size);
2309 HeapFree(GetProcessHeap(), 0, pOutputA);
2310 } else {
2311 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2312 (LPSTR)pOutput, dmA);
2314 HeapFree(GetProcessHeap(),0,pPortA);
2315 HeapFree(GetProcessHeap(),0,pDeviceA);
2316 HeapFree(GetProcessHeap(),0,dmA);
2317 return ret;
2320 /******************************************************************
2321 * DocumentPropertiesA [WINSPOOL.@]
2323 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2325 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2326 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2327 LPDEVMODEA pDevModeInput,DWORD fMode )
2329 LPSTR lpName = pDeviceName;
2330 static CHAR port[] = "LPT1:";
2331 LONG ret;
2333 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2334 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2337 if(!pDeviceName) {
2338 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2339 if(!lpNameW) {
2340 ERR("no name from hPrinter?\n");
2341 SetLastError(ERROR_INVALID_HANDLE);
2342 return -1;
2344 lpName = strdupWtoA(lpNameW);
2347 if (!GDI_CallExtDeviceMode16)
2349 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2350 (LPCSTR)102 );
2351 if (!GDI_CallExtDeviceMode16) {
2352 ERR("No CallExtDeviceMode16?\n");
2353 return -1;
2356 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2357 pDevModeInput, NULL, fMode);
2359 if(!pDeviceName)
2360 HeapFree(GetProcessHeap(),0,lpName);
2361 return ret;
2365 /*****************************************************************************
2366 * DocumentPropertiesW (WINSPOOL.@)
2368 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2370 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2371 LPWSTR pDeviceName,
2372 LPDEVMODEW pDevModeOutput,
2373 LPDEVMODEW pDevModeInput, DWORD fMode)
2376 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2377 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2378 LPDEVMODEA pDevModeOutputA = NULL;
2379 LONG ret;
2381 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2382 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2383 fMode);
2384 if(pDevModeOutput) {
2385 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2386 if(ret < 0) return ret;
2387 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2389 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2390 pDevModeInputA, fMode);
2391 if(pDevModeOutput) {
2392 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2393 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2395 if(fMode == 0 && ret > 0)
2396 ret += (CCHDEVICENAME + CCHFORMNAME);
2397 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2398 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2399 return ret;
2402 /*****************************************************************************
2403 * IsValidDevmodeA [WINSPOOL.@]
2405 * Validate a DEVMODE structure and fix errors if possible.
2408 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2410 FIXME("(%p,%ld): stub\n", pDevMode, size);
2412 if(!pDevMode)
2413 return FALSE;
2415 return TRUE;
2418 /*****************************************************************************
2419 * IsValidDevmodeW [WINSPOOL.@]
2421 * Validate a DEVMODE structure and fix errors if possible.
2424 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2426 FIXME("(%p,%ld): stub\n", pDevMode, size);
2428 if(!pDevMode)
2429 return FALSE;
2431 return TRUE;
2434 /******************************************************************
2435 * OpenPrinterA [WINSPOOL.@]
2437 * See OpenPrinterW.
2440 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2441 LPPRINTER_DEFAULTSA pDefault)
2443 UNICODE_STRING lpPrinterNameW;
2444 UNICODE_STRING usBuffer;
2445 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2446 PWSTR pwstrPrinterNameW;
2447 BOOL ret;
2449 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2451 if(pDefault) {
2452 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2453 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2454 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2455 pDefaultW = &DefaultW;
2457 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2458 if(pDefault) {
2459 RtlFreeUnicodeString(&usBuffer);
2460 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2462 RtlFreeUnicodeString(&lpPrinterNameW);
2463 return ret;
2466 /******************************************************************
2467 * OpenPrinterW [WINSPOOL.@]
2469 * Open a Printer / Printserver or a Printer-Object
2471 * PARAMS
2472 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2473 * phPrinter [O] The resulting Handle is stored here
2474 * pDefault [I] PTR to Default Printer Settings or NULL
2476 * RETURNS
2477 * Success: TRUE
2478 * Failure: FALSE
2480 * NOTES
2481 * lpPrinterName is one of:
2482 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2483 *| Printer: "PrinterName"
2484 *| Printer-Object: "PrinterName,Job xxx"
2485 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2486 *| XcvPort: "Servername,XcvPort PortName"
2488 * BUGS
2489 *| Printer-Object not supported
2490 *| pDefaults is ignored
2493 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2496 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2498 if(!phPrinter) {
2499 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2500 SetLastError(ERROR_INVALID_PARAMETER);
2501 return FALSE;
2504 /* Get the unique handle of the printer or Printserver */
2505 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2507 if (*phPrinter)
2509 HKEY key;
2510 DWORD deleting = 0, size = sizeof( deleting ), type;
2511 DWORD status;
2512 WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key );
2513 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2514 WaitForSingleObject( init_mutex, INFINITE );
2515 status = get_dword_from_reg( key, StatusW );
2516 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2517 ReleaseMutex( init_mutex );
2518 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2519 update_driver( *phPrinter );
2520 RegCloseKey( key );
2523 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2524 return (*phPrinter != 0);
2527 /******************************************************************
2528 * AddMonitorA [WINSPOOL.@]
2530 * See AddMonitorW.
2533 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2535 LPWSTR nameW = NULL;
2536 INT len;
2537 BOOL res;
2538 LPMONITOR_INFO_2A mi2a;
2539 MONITOR_INFO_2W mi2w;
2541 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2542 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2543 debugstr_a(mi2a ? mi2a->pName : NULL),
2544 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2545 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2547 if (Level != 2) {
2548 SetLastError(ERROR_INVALID_LEVEL);
2549 return FALSE;
2552 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2553 if (mi2a == NULL) {
2554 return FALSE;
2557 if (pName) {
2558 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2559 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2560 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2563 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2564 if (mi2a->pName) {
2565 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2566 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2567 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2569 if (mi2a->pEnvironment) {
2570 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2571 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2572 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2574 if (mi2a->pDLLName) {
2575 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2576 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2577 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2580 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2582 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2583 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2584 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2586 HeapFree(GetProcessHeap(), 0, nameW);
2587 return (res);
2590 /******************************************************************************
2591 * AddMonitorW [WINSPOOL.@]
2593 * Install a Printmonitor
2595 * PARAMS
2596 * pName [I] Servername or NULL (local Computer)
2597 * Level [I] Structure-Level (Must be 2)
2598 * pMonitors [I] PTR to MONITOR_INFO_2
2600 * RETURNS
2601 * Success: TRUE
2602 * Failure: FALSE
2604 * NOTES
2605 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2608 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2610 LPMONITOR_INFO_2W mi2w;
2612 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2613 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2614 debugstr_w(mi2w ? mi2w->pName : NULL),
2615 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2616 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2618 if ((backend == NULL) && !load_backend()) return FALSE;
2620 if (Level != 2) {
2621 SetLastError(ERROR_INVALID_LEVEL);
2622 return FALSE;
2625 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2626 if (mi2w == NULL) {
2627 return FALSE;
2630 return backend->fpAddMonitor(pName, Level, pMonitors);
2633 /******************************************************************
2634 * DeletePrinterDriverA [WINSPOOL.@]
2637 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2639 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2642 /******************************************************************
2643 * DeletePrinterDriverW [WINSPOOL.@]
2646 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2648 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2651 /******************************************************************
2652 * DeleteMonitorA [WINSPOOL.@]
2654 * See DeleteMonitorW.
2657 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2659 LPWSTR nameW = NULL;
2660 LPWSTR EnvironmentW = NULL;
2661 LPWSTR MonitorNameW = NULL;
2662 BOOL res;
2663 INT len;
2665 if (pName) {
2666 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2667 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2668 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2671 if (pEnvironment) {
2672 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2673 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2674 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2676 if (pMonitorName) {
2677 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2678 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2679 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2682 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2684 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2685 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2686 HeapFree(GetProcessHeap(), 0, nameW);
2687 return (res);
2690 /******************************************************************
2691 * DeleteMonitorW [WINSPOOL.@]
2693 * Delete a specific Printmonitor from a Printing-Environment
2695 * PARAMS
2696 * pName [I] Servername or NULL (local Computer)
2697 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2698 * pMonitorName [I] Name of the Monitor, that should be deleted
2700 * RETURNS
2701 * Success: TRUE
2702 * Failure: FALSE
2704 * NOTES
2705 * pEnvironment is ignored in Windows for the local Computer.
2708 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2711 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2712 debugstr_w(pMonitorName));
2714 if ((backend == NULL) && !load_backend()) return FALSE;
2716 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2720 /******************************************************************
2721 * DeletePortA [WINSPOOL.@]
2723 * See DeletePortW.
2726 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2728 LPWSTR nameW = NULL;
2729 LPWSTR portW = NULL;
2730 INT len;
2731 DWORD res;
2733 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2735 /* convert servername to unicode */
2736 if (pName) {
2737 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2738 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2739 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2742 /* convert portname to unicode */
2743 if (pPortName) {
2744 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2745 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2746 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2749 res = DeletePortW(nameW, hWnd, portW);
2750 HeapFree(GetProcessHeap(), 0, nameW);
2751 HeapFree(GetProcessHeap(), 0, portW);
2752 return res;
2755 /******************************************************************
2756 * DeletePortW [WINSPOOL.@]
2758 * Delete a specific Port
2760 * PARAMS
2761 * pName [I] Servername or NULL (local Computer)
2762 * hWnd [I] Handle to parent Window for the Dialog-Box
2763 * pPortName [I] Name of the Port, that should be deleted
2765 * RETURNS
2766 * Success: TRUE
2767 * Failure: FALSE
2770 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2772 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2774 if ((backend == NULL) && !load_backend()) return FALSE;
2776 if (!pPortName) {
2777 SetLastError(RPC_X_NULL_REF_POINTER);
2778 return FALSE;
2781 return backend->fpDeletePort(pName, hWnd, pPortName);
2784 /******************************************************************************
2785 * WritePrinter [WINSPOOL.@]
2787 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2789 opened_printer_t *printer;
2790 BOOL ret = FALSE;
2792 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2794 EnterCriticalSection(&printer_handles_cs);
2795 printer = get_opened_printer(hPrinter);
2796 if(!printer)
2798 SetLastError(ERROR_INVALID_HANDLE);
2799 goto end;
2802 if(!printer->doc)
2804 SetLastError(ERROR_SPL_NO_STARTDOC);
2805 goto end;
2808 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2809 end:
2810 LeaveCriticalSection(&printer_handles_cs);
2811 return ret;
2814 /*****************************************************************************
2815 * AddFormA [WINSPOOL.@]
2817 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2819 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2820 return 1;
2823 /*****************************************************************************
2824 * AddFormW [WINSPOOL.@]
2826 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2828 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2829 return 1;
2832 /*****************************************************************************
2833 * AddJobA [WINSPOOL.@]
2835 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2837 BOOL ret;
2838 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2839 DWORD needed;
2841 if(Level != 1) {
2842 SetLastError(ERROR_INVALID_LEVEL);
2843 return FALSE;
2846 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2848 if(ret) {
2849 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2850 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2851 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2852 if(*pcbNeeded > cbBuf) {
2853 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2854 ret = FALSE;
2855 } else {
2856 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2857 addjobA->JobId = addjobW->JobId;
2858 addjobA->Path = (char *)(addjobA + 1);
2859 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2862 return ret;
2865 /*****************************************************************************
2866 * AddJobW [WINSPOOL.@]
2868 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2870 opened_printer_t *printer;
2871 job_t *job;
2872 BOOL ret = FALSE;
2873 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2874 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2875 WCHAR path[MAX_PATH], filename[MAX_PATH];
2876 DWORD len;
2877 ADDJOB_INFO_1W *addjob;
2879 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2881 EnterCriticalSection(&printer_handles_cs);
2883 printer = get_opened_printer(hPrinter);
2885 if(!printer) {
2886 SetLastError(ERROR_INVALID_HANDLE);
2887 goto end;
2890 if(Level != 1) {
2891 SetLastError(ERROR_INVALID_LEVEL);
2892 goto end;
2895 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2896 if(!job)
2897 goto end;
2899 job->job_id = InterlockedIncrement(&next_job_id);
2901 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2902 if(path[len - 1] != '\\')
2903 path[len++] = '\\';
2904 memcpy(path + len, spool_path, sizeof(spool_path));
2905 sprintfW(filename, fmtW, path, job->job_id);
2907 len = strlenW(filename);
2908 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2909 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2910 job->portname = NULL;
2911 job->document_title = strdupW(default_doc_title);
2912 job->printer_name = strdupW(printer->name);
2913 job->devmode = dup_devmode( printer->devmode );
2914 list_add_tail(&printer->queue->jobs, &job->entry);
2916 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2917 if(*pcbNeeded <= cbBuf) {
2918 addjob = (ADDJOB_INFO_1W*)pData;
2919 addjob->JobId = job->job_id;
2920 addjob->Path = (WCHAR *)(addjob + 1);
2921 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2922 ret = TRUE;
2923 } else
2924 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2926 end:
2927 LeaveCriticalSection(&printer_handles_cs);
2928 return ret;
2931 /*****************************************************************************
2932 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2934 * Return the PATH for the Print-Processors
2936 * See GetPrintProcessorDirectoryW.
2940 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2941 DWORD level, LPBYTE Info,
2942 DWORD cbBuf, LPDWORD pcbNeeded)
2944 LPWSTR serverW = NULL;
2945 LPWSTR envW = NULL;
2946 BOOL ret;
2947 INT len;
2949 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2950 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2953 if (server) {
2954 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2955 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2956 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2959 if (env) {
2960 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2961 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2962 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2965 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2966 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2968 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2969 cbBuf, pcbNeeded);
2971 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2972 cbBuf, NULL, NULL) > 0;
2975 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2976 HeapFree(GetProcessHeap(), 0, envW);
2977 HeapFree(GetProcessHeap(), 0, serverW);
2978 return ret;
2981 /*****************************************************************************
2982 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2984 * Return the PATH for the Print-Processors
2986 * PARAMS
2987 * server [I] Servername (NT only) or NULL (local Computer)
2988 * env [I] Printing-Environment (see below) or NULL (Default)
2989 * level [I] Structure-Level (must be 1)
2990 * Info [O] PTR to Buffer that receives the Result
2991 * cbBuf [I] Size of Buffer at "Info"
2992 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2993 * required for the Buffer at "Info"
2995 * RETURNS
2996 * Success: TRUE and in pcbNeeded the Bytes used in Info
2997 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2998 * if cbBuf is too small
3000 * Native Values returned in Info on Success:
3001 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3002 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3003 *| win9x(Windows 4.0): "%winsysdir%"
3005 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3007 * BUGS
3008 * Only NULL or "" is supported for server
3011 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3012 DWORD level, LPBYTE Info,
3013 DWORD cbBuf, LPDWORD pcbNeeded)
3016 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3017 Info, cbBuf, pcbNeeded);
3019 if ((backend == NULL) && !load_backend()) return FALSE;
3021 if (level != 1) {
3022 /* (Level != 1) is ignored in win9x */
3023 SetLastError(ERROR_INVALID_LEVEL);
3024 return FALSE;
3027 if (pcbNeeded == NULL) {
3028 /* (pcbNeeded == NULL) is ignored in win9x */
3029 SetLastError(RPC_X_NULL_REF_POINTER);
3030 return FALSE;
3033 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3036 /*****************************************************************************
3037 * WINSPOOL_OpenDriverReg [internal]
3039 * opens the registry for the printer drivers depending on the given input
3040 * variable pEnvironment
3042 * RETURNS:
3043 * the opened hkey on success
3044 * NULL on error
3046 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3048 HKEY retval = NULL;
3049 LPWSTR buffer;
3050 const printenv_t * env;
3052 TRACE("(%s)\n", debugstr_w(pEnvironment));
3054 env = validate_envW(pEnvironment);
3055 if (!env) return NULL;
3057 buffer = HeapAlloc( GetProcessHeap(), 0,
3058 (strlenW(DriversW) + strlenW(env->envname) +
3059 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3060 if(buffer) {
3061 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3062 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3063 HeapFree(GetProcessHeap(), 0, buffer);
3065 return retval;
3068 /*****************************************************************************
3069 * set_devices_and_printerports [internal]
3071 * set the [Devices] and [PrinterPorts] entries for a printer.
3074 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3076 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3077 WCHAR *devline;
3078 HKEY hkey;
3080 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3082 /* FIXME: the driver must change to "winspool" */
3083 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3084 if (devline) {
3085 lstrcpyW(devline, driver_nt);
3086 lstrcatW(devline, commaW);
3087 lstrcatW(devline, pi->pPortName);
3089 TRACE("using %s\n", debugstr_w(devline));
3090 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
3091 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3092 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3093 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3094 RegCloseKey(hkey);
3097 lstrcatW(devline, timeout_15_45);
3098 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
3099 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3100 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3101 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3102 RegCloseKey(hkey);
3104 HeapFree(GetProcessHeap(), 0, devline);
3108 /*****************************************************************************
3109 * AddPrinterW [WINSPOOL.@]
3111 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3113 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3114 LPDEVMODEW dm;
3115 HANDLE retval;
3116 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3117 LONG size;
3119 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3121 if(pName != NULL) {
3122 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3123 SetLastError(ERROR_INVALID_PARAMETER);
3124 return 0;
3126 if(Level != 2) {
3127 ERR("Level = %d, unsupported!\n", Level);
3128 SetLastError(ERROR_INVALID_LEVEL);
3129 return 0;
3131 if(!pPrinter) {
3132 SetLastError(ERROR_INVALID_PARAMETER);
3133 return 0;
3135 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3136 ERROR_SUCCESS) {
3137 ERR("Can't create Printers key\n");
3138 return 0;
3140 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3141 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3142 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3143 RegCloseKey(hkeyPrinter);
3144 RegCloseKey(hkeyPrinters);
3145 return 0;
3147 RegCloseKey(hkeyPrinter);
3149 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3150 if(!hkeyDrivers) {
3151 ERR("Can't create Drivers key\n");
3152 RegCloseKey(hkeyPrinters);
3153 return 0;
3155 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3156 ERROR_SUCCESS) {
3157 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3158 RegCloseKey(hkeyPrinters);
3159 RegCloseKey(hkeyDrivers);
3160 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3161 return 0;
3163 RegCloseKey(hkeyDriver);
3164 RegCloseKey(hkeyDrivers);
3166 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3167 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3168 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3169 RegCloseKey(hkeyPrinters);
3170 return 0;
3173 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3174 ERROR_SUCCESS) {
3175 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3176 SetLastError(ERROR_INVALID_PRINTER_NAME);
3177 RegCloseKey(hkeyPrinters);
3178 return 0;
3181 set_devices_and_printerports(pi);
3183 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3184 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3185 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3186 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3187 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3188 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3189 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3190 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3191 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3192 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3193 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3194 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3195 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3196 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3197 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3198 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3199 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3200 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3202 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3204 if (size < 0)
3206 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3207 size = sizeof(DEVMODEW);
3209 if(pi->pDevMode)
3210 dm = pi->pDevMode;
3211 else
3213 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3214 dm->dmSize = size;
3215 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3217 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3218 HeapFree( GetProcessHeap(), 0, dm );
3219 dm = NULL;
3221 else
3223 /* set devmode to printer name */
3224 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3228 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3229 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3231 RegCloseKey(hkeyPrinter);
3232 RegCloseKey(hkeyPrinters);
3233 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3234 ERR("OpenPrinter failing\n");
3235 return 0;
3237 return retval;
3240 /*****************************************************************************
3241 * AddPrinterA [WINSPOOL.@]
3243 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3245 UNICODE_STRING pNameW;
3246 PWSTR pwstrNameW;
3247 PRINTER_INFO_2W *piW;
3248 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3249 HANDLE ret;
3251 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3252 if(Level != 2) {
3253 ERR("Level = %d, unsupported!\n", Level);
3254 SetLastError(ERROR_INVALID_LEVEL);
3255 return 0;
3257 pwstrNameW = asciitounicode(&pNameW,pName);
3258 piW = printer_info_AtoW( piA, Level );
3260 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3262 free_printer_info( piW, Level );
3263 RtlFreeUnicodeString(&pNameW);
3264 return ret;
3268 /*****************************************************************************
3269 * ClosePrinter [WINSPOOL.@]
3271 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3273 UINT_PTR i = (UINT_PTR)hPrinter;
3274 opened_printer_t *printer = NULL;
3275 BOOL ret = FALSE;
3277 TRACE("(%p)\n", hPrinter);
3279 EnterCriticalSection(&printer_handles_cs);
3281 if ((i > 0) && (i <= nb_printer_handles))
3282 printer = printer_handles[i - 1];
3285 if(printer)
3287 struct list *cursor, *cursor2;
3289 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3291 if (printer->backend_printer) {
3292 backend->fpClosePrinter(printer->backend_printer);
3295 if(printer->doc)
3296 EndDocPrinter(hPrinter);
3298 if(InterlockedDecrement(&printer->queue->ref) == 0)
3300 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3302 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3303 ScheduleJob(hPrinter, job->job_id);
3305 HeapFree(GetProcessHeap(), 0, printer->queue);
3308 free_printer_entry( printer );
3309 printer_handles[i - 1] = NULL;
3310 ret = TRUE;
3312 LeaveCriticalSection(&printer_handles_cs);
3313 return ret;
3316 /*****************************************************************************
3317 * DeleteFormA [WINSPOOL.@]
3319 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3321 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3322 return 1;
3325 /*****************************************************************************
3326 * DeleteFormW [WINSPOOL.@]
3328 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3330 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3331 return 1;
3334 /*****************************************************************************
3335 * DeletePrinter [WINSPOOL.@]
3337 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3339 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3340 HKEY hkeyPrinters, hkey;
3341 WCHAR def[MAX_PATH];
3342 DWORD size = sizeof( def ) / sizeof( def[0] );
3344 if(!lpNameW) {
3345 SetLastError(ERROR_INVALID_HANDLE);
3346 return FALSE;
3348 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3349 RegDeleteTreeW(hkeyPrinters, lpNameW);
3350 RegCloseKey(hkeyPrinters);
3352 WriteProfileStringW(devicesW, lpNameW, NULL);
3353 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3355 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3356 RegDeleteValueW(hkey, lpNameW);
3357 RegCloseKey(hkey);
3360 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3361 RegDeleteValueW(hkey, lpNameW);
3362 RegCloseKey(hkey);
3365 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3367 WriteProfileStringW( windowsW, deviceW, NULL );
3368 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3370 RegDeleteValueW( hkey, deviceW );
3371 RegCloseKey( hkey );
3373 SetDefaultPrinterW( NULL );
3376 return TRUE;
3379 /*****************************************************************************
3380 * SetPrinterA [WINSPOOL.@]
3382 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3384 BYTE *dataW = data;
3385 BOOL ret;
3387 if (level != 0)
3389 dataW = printer_info_AtoW( data, level );
3390 if (!dataW) return FALSE;
3393 ret = SetPrinterW( printer, level, dataW, command );
3395 if (dataW != data) free_printer_info( dataW, level );
3397 return ret;
3400 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3402 set_reg_szW( key, NameW, pi->pPrinterName );
3403 set_reg_szW( key, Share_NameW, pi->pShareName );
3404 set_reg_szW( key, PortW, pi->pPortName );
3405 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3406 set_reg_szW( key, DescriptionW, pi->pComment );
3407 set_reg_szW( key, LocationW, pi->pLocation );
3409 if (pi->pDevMode)
3410 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3412 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3413 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3414 set_reg_szW( key, DatatypeW, pi->pDatatype );
3415 set_reg_szW( key, ParametersW, pi->pParameters );
3417 set_reg_DWORD( key, AttributesW, pi->Attributes );
3418 set_reg_DWORD( key, PriorityW, pi->Priority );
3419 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3420 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3421 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3424 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3426 if (!pi->pDevMode) return FALSE;
3428 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3429 return TRUE;
3432 /******************************************************************************
3433 * SetPrinterW [WINSPOOL.@]
3435 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3437 HKEY key;
3438 BOOL ret = FALSE;
3440 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3442 if (command != 0) FIXME( "Ignoring command %d\n", command );
3444 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3445 return FALSE;
3447 switch (level)
3449 case 2:
3451 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3452 set_printer_2( key, pi2 );
3453 ret = TRUE;
3454 break;
3457 case 9:
3459 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3460 ret = set_printer_9( key, pi );
3461 break;
3464 default:
3465 FIXME( "Unimplemented level %d\n", level );
3466 SetLastError( ERROR_INVALID_LEVEL );
3469 RegCloseKey( key );
3470 return ret;
3473 /*****************************************************************************
3474 * SetJobA [WINSPOOL.@]
3476 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3477 LPBYTE pJob, DWORD Command)
3479 BOOL ret;
3480 LPBYTE JobW;
3481 UNICODE_STRING usBuffer;
3483 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3485 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3486 are all ignored by SetJob, so we don't bother copying them */
3487 switch(Level)
3489 case 0:
3490 JobW = NULL;
3491 break;
3492 case 1:
3494 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3495 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3497 JobW = (LPBYTE)info1W;
3498 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3499 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3500 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3501 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3502 info1W->Status = info1A->Status;
3503 info1W->Priority = info1A->Priority;
3504 info1W->Position = info1A->Position;
3505 info1W->PagesPrinted = info1A->PagesPrinted;
3506 break;
3508 case 2:
3510 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3511 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3513 JobW = (LPBYTE)info2W;
3514 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3515 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3516 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3517 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3518 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3519 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3520 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3521 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3522 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3523 info2W->Status = info2A->Status;
3524 info2W->Priority = info2A->Priority;
3525 info2W->Position = info2A->Position;
3526 info2W->StartTime = info2A->StartTime;
3527 info2W->UntilTime = info2A->UntilTime;
3528 info2W->PagesPrinted = info2A->PagesPrinted;
3529 break;
3531 case 3:
3532 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3533 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3534 break;
3535 default:
3536 SetLastError(ERROR_INVALID_LEVEL);
3537 return FALSE;
3540 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3542 switch(Level)
3544 case 1:
3546 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3547 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3548 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3549 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3550 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3551 break;
3553 case 2:
3555 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3556 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3557 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3558 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3559 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3560 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3561 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3562 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3563 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3564 break;
3567 HeapFree(GetProcessHeap(), 0, JobW);
3569 return ret;
3572 /*****************************************************************************
3573 * SetJobW [WINSPOOL.@]
3575 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3576 LPBYTE pJob, DWORD Command)
3578 BOOL ret = FALSE;
3579 job_t *job;
3581 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3582 FIXME("Ignoring everything other than document title\n");
3584 EnterCriticalSection(&printer_handles_cs);
3585 job = get_job(hPrinter, JobId);
3586 if(!job)
3587 goto end;
3589 switch(Level)
3591 case 0:
3592 break;
3593 case 1:
3595 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3596 HeapFree(GetProcessHeap(), 0, job->document_title);
3597 job->document_title = strdupW(info1->pDocument);
3598 break;
3600 case 2:
3602 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3603 HeapFree(GetProcessHeap(), 0, job->document_title);
3604 job->document_title = strdupW(info2->pDocument);
3605 HeapFree(GetProcessHeap(), 0, job->devmode);
3606 job->devmode = dup_devmode( info2->pDevMode );
3607 break;
3609 case 3:
3610 break;
3611 default:
3612 SetLastError(ERROR_INVALID_LEVEL);
3613 goto end;
3615 ret = TRUE;
3616 end:
3617 LeaveCriticalSection(&printer_handles_cs);
3618 return ret;
3621 /*****************************************************************************
3622 * EndDocPrinter [WINSPOOL.@]
3624 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3626 opened_printer_t *printer;
3627 BOOL ret = FALSE;
3628 TRACE("(%p)\n", hPrinter);
3630 EnterCriticalSection(&printer_handles_cs);
3632 printer = get_opened_printer(hPrinter);
3633 if(!printer)
3635 SetLastError(ERROR_INVALID_HANDLE);
3636 goto end;
3639 if(!printer->doc)
3641 SetLastError(ERROR_SPL_NO_STARTDOC);
3642 goto end;
3645 CloseHandle(printer->doc->hf);
3646 ScheduleJob(hPrinter, printer->doc->job_id);
3647 HeapFree(GetProcessHeap(), 0, printer->doc);
3648 printer->doc = NULL;
3649 ret = TRUE;
3650 end:
3651 LeaveCriticalSection(&printer_handles_cs);
3652 return ret;
3655 /*****************************************************************************
3656 * EndPagePrinter [WINSPOOL.@]
3658 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3660 FIXME("(%p): stub\n", hPrinter);
3661 return TRUE;
3664 /*****************************************************************************
3665 * StartDocPrinterA [WINSPOOL.@]
3667 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3669 UNICODE_STRING usBuffer;
3670 DOC_INFO_2W doc2W;
3671 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3672 DWORD ret;
3674 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3675 or one (DOC_INFO_3) extra DWORDs */
3677 switch(Level) {
3678 case 2:
3679 doc2W.JobId = doc2->JobId;
3680 /* fall through */
3681 case 3:
3682 doc2W.dwMode = doc2->dwMode;
3683 /* fall through */
3684 case 1:
3685 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3686 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3687 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3688 break;
3690 default:
3691 SetLastError(ERROR_INVALID_LEVEL);
3692 return FALSE;
3695 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3697 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3698 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3699 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3701 return ret;
3704 /*****************************************************************************
3705 * StartDocPrinterW [WINSPOOL.@]
3707 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3709 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3710 opened_printer_t *printer;
3711 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3712 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3713 JOB_INFO_1W job_info;
3714 DWORD needed, ret = 0;
3715 HANDLE hf;
3716 WCHAR *filename;
3717 job_t *job;
3719 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3720 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3721 debugstr_w(doc->pDatatype));
3723 if(Level < 1 || Level > 3)
3725 SetLastError(ERROR_INVALID_LEVEL);
3726 return 0;
3729 EnterCriticalSection(&printer_handles_cs);
3730 printer = get_opened_printer(hPrinter);
3731 if(!printer)
3733 SetLastError(ERROR_INVALID_HANDLE);
3734 goto end;
3737 if(printer->doc)
3739 SetLastError(ERROR_INVALID_PRINTER_STATE);
3740 goto end;
3743 /* Even if we're printing to a file we still add a print job, we'll
3744 just ignore the spool file name */
3746 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3748 ERR("AddJob failed gle %u\n", GetLastError());
3749 goto end;
3752 /* use pOutputFile only, when it is a real filename */
3753 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3754 filename = doc->pOutputFile;
3755 else
3756 filename = addjob->Path;
3758 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3759 if(hf == INVALID_HANDLE_VALUE)
3760 goto end;
3762 memset(&job_info, 0, sizeof(job_info));
3763 job_info.pDocument = doc->pDocName;
3764 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3766 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3767 printer->doc->hf = hf;
3768 ret = printer->doc->job_id = addjob->JobId;
3769 job = get_job(hPrinter, ret);
3770 job->portname = strdupW(doc->pOutputFile);
3772 end:
3773 LeaveCriticalSection(&printer_handles_cs);
3775 return ret;
3778 /*****************************************************************************
3779 * StartPagePrinter [WINSPOOL.@]
3781 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3783 FIXME("(%p): stub\n", hPrinter);
3784 return TRUE;
3787 /*****************************************************************************
3788 * GetFormA [WINSPOOL.@]
3790 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3791 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3793 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3794 Level,pForm,cbBuf,pcbNeeded);
3795 return FALSE;
3798 /*****************************************************************************
3799 * GetFormW [WINSPOOL.@]
3801 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3802 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3804 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3805 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3806 return FALSE;
3809 /*****************************************************************************
3810 * SetFormA [WINSPOOL.@]
3812 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3813 LPBYTE pForm)
3815 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3816 return FALSE;
3819 /*****************************************************************************
3820 * SetFormW [WINSPOOL.@]
3822 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3823 LPBYTE pForm)
3825 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3826 return FALSE;
3829 /*****************************************************************************
3830 * ReadPrinter [WINSPOOL.@]
3832 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3833 LPDWORD pNoBytesRead)
3835 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3836 return FALSE;
3839 /*****************************************************************************
3840 * ResetPrinterA [WINSPOOL.@]
3842 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3844 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3845 return FALSE;
3848 /*****************************************************************************
3849 * ResetPrinterW [WINSPOOL.@]
3851 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3853 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3854 return FALSE;
3857 /*****************************************************************************
3858 * get_filename_from_reg [internal]
3860 * Get ValueName from hkey storing result in out
3861 * when the Value in the registry has only a filename, use driverdir as prefix
3862 * outlen is space left in out
3863 * String is stored either as unicode or ascii
3867 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3868 LPBYTE out, DWORD outlen, LPDWORD needed)
3870 WCHAR filename[MAX_PATH];
3871 DWORD size;
3872 DWORD type;
3873 LONG ret;
3874 LPWSTR buffer = filename;
3875 LPWSTR ptr;
3877 *needed = 0;
3878 size = sizeof(filename);
3879 buffer[0] = '\0';
3880 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3881 if (ret == ERROR_MORE_DATA) {
3882 TRACE("need dynamic buffer: %u\n", size);
3883 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3884 if (!buffer) {
3885 /* No Memory is bad */
3886 return FALSE;
3888 buffer[0] = '\0';
3889 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3892 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3893 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3894 return FALSE;
3897 ptr = buffer;
3898 while (ptr) {
3899 /* do we have a full path ? */
3900 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3901 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3903 if (!ret) {
3904 /* we must build the full Path */
3905 *needed += dirlen;
3906 if ((out) && (outlen > dirlen)) {
3907 lstrcpyW((LPWSTR)out, driverdir);
3908 out += dirlen;
3909 outlen -= dirlen;
3911 else
3912 out = NULL;
3915 /* write the filename */
3916 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3917 if ((out) && (outlen >= size)) {
3918 lstrcpyW((LPWSTR)out, ptr);
3919 out += size;
3920 outlen -= size;
3922 else
3923 out = NULL;
3924 *needed += size;
3925 ptr += lstrlenW(ptr)+1;
3926 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3929 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3931 /* write the multisz-termination */
3932 if (type == REG_MULTI_SZ) {
3933 size = sizeof(WCHAR);
3935 *needed += size;
3936 if (out && (outlen >= size)) {
3937 memset (out, 0, size);
3940 return TRUE;
3943 /*****************************************************************************
3944 * WINSPOOL_GetStringFromReg
3946 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3947 * String is stored as unicode.
3949 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3950 DWORD buflen, DWORD *needed)
3952 DWORD sz = buflen, type;
3953 LONG ret;
3955 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3956 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3957 WARN("Got ret = %d\n", ret);
3958 *needed = 0;
3959 return FALSE;
3961 /* add space for terminating '\0' */
3962 sz += sizeof(WCHAR);
3963 *needed = sz;
3965 if (ptr)
3966 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3968 return TRUE;
3971 /*****************************************************************************
3972 * WINSPOOL_GetDefaultDevMode
3974 * Get a default DevMode values for wineps.
3975 * FIXME - use ppd.
3978 static void WINSPOOL_GetDefaultDevMode(
3979 LPBYTE ptr,
3980 DWORD buflen, DWORD *needed)
3982 DEVMODEW dm;
3983 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3985 /* fill default DEVMODE - should be read from ppd... */
3986 ZeroMemory( &dm, sizeof(dm) );
3987 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3988 dm.dmSpecVersion = DM_SPECVERSION;
3989 dm.dmDriverVersion = 1;
3990 dm.dmSize = sizeof(DEVMODEW);
3991 dm.dmDriverExtra = 0;
3992 dm.dmFields =
3993 DM_ORIENTATION | DM_PAPERSIZE |
3994 DM_PAPERLENGTH | DM_PAPERWIDTH |
3995 DM_SCALE |
3996 DM_COPIES |
3997 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3998 DM_YRESOLUTION | DM_TTOPTION;
4000 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
4001 dm.u1.s1.dmPaperSize = DMPAPER_A4;
4002 dm.u1.s1.dmPaperLength = 2970;
4003 dm.u1.s1.dmPaperWidth = 2100;
4005 dm.u1.s1.dmScale = 100;
4006 dm.u1.s1.dmCopies = 1;
4007 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
4008 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
4009 /* dm.dmColor */
4010 /* dm.dmDuplex */
4011 dm.dmYResolution = 300; /* 300dpi */
4012 dm.dmTTOption = DMTT_BITMAP;
4013 /* dm.dmCollate */
4014 /* dm.dmFormName */
4015 /* dm.dmLogPixels */
4016 /* dm.dmBitsPerPel */
4017 /* dm.dmPelsWidth */
4018 /* dm.dmPelsHeight */
4019 /* dm.u2.dmDisplayFlags */
4020 /* dm.dmDisplayFrequency */
4021 /* dm.dmICMMethod */
4022 /* dm.dmICMIntent */
4023 /* dm.dmMediaType */
4024 /* dm.dmDitherType */
4025 /* dm.dmReserved1 */
4026 /* dm.dmReserved2 */
4027 /* dm.dmPanningWidth */
4028 /* dm.dmPanningHeight */
4030 if(buflen >= sizeof(DEVMODEW))
4031 memcpy(ptr, &dm, sizeof(DEVMODEW));
4032 *needed = sizeof(DEVMODEW);
4035 /*****************************************************************************
4036 * WINSPOOL_GetDevModeFromReg
4038 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4039 * DevMode is stored either as unicode or ascii.
4041 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4042 LPBYTE ptr,
4043 DWORD buflen, DWORD *needed)
4045 DWORD sz = buflen, type;
4046 LONG ret;
4048 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4049 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4050 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4051 if (sz < sizeof(DEVMODEA))
4053 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4054 return FALSE;
4056 /* ensures that dmSize is not erratically bogus if registry is invalid */
4057 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4058 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4059 sz += (CCHDEVICENAME + CCHFORMNAME);
4060 if (ptr && (buflen >= sz)) {
4061 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4062 memcpy(ptr, dmW, sz);
4063 HeapFree(GetProcessHeap(),0,dmW);
4065 *needed = sz;
4066 return TRUE;
4069 /*********************************************************************
4070 * WINSPOOL_GetPrinter_1
4072 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4074 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4075 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4077 DWORD size, left = cbBuf;
4078 BOOL space = (cbBuf > 0);
4079 LPBYTE ptr = buf;
4081 *pcbNeeded = 0;
4083 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4084 if(space && size <= left) {
4085 pi1->pName = (LPWSTR)ptr;
4086 ptr += size;
4087 left -= size;
4088 } else
4089 space = FALSE;
4090 *pcbNeeded += size;
4093 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4094 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4095 if(space && size <= left) {
4096 pi1->pDescription = (LPWSTR)ptr;
4097 ptr += size;
4098 left -= size;
4099 } else
4100 space = FALSE;
4101 *pcbNeeded += size;
4104 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4105 if(space && size <= left) {
4106 pi1->pComment = (LPWSTR)ptr;
4107 ptr += size;
4108 left -= size;
4109 } else
4110 space = FALSE;
4111 *pcbNeeded += size;
4114 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4116 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4117 memset(pi1, 0, sizeof(*pi1));
4119 return space;
4121 /*********************************************************************
4122 * WINSPOOL_GetPrinter_2
4124 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4126 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4127 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4129 DWORD size, left = cbBuf;
4130 BOOL space = (cbBuf > 0);
4131 LPBYTE ptr = buf;
4133 *pcbNeeded = 0;
4135 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4136 if(space && size <= left) {
4137 pi2->pPrinterName = (LPWSTR)ptr;
4138 ptr += size;
4139 left -= size;
4140 } else
4141 space = FALSE;
4142 *pcbNeeded += size;
4144 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4145 if(space && size <= left) {
4146 pi2->pShareName = (LPWSTR)ptr;
4147 ptr += size;
4148 left -= size;
4149 } else
4150 space = FALSE;
4151 *pcbNeeded += size;
4153 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4154 if(space && size <= left) {
4155 pi2->pPortName = (LPWSTR)ptr;
4156 ptr += size;
4157 left -= size;
4158 } else
4159 space = FALSE;
4160 *pcbNeeded += size;
4162 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4163 if(space && size <= left) {
4164 pi2->pDriverName = (LPWSTR)ptr;
4165 ptr += size;
4166 left -= size;
4167 } else
4168 space = FALSE;
4169 *pcbNeeded += size;
4171 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4172 if(space && size <= left) {
4173 pi2->pComment = (LPWSTR)ptr;
4174 ptr += size;
4175 left -= size;
4176 } else
4177 space = FALSE;
4178 *pcbNeeded += size;
4180 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4181 if(space && size <= left) {
4182 pi2->pLocation = (LPWSTR)ptr;
4183 ptr += size;
4184 left -= size;
4185 } else
4186 space = FALSE;
4187 *pcbNeeded += size;
4189 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4190 if(space && size <= left) {
4191 pi2->pDevMode = (LPDEVMODEW)ptr;
4192 ptr += size;
4193 left -= size;
4194 } else
4195 space = FALSE;
4196 *pcbNeeded += size;
4198 else
4200 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4201 if(space && size <= left) {
4202 pi2->pDevMode = (LPDEVMODEW)ptr;
4203 ptr += size;
4204 left -= size;
4205 } else
4206 space = FALSE;
4207 *pcbNeeded += size;
4209 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4210 if(space && size <= left) {
4211 pi2->pSepFile = (LPWSTR)ptr;
4212 ptr += size;
4213 left -= size;
4214 } else
4215 space = FALSE;
4216 *pcbNeeded += size;
4218 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4219 if(space && size <= left) {
4220 pi2->pPrintProcessor = (LPWSTR)ptr;
4221 ptr += size;
4222 left -= size;
4223 } else
4224 space = FALSE;
4225 *pcbNeeded += size;
4227 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4228 if(space && size <= left) {
4229 pi2->pDatatype = (LPWSTR)ptr;
4230 ptr += size;
4231 left -= size;
4232 } else
4233 space = FALSE;
4234 *pcbNeeded += size;
4236 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4237 if(space && size <= left) {
4238 pi2->pParameters = (LPWSTR)ptr;
4239 ptr += size;
4240 left -= size;
4241 } else
4242 space = FALSE;
4243 *pcbNeeded += size;
4245 if(pi2) {
4246 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4247 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4248 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4249 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4250 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4253 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4254 memset(pi2, 0, sizeof(*pi2));
4256 return space;
4259 /*********************************************************************
4260 * WINSPOOL_GetPrinter_4
4262 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4264 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4265 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4267 DWORD size, left = cbBuf;
4268 BOOL space = (cbBuf > 0);
4269 LPBYTE ptr = buf;
4271 *pcbNeeded = 0;
4273 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4274 if(space && size <= left) {
4275 pi4->pPrinterName = (LPWSTR)ptr;
4276 ptr += size;
4277 left -= size;
4278 } else
4279 space = FALSE;
4280 *pcbNeeded += size;
4282 if(pi4) {
4283 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4286 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4287 memset(pi4, 0, sizeof(*pi4));
4289 return space;
4292 /*********************************************************************
4293 * WINSPOOL_GetPrinter_5
4295 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4297 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4298 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4300 DWORD size, left = cbBuf;
4301 BOOL space = (cbBuf > 0);
4302 LPBYTE ptr = buf;
4304 *pcbNeeded = 0;
4306 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4307 if(space && size <= left) {
4308 pi5->pPrinterName = (LPWSTR)ptr;
4309 ptr += size;
4310 left -= size;
4311 } else
4312 space = FALSE;
4313 *pcbNeeded += size;
4315 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4316 if(space && size <= left) {
4317 pi5->pPortName = (LPWSTR)ptr;
4318 ptr += size;
4319 left -= size;
4320 } else
4321 space = FALSE;
4322 *pcbNeeded += size;
4324 if(pi5) {
4325 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4326 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4327 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4330 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4331 memset(pi5, 0, sizeof(*pi5));
4333 return space;
4336 /*********************************************************************
4337 * WINSPOOL_GetPrinter_7
4339 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4341 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4342 DWORD cbBuf, LPDWORD pcbNeeded)
4344 DWORD size, left = cbBuf;
4345 BOOL space = (cbBuf > 0);
4346 LPBYTE ptr = buf;
4348 *pcbNeeded = 0;
4350 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4352 ptr = NULL;
4353 size = sizeof(pi7->pszObjectGUID);
4355 if (space && size <= left) {
4356 pi7->pszObjectGUID = (LPWSTR)ptr;
4357 ptr += size;
4358 left -= size;
4359 } else
4360 space = FALSE;
4361 *pcbNeeded += size;
4362 if (pi7) {
4363 /* We do not have a Directory Service */
4364 pi7->dwAction = DSPRINT_UNPUBLISH;
4367 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4368 memset(pi7, 0, sizeof(*pi7));
4370 return space;
4373 /*********************************************************************
4374 * WINSPOOL_GetPrinter_9
4376 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4378 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4379 DWORD cbBuf, LPDWORD pcbNeeded)
4381 DWORD size;
4382 BOOL space = (cbBuf > 0);
4384 *pcbNeeded = 0;
4386 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4387 if(space && size <= cbBuf) {
4388 pi9->pDevMode = (LPDEVMODEW)buf;
4389 } else
4390 space = FALSE;
4391 *pcbNeeded += size;
4393 else
4395 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4396 if(space && size <= cbBuf) {
4397 pi9->pDevMode = (LPDEVMODEW)buf;
4398 } else
4399 space = FALSE;
4400 *pcbNeeded += size;
4403 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4404 memset(pi9, 0, sizeof(*pi9));
4406 return space;
4409 /*****************************************************************************
4410 * GetPrinterW [WINSPOOL.@]
4412 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4413 DWORD cbBuf, LPDWORD pcbNeeded)
4415 DWORD size, needed = 0, err;
4416 LPBYTE ptr = NULL;
4417 HKEY hkeyPrinter;
4418 BOOL ret;
4420 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4422 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4423 if (err)
4425 SetLastError( err );
4426 return FALSE;
4429 switch(Level) {
4430 case 2:
4432 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4434 size = sizeof(PRINTER_INFO_2W);
4435 if(size <= cbBuf) {
4436 ptr = pPrinter + size;
4437 cbBuf -= size;
4438 memset(pPrinter, 0, size);
4439 } else {
4440 pi2 = NULL;
4441 cbBuf = 0;
4443 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4444 needed += size;
4445 break;
4448 case 4:
4450 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4452 size = sizeof(PRINTER_INFO_4W);
4453 if(size <= cbBuf) {
4454 ptr = pPrinter + size;
4455 cbBuf -= size;
4456 memset(pPrinter, 0, size);
4457 } else {
4458 pi4 = NULL;
4459 cbBuf = 0;
4461 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4462 needed += size;
4463 break;
4467 case 5:
4469 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4471 size = sizeof(PRINTER_INFO_5W);
4472 if(size <= cbBuf) {
4473 ptr = pPrinter + size;
4474 cbBuf -= size;
4475 memset(pPrinter, 0, size);
4476 } else {
4477 pi5 = NULL;
4478 cbBuf = 0;
4481 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4482 needed += size;
4483 break;
4487 case 6:
4489 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4491 size = sizeof(PRINTER_INFO_6);
4492 if (size <= cbBuf) {
4493 /* FIXME: We do not update the status yet */
4494 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4495 ret = TRUE;
4496 } else {
4497 ret = FALSE;
4500 needed += size;
4501 break;
4504 case 7:
4506 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4508 size = sizeof(PRINTER_INFO_7W);
4509 if (size <= cbBuf) {
4510 ptr = pPrinter + size;
4511 cbBuf -= size;
4512 memset(pPrinter, 0, size);
4513 } else {
4514 pi7 = NULL;
4515 cbBuf = 0;
4518 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4519 needed += size;
4520 break;
4524 case 8:
4525 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4526 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4527 /* fall through */
4528 case 9:
4530 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4532 size = sizeof(PRINTER_INFO_9W);
4533 if(size <= cbBuf) {
4534 ptr = pPrinter + size;
4535 cbBuf -= size;
4536 memset(pPrinter, 0, size);
4537 } else {
4538 pi9 = NULL;
4539 cbBuf = 0;
4542 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4543 needed += size;
4544 break;
4548 default:
4549 FIXME("Unimplemented level %d\n", Level);
4550 SetLastError(ERROR_INVALID_LEVEL);
4551 RegCloseKey(hkeyPrinter);
4552 return FALSE;
4555 RegCloseKey(hkeyPrinter);
4557 TRACE("returning %d needed = %d\n", ret, needed);
4558 if(pcbNeeded) *pcbNeeded = needed;
4559 if(!ret)
4560 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4561 return ret;
4564 /*****************************************************************************
4565 * GetPrinterA [WINSPOOL.@]
4567 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4568 DWORD cbBuf, LPDWORD pcbNeeded)
4570 BOOL ret;
4571 LPBYTE buf = NULL;
4573 if (cbBuf)
4574 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4576 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4577 if (ret)
4578 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4579 HeapFree(GetProcessHeap(), 0, buf);
4581 return ret;
4584 /*****************************************************************************
4585 * WINSPOOL_EnumPrintersW
4587 * Implementation of EnumPrintersW
4589 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4590 DWORD dwLevel, LPBYTE lpbPrinters,
4591 DWORD cbBuf, LPDWORD lpdwNeeded,
4592 LPDWORD lpdwReturned)
4595 HKEY hkeyPrinters, hkeyPrinter;
4596 WCHAR PrinterName[255];
4597 DWORD needed = 0, number = 0;
4598 DWORD used, i, left;
4599 PBYTE pi, buf;
4601 if(lpbPrinters)
4602 memset(lpbPrinters, 0, cbBuf);
4603 if(lpdwReturned)
4604 *lpdwReturned = 0;
4605 if(lpdwNeeded)
4606 *lpdwNeeded = 0;
4608 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4609 if(dwType == PRINTER_ENUM_DEFAULT)
4610 return TRUE;
4612 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4613 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4614 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4615 if (!dwType) {
4616 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4617 return TRUE;
4622 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4623 FIXME("dwType = %08x\n", dwType);
4624 SetLastError(ERROR_INVALID_FLAGS);
4625 return FALSE;
4628 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4629 ERROR_SUCCESS) {
4630 ERR("Can't create Printers key\n");
4631 return FALSE;
4634 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4635 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4636 RegCloseKey(hkeyPrinters);
4637 ERR("Can't query Printers key\n");
4638 return FALSE;
4640 TRACE("Found %d printers\n", number);
4642 switch(dwLevel) {
4643 case 1:
4644 used = number * sizeof(PRINTER_INFO_1W);
4645 break;
4646 case 2:
4647 used = number * sizeof(PRINTER_INFO_2W);
4648 break;
4649 case 4:
4650 used = number * sizeof(PRINTER_INFO_4W);
4651 break;
4652 case 5:
4653 used = number * sizeof(PRINTER_INFO_5W);
4654 break;
4656 default:
4657 SetLastError(ERROR_INVALID_LEVEL);
4658 RegCloseKey(hkeyPrinters);
4659 return FALSE;
4661 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4663 for(i = 0; i < number; i++) {
4664 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4665 ERROR_SUCCESS) {
4666 ERR("Can't enum key number %d\n", i);
4667 RegCloseKey(hkeyPrinters);
4668 return FALSE;
4670 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4671 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4672 ERROR_SUCCESS) {
4673 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4674 RegCloseKey(hkeyPrinters);
4675 return FALSE;
4678 if(cbBuf > used) {
4679 buf = lpbPrinters + used;
4680 left = cbBuf - used;
4681 } else {
4682 buf = NULL;
4683 left = 0;
4686 switch(dwLevel) {
4687 case 1:
4688 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4689 left, &needed);
4690 used += needed;
4691 if(pi) pi += sizeof(PRINTER_INFO_1W);
4692 break;
4693 case 2:
4694 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4695 left, &needed);
4696 used += needed;
4697 if(pi) pi += sizeof(PRINTER_INFO_2W);
4698 break;
4699 case 4:
4700 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4701 left, &needed);
4702 used += needed;
4703 if(pi) pi += sizeof(PRINTER_INFO_4W);
4704 break;
4705 case 5:
4706 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4707 left, &needed);
4708 used += needed;
4709 if(pi) pi += sizeof(PRINTER_INFO_5W);
4710 break;
4711 default:
4712 ERR("Shouldn't be here!\n");
4713 RegCloseKey(hkeyPrinter);
4714 RegCloseKey(hkeyPrinters);
4715 return FALSE;
4717 RegCloseKey(hkeyPrinter);
4719 RegCloseKey(hkeyPrinters);
4721 if(lpdwNeeded)
4722 *lpdwNeeded = used;
4724 if(used > cbBuf) {
4725 if(lpbPrinters)
4726 memset(lpbPrinters, 0, cbBuf);
4727 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4728 return FALSE;
4730 if(lpdwReturned)
4731 *lpdwReturned = number;
4732 SetLastError(ERROR_SUCCESS);
4733 return TRUE;
4737 /******************************************************************
4738 * EnumPrintersW [WINSPOOL.@]
4740 * Enumerates the available printers, print servers and print
4741 * providers, depending on the specified flags, name and level.
4743 * RETURNS:
4745 * If level is set to 1:
4746 * Returns an array of PRINTER_INFO_1 data structures in the
4747 * lpbPrinters buffer.
4749 * If level is set to 2:
4750 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4751 * Returns an array of PRINTER_INFO_2 data structures in the
4752 * lpbPrinters buffer. Note that according to MSDN also an
4753 * OpenPrinter should be performed on every remote printer.
4755 * If level is set to 4 (officially WinNT only):
4756 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4757 * Fast: Only the registry is queried to retrieve printer names,
4758 * no connection to the driver is made.
4759 * Returns an array of PRINTER_INFO_4 data structures in the
4760 * lpbPrinters buffer.
4762 * If level is set to 5 (officially WinNT4/Win9x only):
4763 * Fast: Only the registry is queried to retrieve printer names,
4764 * no connection to the driver is made.
4765 * Returns an array of PRINTER_INFO_5 data structures in the
4766 * lpbPrinters buffer.
4768 * If level set to 3 or 6+:
4769 * returns zero (failure!)
4771 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4772 * for information.
4774 * BUGS:
4775 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4776 * - Only levels 2, 4 and 5 are implemented at the moment.
4777 * - 16-bit printer drivers are not enumerated.
4778 * - Returned amount of bytes used/needed does not match the real Windoze
4779 * implementation (as in this implementation, all strings are part
4780 * of the buffer, whereas Win32 keeps them somewhere else)
4781 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4783 * NOTE:
4784 * - In a regular Wine installation, no registry settings for printers
4785 * exist, which makes this function return an empty list.
4787 BOOL WINAPI EnumPrintersW(
4788 DWORD dwType, /* [in] Types of print objects to enumerate */
4789 LPWSTR lpszName, /* [in] name of objects to enumerate */
4790 DWORD dwLevel, /* [in] type of printer info structure */
4791 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4792 DWORD cbBuf, /* [in] max size of buffer in bytes */
4793 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4794 LPDWORD lpdwReturned /* [out] number of entries returned */
4797 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4798 lpdwNeeded, lpdwReturned);
4801 /******************************************************************
4802 * EnumPrintersA [WINSPOOL.@]
4804 * See EnumPrintersW
4807 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4808 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4810 BOOL ret;
4811 UNICODE_STRING pNameU;
4812 LPWSTR pNameW;
4813 LPBYTE pPrintersW;
4815 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4816 pPrinters, cbBuf, pcbNeeded, pcReturned);
4818 pNameW = asciitounicode(&pNameU, pName);
4820 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4821 MS Office need this */
4822 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4824 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4826 RtlFreeUnicodeString(&pNameU);
4827 if (ret) {
4828 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4830 HeapFree(GetProcessHeap(), 0, pPrintersW);
4831 return ret;
4834 /*****************************************************************************
4835 * WINSPOOL_GetDriverInfoFromReg [internal]
4837 * Enters the information from the registry into the DRIVER_INFO struct
4839 * RETURNS
4840 * zero if the printer driver does not exist in the registry
4841 * (only if Level > 1) otherwise nonzero
4843 static BOOL WINSPOOL_GetDriverInfoFromReg(
4844 HKEY hkeyDrivers,
4845 LPWSTR DriverName,
4846 const printenv_t * env,
4847 DWORD Level,
4848 LPBYTE ptr, /* DRIVER_INFO */
4849 LPBYTE pDriverStrings, /* strings buffer */
4850 DWORD cbBuf, /* size of string buffer */
4851 LPDWORD pcbNeeded) /* space needed for str. */
4853 DWORD size, tmp;
4854 HKEY hkeyDriver;
4855 WCHAR driverdir[MAX_PATH];
4856 DWORD dirlen;
4857 LPBYTE strPtr = pDriverStrings;
4858 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4860 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4861 debugstr_w(DriverName), env,
4862 Level, di, pDriverStrings, cbBuf);
4864 if (di) ZeroMemory(di, di_sizeof[Level]);
4866 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4867 if (*pcbNeeded <= cbBuf)
4868 strcpyW((LPWSTR)strPtr, DriverName);
4870 /* pName for level 1 has a different offset! */
4871 if (Level == 1) {
4872 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4873 return TRUE;
4876 /* .cVersion and .pName for level > 1 */
4877 if (di) {
4878 di->cVersion = env->driverversion;
4879 di->pName = (LPWSTR) strPtr;
4880 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4883 /* Reserve Space for the largest subdir and a Backslash*/
4884 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4885 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4886 /* Should never Fail */
4887 return FALSE;
4889 lstrcatW(driverdir, env->versionsubdir);
4890 lstrcatW(driverdir, backslashW);
4892 /* dirlen must not include the terminating zero */
4893 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4895 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4896 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4897 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4898 return FALSE;
4901 /* pEnvironment */
4902 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4904 *pcbNeeded += size;
4905 if (*pcbNeeded <= cbBuf) {
4906 lstrcpyW((LPWSTR)strPtr, env->envname);
4907 if (di) di->pEnvironment = (LPWSTR)strPtr;
4908 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4911 /* .pDriverPath is the Graphics rendering engine.
4912 The full Path is required to avoid a crash in some apps */
4913 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4914 *pcbNeeded += size;
4915 if (*pcbNeeded <= cbBuf)
4916 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4918 if (di) di->pDriverPath = (LPWSTR)strPtr;
4919 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4922 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4923 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4924 *pcbNeeded += size;
4925 if (*pcbNeeded <= cbBuf)
4926 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4928 if (di) di->pDataFile = (LPWSTR)strPtr;
4929 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4932 /* .pConfigFile is the Driver user Interface */
4933 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4934 *pcbNeeded += size;
4935 if (*pcbNeeded <= cbBuf)
4936 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4938 if (di) di->pConfigFile = (LPWSTR)strPtr;
4939 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4942 if (Level == 2 ) {
4943 RegCloseKey(hkeyDriver);
4944 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4945 return TRUE;
4948 if (Level == 5 ) {
4949 RegCloseKey(hkeyDriver);
4950 FIXME("level 5: incomplete\n");
4951 return TRUE;
4954 /* .pHelpFile */
4955 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4956 *pcbNeeded += size;
4957 if (*pcbNeeded <= cbBuf)
4958 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4960 if (di) di->pHelpFile = (LPWSTR)strPtr;
4961 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4964 /* .pDependentFiles */
4965 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4966 *pcbNeeded += size;
4967 if (*pcbNeeded <= cbBuf)
4968 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4970 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4971 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4973 else if (GetVersion() & 0x80000000) {
4974 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4975 size = 2 * sizeof(WCHAR);
4976 *pcbNeeded += size;
4977 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4979 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4980 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4983 /* .pMonitorName is the optional Language Monitor */
4984 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4985 *pcbNeeded += size;
4986 if (*pcbNeeded <= cbBuf)
4987 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4989 if (di) di->pMonitorName = (LPWSTR)strPtr;
4990 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4993 /* .pDefaultDataType */
4994 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4995 *pcbNeeded += size;
4996 if(*pcbNeeded <= cbBuf)
4997 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4999 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
5000 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5003 if (Level == 3 ) {
5004 RegCloseKey(hkeyDriver);
5005 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5006 return TRUE;
5009 /* .pszzPreviousNames */
5010 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
5011 *pcbNeeded += size;
5012 if(*pcbNeeded <= cbBuf)
5013 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
5015 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
5016 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5019 if (Level == 4 ) {
5020 RegCloseKey(hkeyDriver);
5021 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5022 return TRUE;
5025 /* support is missing, but not important enough for a FIXME */
5026 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5028 /* .pszMfgName */
5029 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5030 *pcbNeeded += size;
5031 if(*pcbNeeded <= cbBuf)
5032 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5034 if (di) di->pszMfgName = (LPWSTR)strPtr;
5035 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5038 /* .pszOEMUrl */
5039 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5040 *pcbNeeded += size;
5041 if(*pcbNeeded <= cbBuf)
5042 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5044 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5045 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5048 /* .pszHardwareID */
5049 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5050 *pcbNeeded += size;
5051 if(*pcbNeeded <= cbBuf)
5052 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5054 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5055 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5058 /* .pszProvider */
5059 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5060 *pcbNeeded += size;
5061 if(*pcbNeeded <= cbBuf)
5062 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5064 if (di) di->pszProvider = (LPWSTR)strPtr;
5065 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5068 if (Level == 6 ) {
5069 RegCloseKey(hkeyDriver);
5070 return TRUE;
5073 /* support is missing, but not important enough for a FIXME */
5074 TRACE("level 8: incomplete\n");
5076 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5077 RegCloseKey(hkeyDriver);
5078 return TRUE;
5081 /*****************************************************************************
5082 * GetPrinterDriverW [WINSPOOL.@]
5084 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5085 DWORD Level, LPBYTE pDriverInfo,
5086 DWORD cbBuf, LPDWORD pcbNeeded)
5088 LPCWSTR name;
5089 WCHAR DriverName[100];
5090 DWORD ret, type, size, needed = 0;
5091 LPBYTE ptr = NULL;
5092 HKEY hkeyPrinter, hkeyDrivers;
5093 const printenv_t * env;
5095 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5096 Level,pDriverInfo,cbBuf, pcbNeeded);
5098 if (cbBuf > 0)
5099 ZeroMemory(pDriverInfo, cbBuf);
5101 if (!(name = get_opened_printer_name(hPrinter))) {
5102 SetLastError(ERROR_INVALID_HANDLE);
5103 return FALSE;
5106 if (Level < 1 || Level == 7 || Level > 8) {
5107 SetLastError(ERROR_INVALID_LEVEL);
5108 return FALSE;
5111 env = validate_envW(pEnvironment);
5112 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5114 ret = open_printer_reg_key( name, &hkeyPrinter );
5115 if (ret)
5117 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5118 SetLastError( ret );
5119 return FALSE;
5122 size = sizeof(DriverName);
5123 DriverName[0] = 0;
5124 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5125 (LPBYTE)DriverName, &size);
5126 RegCloseKey(hkeyPrinter);
5127 if(ret != ERROR_SUCCESS) {
5128 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5129 return FALSE;
5132 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5133 if(!hkeyDrivers) {
5134 ERR("Can't create Drivers key\n");
5135 return FALSE;
5138 size = di_sizeof[Level];
5139 if ((size <= cbBuf) && pDriverInfo)
5140 ptr = pDriverInfo + size;
5142 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5143 env, Level, pDriverInfo, ptr,
5144 (cbBuf < size) ? 0 : cbBuf - size,
5145 &needed)) {
5146 RegCloseKey(hkeyDrivers);
5147 return FALSE;
5150 RegCloseKey(hkeyDrivers);
5152 if(pcbNeeded) *pcbNeeded = size + needed;
5153 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5154 if(cbBuf >= size + needed) return TRUE;
5155 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5156 return FALSE;
5159 /*****************************************************************************
5160 * GetPrinterDriverA [WINSPOOL.@]
5162 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5163 DWORD Level, LPBYTE pDriverInfo,
5164 DWORD cbBuf, LPDWORD pcbNeeded)
5166 BOOL ret;
5167 UNICODE_STRING pEnvW;
5168 PWSTR pwstrEnvW;
5169 LPBYTE buf = NULL;
5171 if (cbBuf)
5173 ZeroMemory(pDriverInfo, cbBuf);
5174 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5177 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5178 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5179 cbBuf, pcbNeeded);
5180 if (ret)
5181 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5183 HeapFree(GetProcessHeap(), 0, buf);
5185 RtlFreeUnicodeString(&pEnvW);
5186 return ret;
5189 /*****************************************************************************
5190 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5192 * Return the PATH for the Printer-Drivers (UNICODE)
5194 * PARAMS
5195 * pName [I] Servername (NT only) or NULL (local Computer)
5196 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5197 * Level [I] Structure-Level (must be 1)
5198 * pDriverDirectory [O] PTR to Buffer that receives the Result
5199 * cbBuf [I] Size of Buffer at pDriverDirectory
5200 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5201 * required for pDriverDirectory
5203 * RETURNS
5204 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5205 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5206 * if cbBuf is too small
5208 * Native Values returned in pDriverDirectory on Success:
5209 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5210 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5211 *| win9x(Windows 4.0): "%winsysdir%"
5213 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5215 * FIXME
5216 *- Only NULL or "" is supported for pName
5219 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5220 DWORD Level, LPBYTE pDriverDirectory,
5221 DWORD cbBuf, LPDWORD pcbNeeded)
5223 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5224 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5226 if ((backend == NULL) && !load_backend()) return FALSE;
5228 if (Level != 1) {
5229 /* (Level != 1) is ignored in win9x */
5230 SetLastError(ERROR_INVALID_LEVEL);
5231 return FALSE;
5233 if (pcbNeeded == NULL) {
5234 /* (pcbNeeded == NULL) is ignored in win9x */
5235 SetLastError(RPC_X_NULL_REF_POINTER);
5236 return FALSE;
5239 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5240 pDriverDirectory, cbBuf, pcbNeeded);
5245 /*****************************************************************************
5246 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5248 * Return the PATH for the Printer-Drivers (ANSI)
5250 * See GetPrinterDriverDirectoryW.
5252 * NOTES
5253 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5256 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5257 DWORD Level, LPBYTE pDriverDirectory,
5258 DWORD cbBuf, LPDWORD pcbNeeded)
5260 UNICODE_STRING nameW, environmentW;
5261 BOOL ret;
5262 DWORD pcbNeededW;
5263 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5264 WCHAR *driverDirectoryW = NULL;
5266 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5267 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5269 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5271 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5272 else nameW.Buffer = NULL;
5273 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5274 else environmentW.Buffer = NULL;
5276 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5277 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5278 if (ret) {
5279 DWORD needed;
5280 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5281 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5282 if(pcbNeeded)
5283 *pcbNeeded = needed;
5284 ret = needed <= cbBuf;
5285 } else
5286 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5288 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5290 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5291 RtlFreeUnicodeString(&environmentW);
5292 RtlFreeUnicodeString(&nameW);
5294 return ret;
5297 /*****************************************************************************
5298 * AddPrinterDriverA [WINSPOOL.@]
5300 * See AddPrinterDriverW.
5303 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5305 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5306 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5309 /******************************************************************************
5310 * AddPrinterDriverW (WINSPOOL.@)
5312 * Install a Printer Driver
5314 * PARAMS
5315 * pName [I] Servername or NULL (local Computer)
5316 * level [I] Level for the supplied DRIVER_INFO_*W struct
5317 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5319 * RESULTS
5320 * Success: TRUE
5321 * Failure: FALSE
5324 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5326 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5327 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5330 /*****************************************************************************
5331 * AddPrintProcessorA [WINSPOOL.@]
5333 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5334 LPSTR pPrintProcessorName)
5336 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5337 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5338 return FALSE;
5341 /*****************************************************************************
5342 * AddPrintProcessorW [WINSPOOL.@]
5344 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5345 LPWSTR pPrintProcessorName)
5347 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5348 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5349 return TRUE;
5352 /*****************************************************************************
5353 * AddPrintProvidorA [WINSPOOL.@]
5355 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5357 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5358 return FALSE;
5361 /*****************************************************************************
5362 * AddPrintProvidorW [WINSPOOL.@]
5364 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5366 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5367 return FALSE;
5370 /*****************************************************************************
5371 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5373 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5374 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5376 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5377 pDevModeOutput, pDevModeInput);
5378 return 0;
5381 /*****************************************************************************
5382 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5384 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5385 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5387 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5388 pDevModeOutput, pDevModeInput);
5389 return 0;
5392 /*****************************************************************************
5393 * PrinterProperties [WINSPOOL.@]
5395 * Displays a dialog to set the properties of the printer.
5397 * RETURNS
5398 * nonzero on success or zero on failure
5400 * BUGS
5401 * implemented as stub only
5403 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5404 HANDLE hPrinter /* [in] handle to printer object */
5406 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5407 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5408 return FALSE;
5411 /*****************************************************************************
5412 * EnumJobsA [WINSPOOL.@]
5415 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5416 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5417 LPDWORD pcReturned)
5419 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5420 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5422 if(pcbNeeded) *pcbNeeded = 0;
5423 if(pcReturned) *pcReturned = 0;
5424 return FALSE;
5428 /*****************************************************************************
5429 * EnumJobsW [WINSPOOL.@]
5432 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5433 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5434 LPDWORD pcReturned)
5436 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5437 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5439 if(pcbNeeded) *pcbNeeded = 0;
5440 if(pcReturned) *pcReturned = 0;
5441 return FALSE;
5444 /*****************************************************************************
5445 * WINSPOOL_EnumPrinterDrivers [internal]
5447 * Delivers information about all printer drivers installed on the
5448 * localhost or a given server
5450 * RETURNS
5451 * nonzero on success or zero on failure. If the buffer for the returned
5452 * information is too small the function will return an error
5454 * BUGS
5455 * - only implemented for localhost, foreign hosts will return an error
5457 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5458 DWORD Level, LPBYTE pDriverInfo,
5459 DWORD driver_index,
5460 DWORD cbBuf, LPDWORD pcbNeeded,
5461 LPDWORD pcFound, DWORD data_offset)
5463 { HKEY hkeyDrivers;
5464 DWORD i, size = 0;
5465 const printenv_t * env;
5467 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5468 debugstr_w(pName), debugstr_w(pEnvironment),
5469 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5471 env = validate_envW(pEnvironment);
5472 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5474 *pcFound = 0;
5476 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5477 if(!hkeyDrivers) {
5478 ERR("Can't open Drivers key\n");
5479 return FALSE;
5482 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5483 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5484 RegCloseKey(hkeyDrivers);
5485 ERR("Can't query Drivers key\n");
5486 return FALSE;
5488 TRACE("Found %d Drivers\n", *pcFound);
5490 /* get size of single struct
5491 * unicode and ascii structure have the same size
5493 size = di_sizeof[Level];
5495 if (data_offset == 0)
5496 data_offset = size * (*pcFound);
5497 *pcbNeeded = data_offset;
5499 for( i = 0; i < *pcFound; i++) {
5500 WCHAR DriverNameW[255];
5501 PBYTE table_ptr = NULL;
5502 PBYTE data_ptr = NULL;
5503 DWORD needed = 0;
5505 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5506 != ERROR_SUCCESS) {
5507 ERR("Can't enum key number %d\n", i);
5508 RegCloseKey(hkeyDrivers);
5509 return FALSE;
5512 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5513 table_ptr = pDriverInfo + (driver_index + i) * size;
5514 if (pDriverInfo && *pcbNeeded <= cbBuf)
5515 data_ptr = pDriverInfo + *pcbNeeded;
5517 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5518 env, Level, table_ptr, data_ptr,
5519 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5520 &needed)) {
5521 RegCloseKey(hkeyDrivers);
5522 return FALSE;
5525 *pcbNeeded += needed;
5528 RegCloseKey(hkeyDrivers);
5530 if(cbBuf < *pcbNeeded){
5531 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5532 return FALSE;
5535 return TRUE;
5538 /*****************************************************************************
5539 * EnumPrinterDriversW [WINSPOOL.@]
5541 * see function EnumPrinterDrivers for RETURNS, BUGS
5543 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5544 LPBYTE pDriverInfo, DWORD cbBuf,
5545 LPDWORD pcbNeeded, LPDWORD pcReturned)
5547 static const WCHAR allW[] = {'a','l','l',0};
5548 BOOL ret;
5549 DWORD found;
5551 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5553 SetLastError(RPC_X_NULL_REF_POINTER);
5554 return FALSE;
5557 /* check for local drivers */
5558 if((pName) && (pName[0])) {
5559 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5560 SetLastError(ERROR_ACCESS_DENIED);
5561 return FALSE;
5564 /* check input parameter */
5565 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5566 SetLastError(ERROR_INVALID_LEVEL);
5567 return FALSE;
5570 if(pDriverInfo && cbBuf > 0)
5571 memset( pDriverInfo, 0, cbBuf);
5573 /* Exception: pull all printers */
5574 if (pEnvironment && !strcmpW(pEnvironment, allW))
5576 DWORD i, needed, bufsize = cbBuf;
5577 DWORD total_needed = 0;
5578 DWORD total_found = 0;
5579 DWORD data_offset;
5581 /* Precompute the overall total; we need this to know
5582 where pointers end and data begins (i.e. data_offset) */
5583 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5585 needed = found = 0;
5586 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5587 NULL, 0, 0, &needed, &found, 0);
5588 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5589 total_needed += needed;
5590 total_found += found;
5593 data_offset = di_sizeof[Level] * total_found;
5595 *pcReturned = 0;
5596 *pcbNeeded = 0;
5597 total_found = 0;
5598 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5600 needed = found = 0;
5601 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5602 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5603 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5604 else if (ret)
5605 *pcReturned += found;
5606 *pcbNeeded = needed;
5607 data_offset = needed;
5608 total_found += found;
5610 return ret;
5613 /* Normal behavior */
5614 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5615 0, cbBuf, pcbNeeded, &found, 0);
5616 if (ret)
5617 *pcReturned = found;
5619 return ret;
5622 /*****************************************************************************
5623 * EnumPrinterDriversA [WINSPOOL.@]
5625 * see function EnumPrinterDrivers for RETURNS, BUGS
5627 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5628 LPBYTE pDriverInfo, DWORD cbBuf,
5629 LPDWORD pcbNeeded, LPDWORD pcReturned)
5631 BOOL ret;
5632 UNICODE_STRING pNameW, pEnvironmentW;
5633 PWSTR pwstrNameW, pwstrEnvironmentW;
5634 LPBYTE buf = NULL;
5636 if (cbBuf)
5637 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5639 pwstrNameW = asciitounicode(&pNameW, pName);
5640 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5642 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5643 buf, cbBuf, pcbNeeded, pcReturned);
5644 if (ret)
5645 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5647 HeapFree(GetProcessHeap(), 0, buf);
5649 RtlFreeUnicodeString(&pNameW);
5650 RtlFreeUnicodeString(&pEnvironmentW);
5652 return ret;
5655 /******************************************************************************
5656 * EnumPortsA (WINSPOOL.@)
5658 * See EnumPortsW.
5661 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5662 LPDWORD pcbNeeded, LPDWORD pcReturned)
5664 BOOL res;
5665 LPBYTE bufferW = NULL;
5666 LPWSTR nameW = NULL;
5667 DWORD needed = 0;
5668 DWORD numentries = 0;
5669 INT len;
5671 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5672 cbBuf, pcbNeeded, pcReturned);
5674 /* convert servername to unicode */
5675 if (pName) {
5676 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5677 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5678 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5680 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5681 needed = cbBuf * sizeof(WCHAR);
5682 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5683 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5685 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5686 if (pcbNeeded) needed = *pcbNeeded;
5687 /* HeapReAlloc return NULL, when bufferW was NULL */
5688 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5689 HeapAlloc(GetProcessHeap(), 0, needed);
5691 /* Try again with the large Buffer */
5692 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5694 needed = pcbNeeded ? *pcbNeeded : 0;
5695 numentries = pcReturned ? *pcReturned : 0;
5698 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5699 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5701 if (res) {
5702 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5703 DWORD entrysize = 0;
5704 DWORD index;
5705 LPSTR ptr;
5706 LPPORT_INFO_2W pi2w;
5707 LPPORT_INFO_2A pi2a;
5709 needed = 0;
5710 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5712 /* First pass: calculate the size for all Entries */
5713 pi2w = (LPPORT_INFO_2W) bufferW;
5714 pi2a = (LPPORT_INFO_2A) pPorts;
5715 index = 0;
5716 while (index < numentries) {
5717 index++;
5718 needed += entrysize; /* PORT_INFO_?A */
5719 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5721 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5722 NULL, 0, NULL, NULL);
5723 if (Level > 1) {
5724 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5725 NULL, 0, NULL, NULL);
5726 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5727 NULL, 0, NULL, NULL);
5729 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5730 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5731 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5734 /* check for errors and quit on failure */
5735 if (cbBuf < needed) {
5736 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5737 res = FALSE;
5738 goto cleanup;
5740 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5741 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5742 cbBuf -= len ; /* free Bytes in the user-Buffer */
5743 pi2w = (LPPORT_INFO_2W) bufferW;
5744 pi2a = (LPPORT_INFO_2A) pPorts;
5745 index = 0;
5746 /* Second Pass: Fill the User Buffer (if we have one) */
5747 while ((index < numentries) && pPorts) {
5748 index++;
5749 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5750 pi2a->pPortName = ptr;
5751 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5752 ptr, cbBuf , NULL, NULL);
5753 ptr += len;
5754 cbBuf -= len;
5755 if (Level > 1) {
5756 pi2a->pMonitorName = ptr;
5757 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5758 ptr, cbBuf, NULL, NULL);
5759 ptr += len;
5760 cbBuf -= len;
5762 pi2a->pDescription = ptr;
5763 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5764 ptr, cbBuf, NULL, NULL);
5765 ptr += len;
5766 cbBuf -= len;
5768 pi2a->fPortType = pi2w->fPortType;
5769 pi2a->Reserved = 0; /* documented: "must be zero" */
5772 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5773 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5774 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5778 cleanup:
5779 if (pcbNeeded) *pcbNeeded = needed;
5780 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5782 HeapFree(GetProcessHeap(), 0, nameW);
5783 HeapFree(GetProcessHeap(), 0, bufferW);
5785 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5786 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5788 return (res);
5792 /******************************************************************************
5793 * EnumPortsW (WINSPOOL.@)
5795 * Enumerate available Ports
5797 * PARAMS
5798 * pName [I] Servername or NULL (local Computer)
5799 * Level [I] Structure-Level (1 or 2)
5800 * pPorts [O] PTR to Buffer that receives the Result
5801 * cbBuf [I] Size of Buffer at pPorts
5802 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5803 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5805 * RETURNS
5806 * Success: TRUE
5807 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5810 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5813 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5814 cbBuf, pcbNeeded, pcReturned);
5816 if ((backend == NULL) && !load_backend()) return FALSE;
5818 /* Level is not checked in win9x */
5819 if (!Level || (Level > 2)) {
5820 WARN("level (%d) is ignored in win9x\n", Level);
5821 SetLastError(ERROR_INVALID_LEVEL);
5822 return FALSE;
5824 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5825 SetLastError(RPC_X_NULL_REF_POINTER);
5826 return FALSE;
5829 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5832 /******************************************************************************
5833 * GetDefaultPrinterW (WINSPOOL.@)
5835 * FIXME
5836 * This function must read the value from data 'device' of key
5837 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5839 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5841 BOOL retval = TRUE;
5842 DWORD insize, len;
5843 WCHAR *buffer, *ptr;
5845 if (!namesize)
5847 SetLastError(ERROR_INVALID_PARAMETER);
5848 return FALSE;
5851 /* make the buffer big enough for the stuff from the profile/registry,
5852 * the content must fit into the local buffer to compute the correct
5853 * size even if the extern buffer is too small or not given.
5854 * (20 for ,driver,port) */
5855 insize = *namesize;
5856 len = max(100, (insize + 20));
5857 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5859 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5861 SetLastError (ERROR_FILE_NOT_FOUND);
5862 retval = FALSE;
5863 goto end;
5865 TRACE("%s\n", debugstr_w(buffer));
5867 if ((ptr = strchrW(buffer, ',')) == NULL)
5869 SetLastError(ERROR_INVALID_NAME);
5870 retval = FALSE;
5871 goto end;
5874 *ptr = 0;
5875 *namesize = strlenW(buffer) + 1;
5876 if(!name || (*namesize > insize))
5878 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5879 retval = FALSE;
5880 goto end;
5882 strcpyW(name, buffer);
5884 end:
5885 HeapFree( GetProcessHeap(), 0, buffer);
5886 return retval;
5890 /******************************************************************************
5891 * GetDefaultPrinterA (WINSPOOL.@)
5893 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5895 BOOL retval = TRUE;
5896 DWORD insize = 0;
5897 WCHAR *bufferW = NULL;
5899 if (!namesize)
5901 SetLastError(ERROR_INVALID_PARAMETER);
5902 return FALSE;
5905 if(name && *namesize) {
5906 insize = *namesize;
5907 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5910 if(!GetDefaultPrinterW( bufferW, namesize)) {
5911 retval = FALSE;
5912 goto end;
5915 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5916 NULL, NULL);
5917 if (!*namesize)
5919 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5920 retval = FALSE;
5922 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5924 end:
5925 HeapFree( GetProcessHeap(), 0, bufferW);
5926 return retval;
5930 /******************************************************************************
5931 * SetDefaultPrinterW (WINSPOOL.204)
5933 * Set the Name of the Default Printer
5935 * PARAMS
5936 * pszPrinter [I] Name of the Printer or NULL
5938 * RETURNS
5939 * Success: True
5940 * Failure: FALSE
5942 * NOTES
5943 * When the Parameter is NULL or points to an Empty String and
5944 * a Default Printer was already present, then this Function changes nothing.
5945 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5946 * the First enumerated local Printer is used.
5949 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5951 WCHAR default_printer[MAX_PATH];
5952 LPWSTR buffer = NULL;
5953 HKEY hreg;
5954 DWORD size;
5955 DWORD namelen;
5956 LONG lres;
5958 TRACE("(%s)\n", debugstr_w(pszPrinter));
5959 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5961 default_printer[0] = '\0';
5962 size = sizeof(default_printer)/sizeof(WCHAR);
5964 /* if we have a default Printer, do nothing. */
5965 if (GetDefaultPrinterW(default_printer, &size))
5966 return TRUE;
5968 pszPrinter = NULL;
5969 /* we have no default Printer: search local Printers and use the first */
5970 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5972 default_printer[0] = '\0';
5973 size = sizeof(default_printer)/sizeof(WCHAR);
5974 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5976 pszPrinter = default_printer;
5977 TRACE("using %s\n", debugstr_w(pszPrinter));
5979 RegCloseKey(hreg);
5982 if (pszPrinter == NULL) {
5983 TRACE("no local printer found\n");
5984 SetLastError(ERROR_FILE_NOT_FOUND);
5985 return FALSE;
5989 /* "pszPrinter" is never empty or NULL here. */
5990 namelen = lstrlenW(pszPrinter);
5991 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5992 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5993 if (!buffer ||
5994 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5995 HeapFree(GetProcessHeap(), 0, buffer);
5996 SetLastError(ERROR_FILE_NOT_FOUND);
5997 return FALSE;
6000 /* read the devices entry for the printer (driver,port) to build the string for the
6001 default device entry (printer,driver,port) */
6002 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
6003 buffer[namelen] = ',';
6004 namelen++; /* move index to the start of the driver */
6006 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
6007 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
6008 if (!lres) {
6009 TRACE("set device to %s\n", debugstr_w(buffer));
6011 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
6012 TRACE("failed to set the device entry: %d\n", GetLastError());
6013 lres = ERROR_INVALID_PRINTER_NAME;
6016 /* remove the next section, when INIFileMapping is implemented */
6018 HKEY hdev;
6019 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
6020 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6021 RegCloseKey(hdev);
6025 else
6027 if (lres != ERROR_FILE_NOT_FOUND)
6028 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6030 SetLastError(ERROR_INVALID_PRINTER_NAME);
6033 RegCloseKey(hreg);
6034 HeapFree(GetProcessHeap(), 0, buffer);
6035 return (lres == ERROR_SUCCESS);
6038 /******************************************************************************
6039 * SetDefaultPrinterA (WINSPOOL.202)
6041 * See SetDefaultPrinterW.
6044 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6046 LPWSTR bufferW = NULL;
6047 BOOL res;
6049 TRACE("(%s)\n", debugstr_a(pszPrinter));
6050 if(pszPrinter) {
6051 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6052 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6053 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6055 res = SetDefaultPrinterW(bufferW);
6056 HeapFree(GetProcessHeap(), 0, bufferW);
6057 return res;
6060 /******************************************************************************
6061 * SetPrinterDataExA (WINSPOOL.@)
6063 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6064 LPCSTR pValueName, DWORD Type,
6065 LPBYTE pData, DWORD cbData)
6067 HKEY hkeyPrinter, hkeySubkey;
6068 DWORD ret;
6070 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6071 debugstr_a(pValueName), Type, pData, cbData);
6073 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6074 != ERROR_SUCCESS)
6075 return ret;
6077 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6078 != ERROR_SUCCESS) {
6079 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6080 RegCloseKey(hkeyPrinter);
6081 return ret;
6083 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6084 RegCloseKey(hkeySubkey);
6085 RegCloseKey(hkeyPrinter);
6086 return ret;
6089 /******************************************************************************
6090 * SetPrinterDataExW (WINSPOOL.@)
6092 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6093 LPCWSTR pValueName, DWORD Type,
6094 LPBYTE pData, DWORD cbData)
6096 HKEY hkeyPrinter, hkeySubkey;
6097 DWORD ret;
6099 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6100 debugstr_w(pValueName), Type, pData, cbData);
6102 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6103 != ERROR_SUCCESS)
6104 return ret;
6106 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6107 != ERROR_SUCCESS) {
6108 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6109 RegCloseKey(hkeyPrinter);
6110 return ret;
6112 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6113 RegCloseKey(hkeySubkey);
6114 RegCloseKey(hkeyPrinter);
6115 return ret;
6118 /******************************************************************************
6119 * SetPrinterDataA (WINSPOOL.@)
6121 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6122 LPBYTE pData, DWORD cbData)
6124 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6125 pData, cbData);
6128 /******************************************************************************
6129 * SetPrinterDataW (WINSPOOL.@)
6131 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6132 LPBYTE pData, DWORD cbData)
6134 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6135 pData, cbData);
6138 /******************************************************************************
6139 * GetPrinterDataExA (WINSPOOL.@)
6141 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6142 LPCSTR pValueName, LPDWORD pType,
6143 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6145 opened_printer_t *printer;
6146 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6147 DWORD ret;
6149 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6150 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6152 printer = get_opened_printer(hPrinter);
6153 if(!printer) return ERROR_INVALID_HANDLE;
6155 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6156 if (ret) return ret;
6158 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6160 if (printer->name) {
6162 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6163 if (ret) {
6164 RegCloseKey(hkeyPrinters);
6165 return ret;
6167 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6168 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6169 RegCloseKey(hkeyPrinter);
6170 RegCloseKey(hkeyPrinters);
6171 return ret;
6174 *pcbNeeded = nSize;
6175 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6176 0, pType, pData, pcbNeeded);
6178 if (!ret && !pData) ret = ERROR_MORE_DATA;
6180 RegCloseKey(hkeySubkey);
6181 RegCloseKey(hkeyPrinter);
6182 RegCloseKey(hkeyPrinters);
6184 TRACE("--> %d\n", ret);
6185 return ret;
6188 /******************************************************************************
6189 * GetPrinterDataExW (WINSPOOL.@)
6191 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6192 LPCWSTR pValueName, LPDWORD pType,
6193 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6195 opened_printer_t *printer;
6196 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6197 DWORD ret;
6199 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6200 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6202 printer = get_opened_printer(hPrinter);
6203 if(!printer) return ERROR_INVALID_HANDLE;
6205 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6206 if (ret) return ret;
6208 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6210 if (printer->name) {
6212 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6213 if (ret) {
6214 RegCloseKey(hkeyPrinters);
6215 return ret;
6217 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6218 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6219 RegCloseKey(hkeyPrinter);
6220 RegCloseKey(hkeyPrinters);
6221 return ret;
6224 *pcbNeeded = nSize;
6225 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6226 0, pType, pData, pcbNeeded);
6228 if (!ret && !pData) ret = ERROR_MORE_DATA;
6230 RegCloseKey(hkeySubkey);
6231 RegCloseKey(hkeyPrinter);
6232 RegCloseKey(hkeyPrinters);
6234 TRACE("--> %d\n", ret);
6235 return ret;
6238 /******************************************************************************
6239 * GetPrinterDataA (WINSPOOL.@)
6241 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6242 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6244 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6245 pData, nSize, pcbNeeded);
6248 /******************************************************************************
6249 * GetPrinterDataW (WINSPOOL.@)
6251 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6252 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6254 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6255 pData, nSize, pcbNeeded);
6258 /*******************************************************************************
6259 * EnumPrinterDataExW [WINSPOOL.@]
6261 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6262 LPBYTE pEnumValues, DWORD cbEnumValues,
6263 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6265 HKEY hkPrinter, hkSubKey;
6266 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6267 cbValueNameLen, cbMaxValueLen, cbValueLen,
6268 cbBufSize, dwType;
6269 LPWSTR lpValueName;
6270 HANDLE hHeap;
6271 PBYTE lpValue;
6272 PPRINTER_ENUM_VALUESW ppev;
6274 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6276 if (pKeyName == NULL || *pKeyName == 0)
6277 return ERROR_INVALID_PARAMETER;
6279 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6280 if (ret != ERROR_SUCCESS)
6282 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6283 hPrinter, ret);
6284 return ret;
6287 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6288 if (ret != ERROR_SUCCESS)
6290 r = RegCloseKey (hkPrinter);
6291 if (r != ERROR_SUCCESS)
6292 WARN ("RegCloseKey returned %i\n", r);
6293 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6294 debugstr_w (pKeyName), ret);
6295 return ret;
6298 ret = RegCloseKey (hkPrinter);
6299 if (ret != ERROR_SUCCESS)
6301 ERR ("RegCloseKey returned %i\n", ret);
6302 r = RegCloseKey (hkSubKey);
6303 if (r != ERROR_SUCCESS)
6304 WARN ("RegCloseKey returned %i\n", r);
6305 return ret;
6308 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6309 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6310 if (ret != ERROR_SUCCESS)
6312 r = RegCloseKey (hkSubKey);
6313 if (r != ERROR_SUCCESS)
6314 WARN ("RegCloseKey returned %i\n", r);
6315 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6316 return ret;
6319 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6320 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6322 if (cValues == 0) /* empty key */
6324 r = RegCloseKey (hkSubKey);
6325 if (r != ERROR_SUCCESS)
6326 WARN ("RegCloseKey returned %i\n", r);
6327 *pcbEnumValues = *pnEnumValues = 0;
6328 return ERROR_SUCCESS;
6331 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6333 hHeap = GetProcessHeap ();
6334 if (hHeap == NULL)
6336 ERR ("GetProcessHeap failed\n");
6337 r = RegCloseKey (hkSubKey);
6338 if (r != ERROR_SUCCESS)
6339 WARN ("RegCloseKey returned %i\n", r);
6340 return ERROR_OUTOFMEMORY;
6343 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6344 if (lpValueName == NULL)
6346 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6347 r = RegCloseKey (hkSubKey);
6348 if (r != ERROR_SUCCESS)
6349 WARN ("RegCloseKey returned %i\n", r);
6350 return ERROR_OUTOFMEMORY;
6353 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6354 if (lpValue == NULL)
6356 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
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 return ERROR_OUTOFMEMORY;
6365 TRACE ("pass 1: calculating buffer required for all names and values\n");
6367 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6369 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6371 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6373 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6374 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6375 NULL, NULL, lpValue, &cbValueLen);
6376 if (ret != ERROR_SUCCESS)
6378 if (HeapFree (hHeap, 0, lpValue) == 0)
6379 WARN ("HeapFree failed with code %i\n", GetLastError ());
6380 if (HeapFree (hHeap, 0, lpValueName) == 0)
6381 WARN ("HeapFree failed with code %i\n", GetLastError ());
6382 r = RegCloseKey (hkSubKey);
6383 if (r != ERROR_SUCCESS)
6384 WARN ("RegCloseKey returned %i\n", r);
6385 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6386 return ret;
6389 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6390 debugstr_w (lpValueName), dwIndex,
6391 cbValueNameLen + 1, cbValueLen);
6393 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6394 cbBufSize += cbValueLen;
6397 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6399 *pcbEnumValues = cbBufSize;
6400 *pnEnumValues = cValues;
6402 if (cbEnumValues < cbBufSize) /* buffer too small */
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 ("%i byte buffer is not large enough\n", cbEnumValues);
6412 return ERROR_MORE_DATA;
6415 TRACE ("pass 2: copying all names and values to buffer\n");
6417 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6418 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6420 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6422 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6423 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6424 NULL, &dwType, lpValue, &cbValueLen);
6425 if (ret != ERROR_SUCCESS)
6427 if (HeapFree (hHeap, 0, lpValue) == 0)
6428 WARN ("HeapFree failed with code %i\n", GetLastError ());
6429 if (HeapFree (hHeap, 0, lpValueName) == 0)
6430 WARN ("HeapFree failed with code %i\n", GetLastError ());
6431 r = RegCloseKey (hkSubKey);
6432 if (r != ERROR_SUCCESS)
6433 WARN ("RegCloseKey returned %i\n", r);
6434 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6435 return ret;
6438 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6439 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6440 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6441 pEnumValues += cbValueNameLen;
6443 /* return # of *bytes* (including trailing \0), not # of chars */
6444 ppev[dwIndex].cbValueName = cbValueNameLen;
6446 ppev[dwIndex].dwType = dwType;
6448 memcpy (pEnumValues, lpValue, cbValueLen);
6449 ppev[dwIndex].pData = pEnumValues;
6450 pEnumValues += cbValueLen;
6452 ppev[dwIndex].cbData = cbValueLen;
6454 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6455 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6458 if (HeapFree (hHeap, 0, lpValue) == 0)
6460 ret = GetLastError ();
6461 ERR ("HeapFree failed with code %i\n", ret);
6462 if (HeapFree (hHeap, 0, lpValueName) == 0)
6463 WARN ("HeapFree failed with code %i\n", GetLastError ());
6464 r = RegCloseKey (hkSubKey);
6465 if (r != ERROR_SUCCESS)
6466 WARN ("RegCloseKey returned %i\n", r);
6467 return ret;
6470 if (HeapFree (hHeap, 0, lpValueName) == 0)
6472 ret = GetLastError ();
6473 ERR ("HeapFree failed with code %i\n", ret);
6474 r = RegCloseKey (hkSubKey);
6475 if (r != ERROR_SUCCESS)
6476 WARN ("RegCloseKey returned %i\n", r);
6477 return ret;
6480 ret = RegCloseKey (hkSubKey);
6481 if (ret != ERROR_SUCCESS)
6483 ERR ("RegCloseKey returned %i\n", ret);
6484 return ret;
6487 return ERROR_SUCCESS;
6490 /*******************************************************************************
6491 * EnumPrinterDataExA [WINSPOOL.@]
6493 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6494 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6495 * what Windows 2000 SP1 does.
6498 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6499 LPBYTE pEnumValues, DWORD cbEnumValues,
6500 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6502 INT len;
6503 LPWSTR pKeyNameW;
6504 DWORD ret, dwIndex, dwBufSize;
6505 HANDLE hHeap;
6506 LPSTR pBuffer;
6508 TRACE ("%p %s\n", hPrinter, pKeyName);
6510 if (pKeyName == NULL || *pKeyName == 0)
6511 return ERROR_INVALID_PARAMETER;
6513 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6514 if (len == 0)
6516 ret = GetLastError ();
6517 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6518 return ret;
6521 hHeap = GetProcessHeap ();
6522 if (hHeap == NULL)
6524 ERR ("GetProcessHeap failed\n");
6525 return ERROR_OUTOFMEMORY;
6528 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6529 if (pKeyNameW == NULL)
6531 ERR ("Failed to allocate %i bytes from process heap\n",
6532 (LONG)(len * sizeof (WCHAR)));
6533 return ERROR_OUTOFMEMORY;
6536 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6538 ret = GetLastError ();
6539 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6540 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6541 WARN ("HeapFree failed with code %i\n", GetLastError ());
6542 return ret;
6545 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6546 pcbEnumValues, pnEnumValues);
6547 if (ret != ERROR_SUCCESS)
6549 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6550 WARN ("HeapFree failed with code %i\n", GetLastError ());
6551 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6552 return ret;
6555 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6557 ret = GetLastError ();
6558 ERR ("HeapFree failed with code %i\n", ret);
6559 return ret;
6562 if (*pnEnumValues == 0) /* empty key */
6563 return ERROR_SUCCESS;
6565 dwBufSize = 0;
6566 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6568 PPRINTER_ENUM_VALUESW ppev =
6569 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6571 if (dwBufSize < ppev->cbValueName)
6572 dwBufSize = ppev->cbValueName;
6574 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6575 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6576 dwBufSize = ppev->cbData;
6579 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6581 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6582 if (pBuffer == NULL)
6584 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6585 return ERROR_OUTOFMEMORY;
6588 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6590 PPRINTER_ENUM_VALUESW ppev =
6591 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6593 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6594 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6595 NULL);
6596 if (len == 0)
6598 ret = GetLastError ();
6599 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6600 if (HeapFree (hHeap, 0, pBuffer) == 0)
6601 WARN ("HeapFree failed with code %i\n", GetLastError ());
6602 return ret;
6605 memcpy (ppev->pValueName, pBuffer, len);
6607 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6609 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6610 ppev->dwType != REG_MULTI_SZ)
6611 continue;
6613 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6614 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6615 if (len == 0)
6617 ret = GetLastError ();
6618 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6619 if (HeapFree (hHeap, 0, pBuffer) == 0)
6620 WARN ("HeapFree failed with code %i\n", GetLastError ());
6621 return ret;
6624 memcpy (ppev->pData, pBuffer, len);
6626 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6627 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6630 if (HeapFree (hHeap, 0, pBuffer) == 0)
6632 ret = GetLastError ();
6633 ERR ("HeapFree failed with code %i\n", ret);
6634 return ret;
6637 return ERROR_SUCCESS;
6640 /******************************************************************************
6641 * AbortPrinter (WINSPOOL.@)
6643 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6645 FIXME("(%p), stub!\n", hPrinter);
6646 return TRUE;
6649 /******************************************************************************
6650 * AddPortA (WINSPOOL.@)
6652 * See AddPortW.
6655 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6657 LPWSTR nameW = NULL;
6658 LPWSTR monitorW = NULL;
6659 DWORD len;
6660 BOOL res;
6662 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6664 if (pName) {
6665 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6666 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6667 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6670 if (pMonitorName) {
6671 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6672 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6673 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6675 res = AddPortW(nameW, hWnd, monitorW);
6676 HeapFree(GetProcessHeap(), 0, nameW);
6677 HeapFree(GetProcessHeap(), 0, monitorW);
6678 return res;
6681 /******************************************************************************
6682 * AddPortW (WINSPOOL.@)
6684 * Add a Port for a specific Monitor
6686 * PARAMS
6687 * pName [I] Servername or NULL (local Computer)
6688 * hWnd [I] Handle to parent Window for the Dialog-Box
6689 * pMonitorName [I] Name of the Monitor that manage the Port
6691 * RETURNS
6692 * Success: TRUE
6693 * Failure: FALSE
6696 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6698 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6700 if ((backend == NULL) && !load_backend()) return FALSE;
6702 if (!pMonitorName) {
6703 SetLastError(RPC_X_NULL_REF_POINTER);
6704 return FALSE;
6707 return backend->fpAddPort(pName, hWnd, pMonitorName);
6710 /******************************************************************************
6711 * AddPortExA (WINSPOOL.@)
6713 * See AddPortExW.
6716 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6718 PORT_INFO_2W pi2W;
6719 PORT_INFO_2A * pi2A;
6720 LPWSTR nameW = NULL;
6721 LPWSTR monitorW = NULL;
6722 DWORD len;
6723 BOOL res;
6725 pi2A = (PORT_INFO_2A *) pBuffer;
6727 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6728 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6730 if ((level < 1) || (level > 2)) {
6731 SetLastError(ERROR_INVALID_LEVEL);
6732 return FALSE;
6735 if (!pi2A) {
6736 SetLastError(ERROR_INVALID_PARAMETER);
6737 return FALSE;
6740 if (pName) {
6741 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6742 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6743 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6746 if (pMonitorName) {
6747 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6748 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6749 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6752 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6754 if (pi2A->pPortName) {
6755 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6756 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6757 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6760 if (level > 1) {
6761 if (pi2A->pMonitorName) {
6762 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6763 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6764 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6767 if (pi2A->pDescription) {
6768 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6769 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6770 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6772 pi2W.fPortType = pi2A->fPortType;
6773 pi2W.Reserved = pi2A->Reserved;
6776 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6778 HeapFree(GetProcessHeap(), 0, nameW);
6779 HeapFree(GetProcessHeap(), 0, monitorW);
6780 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6781 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6782 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6783 return res;
6787 /******************************************************************************
6788 * AddPortExW (WINSPOOL.@)
6790 * Add a Port for a specific Monitor, without presenting a user interface
6792 * PARAMS
6793 * pName [I] Servername or NULL (local Computer)
6794 * level [I] Structure-Level (1 or 2) for pBuffer
6795 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6796 * pMonitorName [I] Name of the Monitor that manage the Port
6798 * RETURNS
6799 * Success: TRUE
6800 * Failure: FALSE
6803 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6805 PORT_INFO_2W * pi2;
6807 pi2 = (PORT_INFO_2W *) pBuffer;
6809 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6810 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6811 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6812 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6814 if ((backend == NULL) && !load_backend()) return FALSE;
6816 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6817 SetLastError(ERROR_INVALID_PARAMETER);
6818 return FALSE;
6821 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6824 /******************************************************************************
6825 * AddPrinterConnectionA (WINSPOOL.@)
6827 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6829 FIXME("%s\n", debugstr_a(pName));
6830 return FALSE;
6833 /******************************************************************************
6834 * AddPrinterConnectionW (WINSPOOL.@)
6836 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6838 FIXME("%s\n", debugstr_w(pName));
6839 return FALSE;
6842 /******************************************************************************
6843 * AddPrinterDriverExW (WINSPOOL.@)
6845 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6847 * PARAMS
6848 * pName [I] Servername or NULL (local Computer)
6849 * level [I] Level for the supplied DRIVER_INFO_*W struct
6850 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6851 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6853 * RESULTS
6854 * Success: TRUE
6855 * Failure: FALSE
6858 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6860 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6862 if ((backend == NULL) && !load_backend()) return FALSE;
6864 if (level < 2 || level == 5 || level == 7 || level > 8) {
6865 SetLastError(ERROR_INVALID_LEVEL);
6866 return FALSE;
6869 if (!pDriverInfo) {
6870 SetLastError(ERROR_INVALID_PARAMETER);
6871 return FALSE;
6874 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6877 /******************************************************************************
6878 * AddPrinterDriverExA (WINSPOOL.@)
6880 * See AddPrinterDriverExW.
6883 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6885 DRIVER_INFO_8A *diA;
6886 DRIVER_INFO_8W diW;
6887 LPWSTR nameW = NULL;
6888 DWORD lenA;
6889 DWORD len;
6890 DWORD res = FALSE;
6892 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6894 diA = (DRIVER_INFO_8A *) pDriverInfo;
6895 ZeroMemory(&diW, sizeof(diW));
6897 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6898 SetLastError(ERROR_INVALID_LEVEL);
6899 return FALSE;
6902 if (diA == NULL) {
6903 SetLastError(ERROR_INVALID_PARAMETER);
6904 return FALSE;
6907 /* convert servername to unicode */
6908 if (pName) {
6909 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6910 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6911 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6914 /* common fields */
6915 diW.cVersion = diA->cVersion;
6917 if (diA->pName) {
6918 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6919 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6920 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6923 if (diA->pEnvironment) {
6924 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6925 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6926 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6929 if (diA->pDriverPath) {
6930 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6931 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6932 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6935 if (diA->pDataFile) {
6936 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6937 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6938 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6941 if (diA->pConfigFile) {
6942 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6943 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6944 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6947 if ((Level > 2) && diA->pDependentFiles) {
6948 lenA = multi_sz_lenA(diA->pDependentFiles);
6949 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6950 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6951 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6954 if ((Level > 2) && diA->pMonitorName) {
6955 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6956 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6957 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6960 if ((Level > 3) && diA->pDefaultDataType) {
6961 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6962 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6963 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6966 if ((Level > 3) && diA->pszzPreviousNames) {
6967 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6968 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6969 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6970 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6973 if ((Level > 5) && diA->pszMfgName) {
6974 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6975 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6976 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6979 if ((Level > 5) && diA->pszOEMUrl) {
6980 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6981 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6982 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6985 if ((Level > 5) && diA->pszHardwareID) {
6986 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6987 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6988 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6991 if ((Level > 5) && diA->pszProvider) {
6992 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6993 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6994 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6997 if (Level > 7) {
6998 FIXME("level %u is incomplete\n", Level);
7001 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
7002 TRACE("got %u with %u\n", res, GetLastError());
7003 HeapFree(GetProcessHeap(), 0, nameW);
7004 HeapFree(GetProcessHeap(), 0, diW.pName);
7005 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
7006 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
7007 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
7008 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
7009 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
7010 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
7011 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
7012 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
7013 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
7014 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
7015 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
7016 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
7018 TRACE("=> %u with %u\n", res, GetLastError());
7019 return res;
7022 /******************************************************************************
7023 * ConfigurePortA (WINSPOOL.@)
7025 * See ConfigurePortW.
7028 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7030 LPWSTR nameW = NULL;
7031 LPWSTR portW = NULL;
7032 INT len;
7033 DWORD res;
7035 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7037 /* convert servername to unicode */
7038 if (pName) {
7039 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7040 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7041 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7044 /* convert portname to unicode */
7045 if (pPortName) {
7046 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7047 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7048 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7051 res = ConfigurePortW(nameW, hWnd, portW);
7052 HeapFree(GetProcessHeap(), 0, nameW);
7053 HeapFree(GetProcessHeap(), 0, portW);
7054 return res;
7057 /******************************************************************************
7058 * ConfigurePortW (WINSPOOL.@)
7060 * Display the Configuration-Dialog for a specific Port
7062 * PARAMS
7063 * pName [I] Servername or NULL (local Computer)
7064 * hWnd [I] Handle to parent Window for the Dialog-Box
7065 * pPortName [I] Name of the Port, that should be configured
7067 * RETURNS
7068 * Success: TRUE
7069 * Failure: FALSE
7072 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7075 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7077 if ((backend == NULL) && !load_backend()) return FALSE;
7079 if (!pPortName) {
7080 SetLastError(RPC_X_NULL_REF_POINTER);
7081 return FALSE;
7084 return backend->fpConfigurePort(pName, hWnd, pPortName);
7087 /******************************************************************************
7088 * ConnectToPrinterDlg (WINSPOOL.@)
7090 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7092 FIXME("%p %x\n", hWnd, Flags);
7093 return NULL;
7096 /******************************************************************************
7097 * DeletePrinterConnectionA (WINSPOOL.@)
7099 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7101 FIXME("%s\n", debugstr_a(pName));
7102 return TRUE;
7105 /******************************************************************************
7106 * DeletePrinterConnectionW (WINSPOOL.@)
7108 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7110 FIXME("%s\n", debugstr_w(pName));
7111 return TRUE;
7114 /******************************************************************************
7115 * DeletePrinterDriverExW (WINSPOOL.@)
7117 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7118 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7120 HKEY hkey_drivers;
7121 BOOL ret = FALSE;
7123 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7124 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7126 if(pName && pName[0])
7128 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7129 SetLastError(ERROR_INVALID_PARAMETER);
7130 return FALSE;
7133 if(dwDeleteFlag)
7135 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7136 SetLastError(ERROR_INVALID_PARAMETER);
7137 return FALSE;
7140 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7142 if(!hkey_drivers)
7144 ERR("Can't open drivers key\n");
7145 return FALSE;
7148 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7149 ret = TRUE;
7151 RegCloseKey(hkey_drivers);
7153 return ret;
7156 /******************************************************************************
7157 * DeletePrinterDriverExA (WINSPOOL.@)
7159 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7160 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7162 UNICODE_STRING NameW, EnvW, DriverW;
7163 BOOL ret;
7165 asciitounicode(&NameW, pName);
7166 asciitounicode(&EnvW, pEnvironment);
7167 asciitounicode(&DriverW, pDriverName);
7169 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7171 RtlFreeUnicodeString(&DriverW);
7172 RtlFreeUnicodeString(&EnvW);
7173 RtlFreeUnicodeString(&NameW);
7175 return ret;
7178 /******************************************************************************
7179 * DeletePrinterDataExW (WINSPOOL.@)
7181 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7182 LPCWSTR pValueName)
7184 FIXME("%p %s %s\n", hPrinter,
7185 debugstr_w(pKeyName), debugstr_w(pValueName));
7186 return ERROR_INVALID_PARAMETER;
7189 /******************************************************************************
7190 * DeletePrinterDataExA (WINSPOOL.@)
7192 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7193 LPCSTR pValueName)
7195 FIXME("%p %s %s\n", hPrinter,
7196 debugstr_a(pKeyName), debugstr_a(pValueName));
7197 return ERROR_INVALID_PARAMETER;
7200 /******************************************************************************
7201 * DeletePrintProcessorA (WINSPOOL.@)
7203 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7205 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7206 debugstr_a(pPrintProcessorName));
7207 return TRUE;
7210 /******************************************************************************
7211 * DeletePrintProcessorW (WINSPOOL.@)
7213 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7215 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7216 debugstr_w(pPrintProcessorName));
7217 return TRUE;
7220 /******************************************************************************
7221 * DeletePrintProvidorA (WINSPOOL.@)
7223 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7225 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7226 debugstr_a(pPrintProviderName));
7227 return TRUE;
7230 /******************************************************************************
7231 * DeletePrintProvidorW (WINSPOOL.@)
7233 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7235 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7236 debugstr_w(pPrintProviderName));
7237 return TRUE;
7240 /******************************************************************************
7241 * EnumFormsA (WINSPOOL.@)
7243 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7244 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7246 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7247 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7248 return FALSE;
7251 /******************************************************************************
7252 * EnumFormsW (WINSPOOL.@)
7254 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7255 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7257 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7258 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7259 return FALSE;
7262 /*****************************************************************************
7263 * EnumMonitorsA [WINSPOOL.@]
7265 * See EnumMonitorsW.
7268 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7269 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7271 BOOL res;
7272 LPBYTE bufferW = NULL;
7273 LPWSTR nameW = NULL;
7274 DWORD needed = 0;
7275 DWORD numentries = 0;
7276 INT len;
7278 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7279 cbBuf, pcbNeeded, pcReturned);
7281 /* convert servername to unicode */
7282 if (pName) {
7283 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7284 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7285 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7287 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7288 needed = cbBuf * sizeof(WCHAR);
7289 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7290 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7292 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7293 if (pcbNeeded) needed = *pcbNeeded;
7294 /* HeapReAlloc return NULL, when bufferW was NULL */
7295 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7296 HeapAlloc(GetProcessHeap(), 0, needed);
7298 /* Try again with the large Buffer */
7299 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7301 numentries = pcReturned ? *pcReturned : 0;
7302 needed = 0;
7304 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7305 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7307 if (res) {
7308 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7309 DWORD entrysize = 0;
7310 DWORD index;
7311 LPSTR ptr;
7312 LPMONITOR_INFO_2W mi2w;
7313 LPMONITOR_INFO_2A mi2a;
7315 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7316 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7318 /* First pass: calculate the size for all Entries */
7319 mi2w = (LPMONITOR_INFO_2W) bufferW;
7320 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7321 index = 0;
7322 while (index < numentries) {
7323 index++;
7324 needed += entrysize; /* MONITOR_INFO_?A */
7325 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7327 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7328 NULL, 0, NULL, NULL);
7329 if (Level > 1) {
7330 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7331 NULL, 0, NULL, NULL);
7332 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7333 NULL, 0, NULL, NULL);
7335 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7336 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7337 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7340 /* check for errors and quit on failure */
7341 if (cbBuf < needed) {
7342 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7343 res = FALSE;
7344 goto emA_cleanup;
7346 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7347 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7348 cbBuf -= len ; /* free Bytes in the user-Buffer */
7349 mi2w = (LPMONITOR_INFO_2W) bufferW;
7350 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7351 index = 0;
7352 /* Second Pass: Fill the User Buffer (if we have one) */
7353 while ((index < numentries) && pMonitors) {
7354 index++;
7355 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7356 mi2a->pName = ptr;
7357 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7358 ptr, cbBuf , NULL, NULL);
7359 ptr += len;
7360 cbBuf -= len;
7361 if (Level > 1) {
7362 mi2a->pEnvironment = ptr;
7363 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7364 ptr, cbBuf, NULL, NULL);
7365 ptr += len;
7366 cbBuf -= len;
7368 mi2a->pDLLName = ptr;
7369 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7370 ptr, cbBuf, NULL, NULL);
7371 ptr += len;
7372 cbBuf -= len;
7374 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7375 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7376 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7379 emA_cleanup:
7380 if (pcbNeeded) *pcbNeeded = needed;
7381 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7383 HeapFree(GetProcessHeap(), 0, nameW);
7384 HeapFree(GetProcessHeap(), 0, bufferW);
7386 TRACE("returning %d with %d (%d byte for %d entries)\n",
7387 (res), GetLastError(), needed, numentries);
7389 return (res);
7393 /*****************************************************************************
7394 * EnumMonitorsW [WINSPOOL.@]
7396 * Enumerate available Port-Monitors
7398 * PARAMS
7399 * pName [I] Servername or NULL (local Computer)
7400 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7401 * pMonitors [O] PTR to Buffer that receives the Result
7402 * cbBuf [I] Size of Buffer at pMonitors
7403 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7404 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7406 * RETURNS
7407 * Success: TRUE
7408 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7411 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7412 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7415 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7416 cbBuf, pcbNeeded, pcReturned);
7418 if ((backend == NULL) && !load_backend()) return FALSE;
7420 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7421 SetLastError(RPC_X_NULL_REF_POINTER);
7422 return FALSE;
7425 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7428 /******************************************************************************
7429 * SpoolerInit (WINSPOOL.@)
7431 * Initialize the Spooler
7433 * RETURNS
7434 * Success: TRUE
7435 * Failure: FALSE
7437 * NOTES
7438 * The function fails on windows, when the spooler service is not running
7441 BOOL WINAPI SpoolerInit(void)
7444 if ((backend == NULL) && !load_backend()) return FALSE;
7445 return TRUE;
7448 /******************************************************************************
7449 * XcvDataW (WINSPOOL.@)
7451 * Execute commands in the Printmonitor DLL
7453 * PARAMS
7454 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7455 * pszDataName [i] Name of the command to execute
7456 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7457 * cbInputData [i] Size in Bytes of Buffer at pInputData
7458 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7459 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7460 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7461 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7463 * RETURNS
7464 * Success: TRUE
7465 * Failure: FALSE
7467 * NOTES
7468 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7469 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7471 * Minimal List of commands, that a Printmonitor DLL should support:
7473 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7474 *| "AddPort" : Add a Port
7475 *| "DeletePort": Delete a Port
7477 * Many Printmonitors support additional commands. Examples for localspl.dll:
7478 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7479 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7482 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7483 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7484 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7486 opened_printer_t *printer;
7488 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7489 pInputData, cbInputData, pOutputData,
7490 cbOutputData, pcbOutputNeeded, pdwStatus);
7492 if ((backend == NULL) && !load_backend()) return FALSE;
7494 printer = get_opened_printer(hXcv);
7495 if (!printer || (!printer->backend_printer)) {
7496 SetLastError(ERROR_INVALID_HANDLE);
7497 return FALSE;
7500 if (!pcbOutputNeeded) {
7501 SetLastError(ERROR_INVALID_PARAMETER);
7502 return FALSE;
7505 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7506 SetLastError(RPC_X_NULL_REF_POINTER);
7507 return FALSE;
7510 *pcbOutputNeeded = 0;
7512 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7513 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7517 /*****************************************************************************
7518 * EnumPrinterDataA [WINSPOOL.@]
7521 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7522 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7523 DWORD cbData, LPDWORD pcbData )
7525 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7526 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7527 return ERROR_NO_MORE_ITEMS;
7530 /*****************************************************************************
7531 * EnumPrinterDataW [WINSPOOL.@]
7534 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7535 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7536 DWORD cbData, LPDWORD pcbData )
7538 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7539 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7540 return ERROR_NO_MORE_ITEMS;
7543 /*****************************************************************************
7544 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7547 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7548 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7549 LPDWORD pcbNeeded, LPDWORD pcReturned)
7551 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7552 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7553 pcbNeeded, pcReturned);
7554 return FALSE;
7557 /*****************************************************************************
7558 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7561 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7562 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7563 LPDWORD pcbNeeded, LPDWORD pcReturned)
7565 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7566 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7567 pcbNeeded, pcReturned);
7568 return FALSE;
7571 /*****************************************************************************
7572 * EnumPrintProcessorsA [WINSPOOL.@]
7574 * See EnumPrintProcessorsW.
7577 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7578 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7580 BOOL res;
7581 LPBYTE bufferW = NULL;
7582 LPWSTR nameW = NULL;
7583 LPWSTR envW = NULL;
7584 DWORD needed = 0;
7585 DWORD numentries = 0;
7586 INT len;
7588 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7589 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7591 /* convert names to unicode */
7592 if (pName) {
7593 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7594 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7595 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7597 if (pEnvironment) {
7598 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7599 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7600 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7603 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7604 needed = cbBuf * sizeof(WCHAR);
7605 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7606 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7608 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7609 if (pcbNeeded) needed = *pcbNeeded;
7610 /* HeapReAlloc return NULL, when bufferW was NULL */
7611 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7612 HeapAlloc(GetProcessHeap(), 0, needed);
7614 /* Try again with the large Buffer */
7615 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7617 numentries = pcReturned ? *pcReturned : 0;
7618 needed = 0;
7620 if (res) {
7621 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7622 DWORD index;
7623 LPSTR ptr;
7624 PPRINTPROCESSOR_INFO_1W ppiw;
7625 PPRINTPROCESSOR_INFO_1A ppia;
7627 /* First pass: calculate the size for all Entries */
7628 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7629 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7630 index = 0;
7631 while (index < numentries) {
7632 index++;
7633 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7634 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7636 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7637 NULL, 0, NULL, NULL);
7639 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7640 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7643 /* check for errors and quit on failure */
7644 if (cbBuf < needed) {
7645 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7646 res = FALSE;
7647 goto epp_cleanup;
7650 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7651 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7652 cbBuf -= len ; /* free Bytes in the user-Buffer */
7653 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7654 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7655 index = 0;
7656 /* Second Pass: Fill the User Buffer (if we have one) */
7657 while ((index < numentries) && pPPInfo) {
7658 index++;
7659 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7660 ppia->pName = ptr;
7661 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7662 ptr, cbBuf , NULL, NULL);
7663 ptr += len;
7664 cbBuf -= len;
7666 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7667 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7671 epp_cleanup:
7672 if (pcbNeeded) *pcbNeeded = needed;
7673 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7675 HeapFree(GetProcessHeap(), 0, nameW);
7676 HeapFree(GetProcessHeap(), 0, envW);
7677 HeapFree(GetProcessHeap(), 0, bufferW);
7679 TRACE("returning %d with %d (%d byte for %d entries)\n",
7680 (res), GetLastError(), needed, numentries);
7682 return (res);
7685 /*****************************************************************************
7686 * EnumPrintProcessorsW [WINSPOOL.@]
7688 * Enumerate available Print Processors
7690 * PARAMS
7691 * pName [I] Servername or NULL (local Computer)
7692 * pEnvironment [I] Printing-Environment or NULL (Default)
7693 * Level [I] Structure-Level (Only 1 is allowed)
7694 * pPPInfo [O] PTR to Buffer that receives the Result
7695 * cbBuf [I] Size of Buffer at pPPInfo
7696 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7697 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7699 * RETURNS
7700 * Success: TRUE
7701 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7704 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7705 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7708 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7709 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7711 if ((backend == NULL) && !load_backend()) return FALSE;
7713 if (!pcbNeeded || !pcReturned) {
7714 SetLastError(RPC_X_NULL_REF_POINTER);
7715 return FALSE;
7718 if (!pPPInfo && (cbBuf > 0)) {
7719 SetLastError(ERROR_INVALID_USER_BUFFER);
7720 return FALSE;
7723 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7724 cbBuf, pcbNeeded, pcReturned);
7727 /*****************************************************************************
7728 * ExtDeviceMode [WINSPOOL.@]
7731 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7732 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7733 DWORD fMode)
7735 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7736 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7737 debugstr_a(pProfile), fMode);
7738 return -1;
7741 /*****************************************************************************
7742 * FindClosePrinterChangeNotification [WINSPOOL.@]
7745 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7747 FIXME("Stub: %p\n", hChange);
7748 return TRUE;
7751 /*****************************************************************************
7752 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7755 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7756 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7758 FIXME("Stub: %p %x %x %p\n",
7759 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7760 return INVALID_HANDLE_VALUE;
7763 /*****************************************************************************
7764 * FindNextPrinterChangeNotification [WINSPOOL.@]
7767 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7768 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7770 FIXME("Stub: %p %p %p %p\n",
7771 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7772 return FALSE;
7775 /*****************************************************************************
7776 * FreePrinterNotifyInfo [WINSPOOL.@]
7779 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7781 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7782 return TRUE;
7785 /*****************************************************************************
7786 * string_to_buf
7788 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7789 * ansi depending on the unicode parameter.
7791 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7793 if(!str)
7795 *size = 0;
7796 return TRUE;
7799 if(unicode)
7801 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7802 if(*size <= cb)
7804 memcpy(ptr, str, *size);
7805 return TRUE;
7807 return FALSE;
7809 else
7811 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7812 if(*size <= cb)
7814 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7815 return TRUE;
7817 return FALSE;
7821 /*****************************************************************************
7822 * get_job_info_1
7824 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7825 LPDWORD pcbNeeded, BOOL unicode)
7827 DWORD size, left = cbBuf;
7828 BOOL space = (cbBuf > 0);
7829 LPBYTE ptr = buf;
7831 *pcbNeeded = 0;
7833 if(space)
7835 ji1->JobId = job->job_id;
7838 string_to_buf(job->document_title, ptr, left, &size, unicode);
7839 if(space && size <= left)
7841 ji1->pDocument = (LPWSTR)ptr;
7842 ptr += size;
7843 left -= size;
7845 else
7846 space = FALSE;
7847 *pcbNeeded += size;
7849 if (job->printer_name)
7851 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7852 if(space && size <= left)
7854 ji1->pPrinterName = (LPWSTR)ptr;
7855 ptr += size;
7856 left -= size;
7858 else
7859 space = FALSE;
7860 *pcbNeeded += size;
7863 return space;
7866 /*****************************************************************************
7867 * get_job_info_2
7869 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7870 LPDWORD pcbNeeded, BOOL unicode)
7872 DWORD size, left = cbBuf;
7873 DWORD shift;
7874 BOOL space = (cbBuf > 0);
7875 LPBYTE ptr = buf;
7876 LPDEVMODEA dmA = NULL;
7877 LPDEVMODEW devmode;
7879 *pcbNeeded = 0;
7881 if(space)
7883 ji2->JobId = job->job_id;
7886 string_to_buf(job->document_title, ptr, left, &size, unicode);
7887 if(space && size <= left)
7889 ji2->pDocument = (LPWSTR)ptr;
7890 ptr += size;
7891 left -= size;
7893 else
7894 space = FALSE;
7895 *pcbNeeded += size;
7897 if (job->printer_name)
7899 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7900 if(space && size <= left)
7902 ji2->pPrinterName = (LPWSTR)ptr;
7903 ptr += size;
7904 left -= size;
7906 else
7907 space = FALSE;
7908 *pcbNeeded += size;
7911 if (job->devmode)
7913 if (!unicode)
7915 dmA = DEVMODEdupWtoA(job->devmode);
7916 devmode = (LPDEVMODEW) dmA;
7917 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7919 else
7921 devmode = job->devmode;
7922 size = devmode->dmSize + devmode->dmDriverExtra;
7925 if (!devmode)
7926 FIXME("Can't convert DEVMODE W to A\n");
7927 else
7929 /* align DEVMODE to a DWORD boundary */
7930 shift = (4 - (*pcbNeeded & 3)) & 3;
7931 size += shift;
7933 if (size <= left)
7935 ptr += shift;
7936 memcpy(ptr, devmode, size-shift);
7937 ji2->pDevMode = (LPDEVMODEW)ptr;
7938 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7939 ptr += size-shift;
7940 left -= size;
7942 else
7943 space = FALSE;
7944 *pcbNeeded +=size;
7948 return space;
7951 /*****************************************************************************
7952 * get_job_info
7954 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7955 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7957 BOOL ret = FALSE;
7958 DWORD needed = 0, size;
7959 job_t *job;
7960 LPBYTE ptr = pJob;
7962 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7964 EnterCriticalSection(&printer_handles_cs);
7965 job = get_job(hPrinter, JobId);
7966 if(!job)
7967 goto end;
7969 switch(Level)
7971 case 1:
7972 size = sizeof(JOB_INFO_1W);
7973 if(cbBuf >= size)
7975 cbBuf -= size;
7976 ptr += size;
7977 memset(pJob, 0, size);
7979 else
7980 cbBuf = 0;
7981 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7982 needed += size;
7983 break;
7985 case 2:
7986 size = sizeof(JOB_INFO_2W);
7987 if(cbBuf >= size)
7989 cbBuf -= size;
7990 ptr += size;
7991 memset(pJob, 0, size);
7993 else
7994 cbBuf = 0;
7995 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7996 needed += size;
7997 break;
7999 case 3:
8000 size = sizeof(JOB_INFO_3);
8001 if(cbBuf >= size)
8003 cbBuf -= size;
8004 memset(pJob, 0, size);
8005 ret = TRUE;
8007 else
8008 cbBuf = 0;
8009 needed = size;
8010 break;
8012 default:
8013 SetLastError(ERROR_INVALID_LEVEL);
8014 goto end;
8016 if(pcbNeeded)
8017 *pcbNeeded = needed;
8018 end:
8019 LeaveCriticalSection(&printer_handles_cs);
8020 return ret;
8023 /*****************************************************************************
8024 * GetJobA [WINSPOOL.@]
8027 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8028 DWORD cbBuf, LPDWORD pcbNeeded)
8030 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8033 /*****************************************************************************
8034 * GetJobW [WINSPOOL.@]
8037 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8038 DWORD cbBuf, LPDWORD pcbNeeded)
8040 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8043 /*****************************************************************************
8044 * schedule_pipe
8046 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8048 #ifdef HAVE_FORK
8049 char *unixname, *cmdA;
8050 DWORD len;
8051 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8052 BOOL ret = FALSE;
8053 char buf[1024];
8054 pid_t pid, wret;
8055 int status;
8057 if(!(unixname = wine_get_unix_file_name(filename)))
8058 return FALSE;
8060 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8061 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8062 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8064 TRACE("printing with: %s\n", cmdA);
8066 if((file_fd = open(unixname, O_RDONLY)) == -1)
8067 goto end;
8069 if (pipe(fds))
8071 ERR("pipe() failed!\n");
8072 goto end;
8075 if ((pid = fork()) == 0)
8077 close(0);
8078 dup2(fds[0], 0);
8079 close(fds[1]);
8081 /* reset signals that we previously set to SIG_IGN */
8082 signal(SIGPIPE, SIG_DFL);
8084 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8085 _exit(1);
8087 else if (pid == -1)
8089 ERR("fork() failed!\n");
8090 goto end;
8093 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8094 write(fds[1], buf, no_read);
8096 close(fds[1]);
8097 fds[1] = -1;
8099 /* reap child */
8100 do {
8101 wret = waitpid(pid, &status, 0);
8102 } while (wret < 0 && errno == EINTR);
8103 if (wret < 0)
8105 ERR("waitpid() failed!\n");
8106 goto end;
8108 if (!WIFEXITED(status) || WEXITSTATUS(status))
8110 ERR("child process failed! %d\n", status);
8111 goto end;
8114 ret = TRUE;
8116 end:
8117 if(file_fd != -1) close(file_fd);
8118 if(fds[0] != -1) close(fds[0]);
8119 if(fds[1] != -1) close(fds[1]);
8121 HeapFree(GetProcessHeap(), 0, cmdA);
8122 HeapFree(GetProcessHeap(), 0, unixname);
8123 return ret;
8124 #else
8125 return FALSE;
8126 #endif
8129 /*****************************************************************************
8130 * schedule_lpr
8132 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8134 WCHAR *cmd;
8135 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8136 BOOL r;
8138 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8139 sprintfW(cmd, fmtW, printer_name);
8141 r = schedule_pipe(cmd, filename);
8143 HeapFree(GetProcessHeap(), 0, cmd);
8144 return r;
8147 #ifdef SONAME_LIBCUPS
8148 /*****************************************************************************
8149 * get_cups_jobs_ticket_options
8151 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8152 * The CUPS scheduler only looks for these in Print-File requests, and since
8153 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8154 * parsed.
8156 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8158 FILE *fp = fopen( file, "r" );
8159 char buf[257]; /* DSC max of 256 + '\0' */
8160 const char *ps_adobe = "%!PS-Adobe-";
8161 const char *cups_job = "%cupsJobTicket:";
8163 if (!fp) return num_options;
8164 if (!fgets( buf, sizeof(buf), fp )) goto end;
8165 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8166 while (fgets( buf, sizeof(buf), fp ))
8168 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8169 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8172 end:
8173 fclose( fp );
8174 return num_options;
8176 #endif
8178 /*****************************************************************************
8179 * schedule_cups
8181 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8183 #ifdef SONAME_LIBCUPS
8184 if(pcupsPrintFile)
8186 char *unixname, *queue, *unix_doc_title;
8187 DWORD len;
8188 BOOL ret;
8189 int num_options = 0, i;
8190 cups_option_t *options = NULL;
8192 if(!(unixname = wine_get_unix_file_name(filename)))
8193 return FALSE;
8195 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8196 queue = HeapAlloc(GetProcessHeap(), 0, len);
8197 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8199 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8200 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8201 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8203 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8205 TRACE( "printing via cups with options:\n" );
8206 for (i = 0; i < num_options; i++)
8207 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8209 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8211 pcupsFreeOptions( num_options, options );
8213 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8214 HeapFree(GetProcessHeap(), 0, queue);
8215 HeapFree(GetProcessHeap(), 0, unixname);
8216 return ret;
8218 else
8219 #endif
8221 return schedule_lpr(printer_name, filename);
8225 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8227 LPWSTR filename;
8229 switch(msg)
8231 case WM_INITDIALOG:
8232 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8233 return TRUE;
8235 case WM_COMMAND:
8236 if(HIWORD(wparam) == BN_CLICKED)
8238 if(LOWORD(wparam) == IDOK)
8240 HANDLE hf;
8241 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8242 LPWSTR *output;
8244 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8245 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8247 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8249 WCHAR caption[200], message[200];
8250 int mb_ret;
8252 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8253 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8254 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8255 if(mb_ret == IDCANCEL)
8257 HeapFree(GetProcessHeap(), 0, filename);
8258 return TRUE;
8261 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8262 if(hf == INVALID_HANDLE_VALUE)
8264 WCHAR caption[200], message[200];
8266 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8267 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8268 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8269 HeapFree(GetProcessHeap(), 0, filename);
8270 return TRUE;
8272 CloseHandle(hf);
8273 DeleteFileW(filename);
8274 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8275 *output = filename;
8276 EndDialog(hwnd, IDOK);
8277 return TRUE;
8279 if(LOWORD(wparam) == IDCANCEL)
8281 EndDialog(hwnd, IDCANCEL);
8282 return TRUE;
8285 return FALSE;
8287 return FALSE;
8290 /*****************************************************************************
8291 * get_filename
8293 static BOOL get_filename(LPWSTR *filename)
8295 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8296 file_dlg_proc, (LPARAM)filename) == IDOK;
8299 /*****************************************************************************
8300 * schedule_file
8302 static BOOL schedule_file(LPCWSTR filename)
8304 LPWSTR output = NULL;
8306 if(get_filename(&output))
8308 BOOL r;
8309 TRACE("copy to %s\n", debugstr_w(output));
8310 r = CopyFileW(filename, output, FALSE);
8311 HeapFree(GetProcessHeap(), 0, output);
8312 return r;
8314 return FALSE;
8317 /*****************************************************************************
8318 * schedule_unixfile
8320 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8322 int in_fd, out_fd, no_read;
8323 char buf[1024];
8324 BOOL ret = FALSE;
8325 char *unixname, *outputA;
8326 DWORD len;
8328 if(!(unixname = wine_get_unix_file_name(filename)))
8329 return FALSE;
8331 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8332 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8333 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8335 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8336 in_fd = open(unixname, O_RDONLY);
8337 if(out_fd == -1 || in_fd == -1)
8338 goto end;
8340 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8341 write(out_fd, buf, no_read);
8343 ret = TRUE;
8344 end:
8345 if(in_fd != -1) close(in_fd);
8346 if(out_fd != -1) close(out_fd);
8347 HeapFree(GetProcessHeap(), 0, outputA);
8348 HeapFree(GetProcessHeap(), 0, unixname);
8349 return ret;
8352 /*****************************************************************************
8353 * ScheduleJob [WINSPOOL.@]
8356 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8358 opened_printer_t *printer;
8359 BOOL ret = FALSE;
8360 struct list *cursor, *cursor2;
8362 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8363 EnterCriticalSection(&printer_handles_cs);
8364 printer = get_opened_printer(hPrinter);
8365 if(!printer)
8366 goto end;
8368 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8370 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8371 HANDLE hf;
8373 if(job->job_id != dwJobID) continue;
8375 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8376 if(hf != INVALID_HANDLE_VALUE)
8378 PRINTER_INFO_5W *pi5 = NULL;
8379 LPWSTR portname = job->portname;
8380 DWORD needed;
8381 HKEY hkey;
8382 WCHAR output[1024];
8383 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8384 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8386 if (!portname)
8388 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8389 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8390 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8391 portname = pi5->pPortName;
8393 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8394 debugstr_w(portname));
8396 output[0] = 0;
8398 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8399 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8401 DWORD type, count = sizeof(output);
8402 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8403 RegCloseKey(hkey);
8405 if(output[0] == '|')
8407 ret = schedule_pipe(output + 1, job->filename);
8409 else if(output[0])
8411 ret = schedule_unixfile(output, job->filename);
8413 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8415 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8417 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8419 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8421 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8423 ret = schedule_file(job->filename);
8425 else
8427 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8429 HeapFree(GetProcessHeap(), 0, pi5);
8430 CloseHandle(hf);
8431 DeleteFileW(job->filename);
8433 list_remove(cursor);
8434 HeapFree(GetProcessHeap(), 0, job->document_title);
8435 HeapFree(GetProcessHeap(), 0, job->printer_name);
8436 HeapFree(GetProcessHeap(), 0, job->portname);
8437 HeapFree(GetProcessHeap(), 0, job->filename);
8438 HeapFree(GetProcessHeap(), 0, job->devmode);
8439 HeapFree(GetProcessHeap(), 0, job);
8440 break;
8442 end:
8443 LeaveCriticalSection(&printer_handles_cs);
8444 return ret;
8447 /*****************************************************************************
8448 * StartDocDlgA [WINSPOOL.@]
8450 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8452 UNICODE_STRING usBuffer;
8453 DOCINFOW docW;
8454 LPWSTR retW;
8455 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8456 LPSTR ret = NULL;
8458 docW.cbSize = sizeof(docW);
8459 if (doc->lpszDocName)
8461 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8462 if (!(docW.lpszDocName = docnameW)) return NULL;
8464 if (doc->lpszOutput)
8466 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8467 if (!(docW.lpszOutput = outputW)) return NULL;
8469 if (doc->lpszDatatype)
8471 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8472 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8474 docW.fwType = doc->fwType;
8476 retW = StartDocDlgW(hPrinter, &docW);
8478 if(retW)
8480 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8481 ret = HeapAlloc(GetProcessHeap(), 0, len);
8482 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8483 HeapFree(GetProcessHeap(), 0, retW);
8486 HeapFree(GetProcessHeap(), 0, datatypeW);
8487 HeapFree(GetProcessHeap(), 0, outputW);
8488 HeapFree(GetProcessHeap(), 0, docnameW);
8490 return ret;
8493 /*****************************************************************************
8494 * StartDocDlgW [WINSPOOL.@]
8496 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8497 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8498 * port is "FILE:". Also returns the full path if passed a relative path.
8500 * The caller should free the returned string from the process heap.
8502 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8504 LPWSTR ret = NULL;
8505 DWORD len, attr;
8507 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8509 PRINTER_INFO_5W *pi5;
8510 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8511 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8512 return NULL;
8513 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8514 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8515 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8517 HeapFree(GetProcessHeap(), 0, pi5);
8518 return NULL;
8520 HeapFree(GetProcessHeap(), 0, pi5);
8523 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8525 LPWSTR name;
8527 if (get_filename(&name))
8529 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8531 HeapFree(GetProcessHeap(), 0, name);
8532 return NULL;
8534 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8535 GetFullPathNameW(name, len, ret, NULL);
8536 HeapFree(GetProcessHeap(), 0, name);
8538 return ret;
8541 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8542 return NULL;
8544 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8545 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8547 attr = GetFileAttributesW(ret);
8548 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8550 HeapFree(GetProcessHeap(), 0, ret);
8551 ret = NULL;
8553 return ret;