wined3d: Pass the pixel shader input signature to shader_arb_generate_vshader.
[wine.git] / dlls / winspool.drv / info.c
blobfc74e7606f7ddbe5ca6cb8621c246525bbcaa942
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 );
837 if (http_status != HTTP_OK) unlink( unix_name );
838 HeapFree( GetProcessHeap(), 0, unix_name );
840 if (http_status == HTTP_OK) return TRUE;
842 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
843 debugstr_a(printer_name), http_status );
844 return get_fallback_ppd( printer_name, ppd );
847 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
849 const char *value;
850 WCHAR *ret;
851 int len;
853 value = pcupsGetOption( name, num_options, options );
854 if (!value) return NULL;
856 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
857 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
858 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
860 return ret;
863 static cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
865 WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
866 cups_ptype_t ret = 0;
868 if (type && *type)
870 ret = (cups_ptype_t)strtoulW( type, &end, 10 );
871 if (*end) ret = 0;
873 HeapFree( GetProcessHeap(), 0, type );
874 return ret;
877 static void load_cups(void)
879 cupshandle = wine_dlopen( SONAME_LIBCUPS, RTLD_NOW, NULL, 0 );
880 if (!cupshandle) return;
882 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
884 #define DO_FUNC(x) \
885 p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); \
886 if (!p##x) \
888 ERR("failed to load symbol %s\n", #x); \
889 cupshandle = NULL; \
890 return; \
892 CUPS_FUNCS;
893 #undef DO_FUNC
894 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 )
895 CUPS_OPT_FUNCS;
896 #undef DO_FUNC
899 static BOOL CUPS_LoadPrinters(void)
901 int i, nrofdests;
902 BOOL hadprinter = FALSE, haddefault = FALSE;
903 cups_dest_t *dests;
904 PRINTER_INFO_2W pi2;
905 WCHAR *port, *ppd_dir = NULL, *ppd;
906 HKEY hkeyPrinter, hkeyPrinters;
907 WCHAR nameW[MAX_PATH];
908 HANDLE added_printer;
909 cups_ptype_t printer_type;
911 if (!cupshandle) return FALSE;
913 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
914 ERROR_SUCCESS) {
915 ERR("Can't create Printers key\n");
916 return FALSE;
919 nrofdests = pcupsGetDests(&dests);
920 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
921 for (i=0;i<nrofdests;i++) {
922 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
923 printer_type = get_cups_printer_type( dests + i );
925 TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
927 if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
929 TRACE( "skipping scanner-only device\n" );
930 continue;
933 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
934 lstrcpyW(port, CUPS_Port);
935 lstrcatW(port, nameW);
937 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
938 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
939 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
940 and continue */
941 TRACE("Printer already exists\n");
942 /* overwrite old LPR:* port */
943 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
944 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
945 /* flag that the PPD file should be checked for an update */
946 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
947 RegCloseKey(hkeyPrinter);
948 } else {
949 BOOL added_driver = FALSE;
951 if (!ppd_dir) ppd_dir = get_ppd_dir();
952 ppd = get_ppd_filename( ppd_dir, nameW );
953 if (get_cups_ppd( dests[i].name, ppd ))
955 added_driver = add_printer_driver( nameW, ppd );
956 unlink_ppd( ppd );
958 HeapFree( GetProcessHeap(), 0, ppd );
959 if (!added_driver)
961 HeapFree( GetProcessHeap(), 0, port );
962 continue;
965 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
966 pi2.pPrinterName = nameW;
967 pi2.pDatatype = rawW;
968 pi2.pPrintProcessor = WinPrintW;
969 pi2.pDriverName = nameW;
970 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
971 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
972 pi2.pPortName = port;
973 pi2.pParameters = emptyStringW;
974 pi2.pShareName = emptyStringW;
975 pi2.pSepFile = emptyStringW;
977 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
978 if (added_printer) ClosePrinter( added_printer );
979 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
980 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
982 HeapFree( GetProcessHeap(), 0, pi2.pComment );
983 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
985 HeapFree( GetProcessHeap(), 0, port );
987 hadprinter = TRUE;
988 if (dests[i].is_default) {
989 SetDefaultPrinterW(nameW);
990 haddefault = TRUE;
994 if (ppd_dir)
996 RemoveDirectoryW( ppd_dir );
997 HeapFree( GetProcessHeap(), 0, ppd_dir );
1000 if (hadprinter && !haddefault) {
1001 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
1002 SetDefaultPrinterW(nameW);
1004 pcupsFreeDests(nrofdests, dests);
1005 RegCloseKey(hkeyPrinters);
1006 return TRUE;
1009 #endif
1011 static char *get_queue_name( HANDLE printer, BOOL *cups )
1013 WCHAR *port, *name = NULL;
1014 DWORD err, needed, type;
1015 char *ret = NULL;
1016 HKEY key;
1018 *cups = FALSE;
1020 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1021 if (err) return NULL;
1022 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1023 if (err) goto end;
1024 port = HeapAlloc( GetProcessHeap(), 0, needed );
1025 if (!port) goto end;
1026 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1028 if (!strncmpW( port, CUPS_Port, sizeof(CUPS_Port) / sizeof(WCHAR) -1 ))
1030 name = port + sizeof(CUPS_Port) / sizeof(WCHAR) - 1;
1031 *cups = TRUE;
1033 else if (!strncmpW( port, LPR_Port, sizeof(LPR_Port) / sizeof(WCHAR) -1 ))
1034 name = port + sizeof(LPR_Port) / sizeof(WCHAR) - 1;
1035 if (name)
1037 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1038 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1039 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1041 HeapFree( GetProcessHeap(), 0, port );
1042 end:
1043 RegCloseKey( key );
1044 return ret;
1048 static void set_ppd_overrides( HANDLE printer )
1050 WCHAR *wstr = NULL;
1051 int size = 0;
1052 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1053 OSStatus status;
1054 PMPrintSession session = NULL;
1055 PMPageFormat format = NULL;
1056 PMPaper paper;
1057 CFStringRef paper_name;
1058 CFRange range;
1060 status = PMCreateSession( &session );
1061 if (status) goto end;
1063 status = PMCreatePageFormat( &format );
1064 if (status) goto end;
1066 status = PMSessionDefaultPageFormat( session, format );
1067 if (status) goto end;
1069 status = PMGetPageFormatPaper( format, &paper );
1070 if (status) goto end;
1072 status = PMPaperGetPPDPaperName( paper, &paper_name );
1073 if (status) goto end;
1075 range.location = 0;
1076 range.length = CFStringGetLength( paper_name );
1077 size = (range.length + 1) * sizeof(WCHAR);
1079 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1080 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1081 wstr[range.length] = 0;
1083 end:
1084 if (format) PMRelease( format );
1085 if (session) PMRelease( session );
1086 #endif
1088 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1089 HeapFree( GetProcessHeap(), 0, wstr );
1092 static BOOL update_driver( HANDLE printer )
1094 BOOL ret, is_cups;
1095 const WCHAR *name = get_opened_printer_name( printer );
1096 WCHAR *ppd_dir, *ppd;
1097 char *queue_name;
1099 if (!name) return FALSE;
1100 queue_name = get_queue_name( printer, &is_cups );
1101 if (!queue_name) return FALSE;
1103 ppd_dir = get_ppd_dir();
1104 ppd = get_ppd_filename( ppd_dir, name );
1106 #ifdef SONAME_LIBCUPS
1107 if (is_cups)
1108 ret = get_cups_ppd( queue_name, ppd );
1109 else
1110 #endif
1111 ret = get_fallback_ppd( queue_name, ppd );
1113 if (ret)
1115 TRACE( "updating driver %s\n", debugstr_w( name ) );
1116 ret = add_printer_driver( name, ppd );
1117 unlink_ppd( ppd );
1119 HeapFree( GetProcessHeap(), 0, ppd_dir );
1120 HeapFree( GetProcessHeap(), 0, ppd );
1121 HeapFree( GetProcessHeap(), 0, queue_name );
1123 set_ppd_overrides( printer );
1125 /* call into the driver to update the devmode */
1126 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1128 return ret;
1131 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1133 PRINTER_INFO_2A pinfo2a;
1134 const char *r;
1135 size_t name_len;
1136 char *e,*s,*name,*prettyname,*devname;
1137 BOOL ret = FALSE, set_default = FALSE;
1138 char *port = NULL, *env_default;
1139 HKEY hkeyPrinter, hkeyPrinters = NULL;
1140 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1141 HANDLE added_printer;
1143 while (isspace(*pent)) pent++;
1144 r = strchr(pent,':');
1145 if (r)
1146 name_len = r - pent;
1147 else
1148 name_len = strlen(pent);
1149 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1150 memcpy(name, pent, name_len);
1151 name[name_len] = '\0';
1152 if (r)
1153 pent = r;
1154 else
1155 pent = "";
1157 TRACE("name=%s entry=%s\n",name, pent);
1159 if(ispunct(*name)) { /* a tc entry, not a real printer */
1160 TRACE("skipping tc entry\n");
1161 goto end;
1164 if(strstr(pent,":server")) { /* server only version so skip */
1165 TRACE("skipping server entry\n");
1166 goto end;
1169 /* Determine whether this is a postscript printer. */
1171 ret = TRUE;
1172 env_default = getenv("PRINTER");
1173 prettyname = name;
1174 /* Get longest name, usually the one at the right for later display. */
1175 while((s=strchr(prettyname,'|'))) {
1176 *s = '\0';
1177 e = s;
1178 while(isspace(*--e)) *e = '\0';
1179 TRACE("\t%s\n", debugstr_a(prettyname));
1180 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1181 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1184 e = prettyname + strlen(prettyname);
1185 while(isspace(*--e)) *e = '\0';
1186 TRACE("\t%s\n", debugstr_a(prettyname));
1187 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1189 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1190 * if it is too long, we use it as comment below. */
1191 devname = prettyname;
1192 if (strlen(devname)>=CCHDEVICENAME-1)
1193 devname = name;
1194 if (strlen(devname)>=CCHDEVICENAME-1) {
1195 ret = FALSE;
1196 goto end;
1199 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1200 sprintf(port,"LPR:%s",name);
1202 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1203 ERROR_SUCCESS) {
1204 ERR("Can't create Printers key\n");
1205 ret = FALSE;
1206 goto end;
1209 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
1211 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1212 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1213 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1214 and continue */
1215 TRACE("Printer already exists\n");
1216 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1217 /* flag that the PPD file should be checked for an update */
1218 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1219 RegCloseKey(hkeyPrinter);
1220 } else {
1221 static CHAR data_type[] = "RAW",
1222 print_proc[] = "WinPrint",
1223 comment[] = "WINEPS Printer using LPR",
1224 params[] = "<parameters?>",
1225 share_name[] = "<share name?>",
1226 sep_file[] = "<sep file?>";
1227 BOOL added_driver = FALSE;
1229 if (!ppd_dir) ppd_dir = get_ppd_dir();
1230 ppd = get_ppd_filename( ppd_dir, devnameW );
1231 if (get_fallback_ppd( devname, ppd ))
1233 added_driver = add_printer_driver( devnameW, ppd );
1234 unlink_ppd( ppd );
1236 HeapFree( GetProcessHeap(), 0, ppd );
1237 if (!added_driver) goto end;
1239 memset(&pinfo2a,0,sizeof(pinfo2a));
1240 pinfo2a.pPrinterName = devname;
1241 pinfo2a.pDatatype = data_type;
1242 pinfo2a.pPrintProcessor = print_proc;
1243 pinfo2a.pDriverName = devname;
1244 pinfo2a.pComment = comment;
1245 pinfo2a.pLocation = prettyname;
1246 pinfo2a.pPortName = port;
1247 pinfo2a.pParameters = params;
1248 pinfo2a.pShareName = share_name;
1249 pinfo2a.pSepFile = sep_file;
1251 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1252 if (added_printer) ClosePrinter( added_printer );
1253 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1254 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1257 if (isfirst || set_default)
1258 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1260 end:
1261 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1262 if (ppd_dir)
1264 RemoveDirectoryW( ppd_dir );
1265 HeapFree( GetProcessHeap(), 0, ppd_dir );
1267 HeapFree(GetProcessHeap(), 0, port);
1268 HeapFree(GetProcessHeap(), 0, name);
1269 return ret;
1272 static BOOL
1273 PRINTCAP_LoadPrinters(void) {
1274 BOOL hadprinter = FALSE;
1275 char buf[200];
1276 FILE *f;
1277 char *pent = NULL;
1278 BOOL had_bash = FALSE;
1280 f = fopen("/etc/printcap","r");
1281 if (!f)
1282 return FALSE;
1284 while(fgets(buf,sizeof(buf),f)) {
1285 char *start, *end;
1287 end=strchr(buf,'\n');
1288 if (end) *end='\0';
1290 start = buf;
1291 while(isspace(*start)) start++;
1292 if(*start == '#' || *start == '\0')
1293 continue;
1295 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1296 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1297 HeapFree(GetProcessHeap(),0,pent);
1298 pent = NULL;
1301 if (end && *--end == '\\') {
1302 *end = '\0';
1303 had_bash = TRUE;
1304 } else
1305 had_bash = FALSE;
1307 if (pent) {
1308 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1309 strcat(pent,start);
1310 } else {
1311 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1312 strcpy(pent,start);
1316 if(pent) {
1317 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1318 HeapFree(GetProcessHeap(),0,pent);
1320 fclose(f);
1321 return hadprinter;
1324 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1326 if (value)
1327 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1328 (lstrlenW(value) + 1) * sizeof(WCHAR));
1329 else
1330 return ERROR_FILE_NOT_FOUND;
1333 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1335 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1336 DWORD ret = ERROR_FILE_NOT_FOUND;
1338 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1339 and we support these drivers. NT writes DEVMODEW so somehow
1340 we'll need to distinguish between these when we support NT
1341 drivers */
1343 if (dmA)
1345 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1346 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1347 HeapFree( GetProcessHeap(), 0, dmA );
1350 return ret;
1353 /******************************************************************
1354 * get_servername_from_name (internal)
1356 * for an external server, a copy of the serverpart from the full name is returned
1359 static LPWSTR get_servername_from_name(LPCWSTR name)
1361 LPWSTR server;
1362 LPWSTR ptr;
1363 WCHAR buffer[MAX_PATH];
1364 DWORD len;
1366 if (name == NULL) return NULL;
1367 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1369 server = strdupW(&name[2]); /* skip over both backslash */
1370 if (server == NULL) return NULL;
1372 /* strip '\' and the printername */
1373 ptr = strchrW(server, '\\');
1374 if (ptr) ptr[0] = '\0';
1376 TRACE("found %s\n", debugstr_w(server));
1378 len = sizeof(buffer)/sizeof(buffer[0]);
1379 if (GetComputerNameW(buffer, &len)) {
1380 if (lstrcmpW(buffer, server) == 0) {
1381 /* The requested Servername is our computername */
1382 HeapFree(GetProcessHeap(), 0, server);
1383 return NULL;
1386 return server;
1389 /******************************************************************
1390 * get_basename_from_name (internal)
1392 * skip over the serverpart from the full name
1395 static LPCWSTR get_basename_from_name(LPCWSTR name)
1397 if (name == NULL) return NULL;
1398 if ((name[0] == '\\') && (name[1] == '\\')) {
1399 /* skip over the servername and search for the following '\' */
1400 name = strchrW(&name[2], '\\');
1401 if ((name) && (name[1])) {
1402 /* found a separator ('\') followed by a name:
1403 skip over the separator and return the rest */
1404 name++;
1406 else
1408 /* no basename present (we found only a servername) */
1409 return NULL;
1412 return name;
1415 static void free_printer_entry( opened_printer_t *printer )
1417 /* the queue is shared, so don't free that here */
1418 HeapFree( GetProcessHeap(), 0, printer->printername );
1419 HeapFree( GetProcessHeap(), 0, printer->name );
1420 HeapFree( GetProcessHeap(), 0, printer->devmode );
1421 HeapFree( GetProcessHeap(), 0, printer );
1424 /******************************************************************
1425 * get_opened_printer_entry
1426 * Get the first place empty in the opened printer table
1428 * ToDo:
1429 * - pDefault is ignored
1431 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1433 UINT_PTR handle = nb_printer_handles, i;
1434 jobqueue_t *queue = NULL;
1435 opened_printer_t *printer = NULL;
1436 LPWSTR servername;
1437 LPCWSTR printername;
1439 if ((backend == NULL) && !load_backend()) return NULL;
1441 servername = get_servername_from_name(name);
1442 if (servername) {
1443 FIXME("server %s not supported\n", debugstr_w(servername));
1444 HeapFree(GetProcessHeap(), 0, servername);
1445 SetLastError(ERROR_INVALID_PRINTER_NAME);
1446 return NULL;
1449 printername = get_basename_from_name(name);
1450 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1452 /* an empty printername is invalid */
1453 if (printername && (!printername[0])) {
1454 SetLastError(ERROR_INVALID_PARAMETER);
1455 return NULL;
1458 EnterCriticalSection(&printer_handles_cs);
1460 for (i = 0; i < nb_printer_handles; i++)
1462 if (!printer_handles[i])
1464 if(handle == nb_printer_handles)
1465 handle = i;
1467 else
1469 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1470 queue = printer_handles[i]->queue;
1474 if (handle >= nb_printer_handles)
1476 opened_printer_t **new_array;
1477 if (printer_handles)
1478 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1479 (nb_printer_handles + 16) * sizeof(*new_array) );
1480 else
1481 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1482 (nb_printer_handles + 16) * sizeof(*new_array) );
1484 if (!new_array)
1486 handle = 0;
1487 goto end;
1489 printer_handles = new_array;
1490 nb_printer_handles += 16;
1493 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1495 handle = 0;
1496 goto end;
1499 /* get a printer handle from the backend */
1500 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1501 handle = 0;
1502 goto end;
1505 /* clone the base name. This is NULL for the printserver */
1506 printer->printername = strdupW(printername);
1508 /* clone the full name */
1509 printer->name = strdupW(name);
1510 if (name && (!printer->name)) {
1511 handle = 0;
1512 goto end;
1515 if (pDefault && pDefault->pDevMode)
1516 printer->devmode = dup_devmode( pDefault->pDevMode );
1518 if(queue)
1519 printer->queue = queue;
1520 else
1522 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1523 if (!printer->queue) {
1524 handle = 0;
1525 goto end;
1527 list_init(&printer->queue->jobs);
1528 printer->queue->ref = 0;
1530 InterlockedIncrement(&printer->queue->ref);
1532 printer_handles[handle] = printer;
1533 handle++;
1534 end:
1535 LeaveCriticalSection(&printer_handles_cs);
1536 if (!handle && printer) {
1537 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1538 free_printer_entry( printer );
1541 return (HANDLE)handle;
1544 static void old_printer_check( BOOL delete_phase )
1546 PRINTER_INFO_5W* pi;
1547 DWORD needed, type, num, delete, i, size;
1548 const DWORD one = 1;
1549 HKEY key;
1550 HANDLE hprn;
1552 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1553 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1555 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1556 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1557 for (i = 0; i < num; i++)
1559 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1560 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1561 continue;
1563 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1565 if (!delete_phase)
1567 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1568 RegCloseKey( key );
1570 else
1572 delete = 0;
1573 size = sizeof( delete );
1574 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1575 RegCloseKey( key );
1576 if (delete)
1578 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1579 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1581 DeletePrinter( hprn );
1582 ClosePrinter( hprn );
1584 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1588 HeapFree(GetProcessHeap(), 0, pi);
1591 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1592 'M','U','T','E','X','_','_','\0'};
1593 static HANDLE init_mutex;
1595 void WINSPOOL_LoadSystemPrinters(void)
1597 HKEY hkey, hkeyPrinters;
1598 DWORD needed, num, i;
1599 WCHAR PrinterName[256];
1600 BOOL done = FALSE;
1602 #ifdef SONAME_LIBCUPS
1603 load_cups();
1604 #endif
1606 /* FIXME: The init code should be moved to spoolsv.exe */
1607 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1608 if (!init_mutex)
1610 ERR( "Failed to create mutex\n" );
1611 return;
1613 if (GetLastError() == ERROR_ALREADY_EXISTS)
1615 WaitForSingleObject( init_mutex, INFINITE );
1616 ReleaseMutex( init_mutex );
1617 TRACE( "Init already done\n" );
1618 return;
1621 /* This ensures that all printer entries have a valid Name value. If causes
1622 problems later if they don't. If one is found to be missed we create one
1623 and set it equal to the name of the key */
1624 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1625 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1626 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1627 for(i = 0; i < num; i++) {
1628 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1629 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1630 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1631 set_reg_szW(hkey, NameW, PrinterName);
1633 RegCloseKey(hkey);
1638 RegCloseKey(hkeyPrinters);
1641 old_printer_check( FALSE );
1643 #ifdef SONAME_LIBCUPS
1644 done = CUPS_LoadPrinters();
1645 #endif
1647 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1648 PRINTCAP_LoadPrinters();
1650 old_printer_check( TRUE );
1652 ReleaseMutex( init_mutex );
1653 return;
1656 /******************************************************************
1657 * get_job
1659 * Get the pointer to the specified job.
1660 * Should hold the printer_handles_cs before calling.
1662 static job_t *get_job(HANDLE hprn, DWORD JobId)
1664 opened_printer_t *printer = get_opened_printer(hprn);
1665 job_t *job;
1667 if(!printer) return NULL;
1668 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1670 if(job->job_id == JobId)
1671 return job;
1673 return NULL;
1676 /***********************************************************
1677 * DEVMODEcpyAtoW
1679 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1681 BOOL Formname;
1682 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1683 DWORD size;
1685 Formname = (dmA->dmSize > off_formname);
1686 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1687 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1688 dmW->dmDeviceName, CCHDEVICENAME);
1689 if(!Formname) {
1690 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1691 dmA->dmSize - CCHDEVICENAME);
1692 } else {
1693 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1694 off_formname - CCHDEVICENAME);
1695 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1696 dmW->dmFormName, CCHFORMNAME);
1697 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1698 (off_formname + CCHFORMNAME));
1700 dmW->dmSize = size;
1701 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1702 dmA->dmDriverExtra);
1703 return dmW;
1706 /******************************************************************
1707 * convert_printerinfo_W_to_A [internal]
1710 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1711 DWORD level, DWORD outlen, DWORD numentries)
1713 DWORD id = 0;
1714 LPSTR ptr;
1715 INT len;
1717 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1719 len = pi_sizeof[level] * numentries;
1720 ptr = (LPSTR) out + len;
1721 outlen -= len;
1723 /* copy the numbers of all PRINTER_INFO_* first */
1724 memcpy(out, pPrintersW, len);
1726 while (id < numentries) {
1727 switch (level) {
1728 case 1:
1730 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1731 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1733 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1734 if (piW->pDescription) {
1735 piA->pDescription = ptr;
1736 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1737 ptr, outlen, NULL, NULL);
1738 ptr += len;
1739 outlen -= len;
1741 if (piW->pName) {
1742 piA->pName = ptr;
1743 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1744 ptr, outlen, NULL, NULL);
1745 ptr += len;
1746 outlen -= len;
1748 if (piW->pComment) {
1749 piA->pComment = ptr;
1750 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1751 ptr, outlen, NULL, NULL);
1752 ptr += len;
1753 outlen -= len;
1755 break;
1758 case 2:
1760 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1761 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1762 LPDEVMODEA dmA;
1764 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1765 if (piW->pServerName) {
1766 piA->pServerName = ptr;
1767 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1768 ptr, outlen, NULL, NULL);
1769 ptr += len;
1770 outlen -= len;
1772 if (piW->pPrinterName) {
1773 piA->pPrinterName = ptr;
1774 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1775 ptr, outlen, NULL, NULL);
1776 ptr += len;
1777 outlen -= len;
1779 if (piW->pShareName) {
1780 piA->pShareName = ptr;
1781 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1782 ptr, outlen, NULL, NULL);
1783 ptr += len;
1784 outlen -= len;
1786 if (piW->pPortName) {
1787 piA->pPortName = ptr;
1788 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1789 ptr, outlen, NULL, NULL);
1790 ptr += len;
1791 outlen -= len;
1793 if (piW->pDriverName) {
1794 piA->pDriverName = ptr;
1795 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1796 ptr, outlen, NULL, NULL);
1797 ptr += len;
1798 outlen -= len;
1800 if (piW->pComment) {
1801 piA->pComment = ptr;
1802 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1803 ptr, outlen, NULL, NULL);
1804 ptr += len;
1805 outlen -= len;
1807 if (piW->pLocation) {
1808 piA->pLocation = ptr;
1809 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1810 ptr, outlen, NULL, NULL);
1811 ptr += len;
1812 outlen -= len;
1815 dmA = DEVMODEdupWtoA(piW->pDevMode);
1816 if (dmA) {
1817 /* align DEVMODEA to a DWORD boundary */
1818 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1819 ptr += len;
1820 outlen -= len;
1822 piA->pDevMode = (LPDEVMODEA) ptr;
1823 len = dmA->dmSize + dmA->dmDriverExtra;
1824 memcpy(ptr, dmA, len);
1825 HeapFree(GetProcessHeap(), 0, dmA);
1827 ptr += len;
1828 outlen -= len;
1831 if (piW->pSepFile) {
1832 piA->pSepFile = ptr;
1833 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1834 ptr, outlen, NULL, NULL);
1835 ptr += len;
1836 outlen -= len;
1838 if (piW->pPrintProcessor) {
1839 piA->pPrintProcessor = ptr;
1840 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1841 ptr, outlen, NULL, NULL);
1842 ptr += len;
1843 outlen -= len;
1845 if (piW->pDatatype) {
1846 piA->pDatatype = ptr;
1847 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1848 ptr, outlen, NULL, NULL);
1849 ptr += len;
1850 outlen -= len;
1852 if (piW->pParameters) {
1853 piA->pParameters = ptr;
1854 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1855 ptr, outlen, NULL, NULL);
1856 ptr += len;
1857 outlen -= len;
1859 if (piW->pSecurityDescriptor) {
1860 piA->pSecurityDescriptor = NULL;
1861 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1863 break;
1866 case 4:
1868 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1869 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1871 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1873 if (piW->pPrinterName) {
1874 piA->pPrinterName = ptr;
1875 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1876 ptr, outlen, NULL, NULL);
1877 ptr += len;
1878 outlen -= len;
1880 if (piW->pServerName) {
1881 piA->pServerName = ptr;
1882 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1883 ptr, outlen, NULL, NULL);
1884 ptr += len;
1885 outlen -= len;
1887 break;
1890 case 5:
1892 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1893 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1895 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1897 if (piW->pPrinterName) {
1898 piA->pPrinterName = ptr;
1899 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1900 ptr, outlen, NULL, NULL);
1901 ptr += len;
1902 outlen -= len;
1904 if (piW->pPortName) {
1905 piA->pPortName = ptr;
1906 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1907 ptr, outlen, NULL, NULL);
1908 ptr += len;
1909 outlen -= len;
1911 break;
1914 case 6: /* 6A and 6W are the same structure */
1915 break;
1917 case 7:
1919 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1920 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1922 TRACE("(%u) #%u\n", level, id);
1923 if (piW->pszObjectGUID) {
1924 piA->pszObjectGUID = ptr;
1925 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1926 ptr, outlen, NULL, NULL);
1927 ptr += len;
1928 outlen -= len;
1930 break;
1933 case 8:
1934 case 9:
1936 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1937 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1938 LPDEVMODEA dmA;
1940 TRACE("(%u) #%u\n", level, id);
1941 dmA = DEVMODEdupWtoA(piW->pDevMode);
1942 if (dmA) {
1943 /* align DEVMODEA to a DWORD boundary */
1944 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1945 ptr += len;
1946 outlen -= len;
1948 piA->pDevMode = (LPDEVMODEA) ptr;
1949 len = dmA->dmSize + dmA->dmDriverExtra;
1950 memcpy(ptr, dmA, len);
1951 HeapFree(GetProcessHeap(), 0, dmA);
1953 ptr += len;
1954 outlen -= len;
1957 break;
1960 default:
1961 FIXME("for level %u\n", level);
1963 pPrintersW += pi_sizeof[level];
1964 out += pi_sizeof[level];
1965 id++;
1969 /******************************************************************
1970 * convert_driverinfo_W_to_A [internal]
1973 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1974 DWORD level, DWORD outlen, DWORD numentries)
1976 DWORD id = 0;
1977 LPSTR ptr;
1978 INT len;
1980 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1982 len = di_sizeof[level] * numentries;
1983 ptr = (LPSTR) out + len;
1984 outlen -= len;
1986 /* copy the numbers of all PRINTER_INFO_* first */
1987 memcpy(out, pDriversW, len);
1989 #define COPY_STRING(fld) \
1990 { if (diW->fld){ \
1991 diA->fld = ptr; \
1992 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1993 ptr += len; outlen -= len;\
1995 #define COPY_MULTIZ_STRING(fld) \
1996 { LPWSTR p = diW->fld; if (p){ \
1997 diA->fld = ptr; \
1998 do {\
1999 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2000 ptr += len; outlen -= len; p += len;\
2002 while(len > 1 && outlen > 0); \
2005 while (id < numentries)
2007 switch (level)
2009 case 1:
2011 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
2012 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
2014 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2016 COPY_STRING(pName);
2017 break;
2019 case 2:
2021 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2022 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2024 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2026 COPY_STRING(pName);
2027 COPY_STRING(pEnvironment);
2028 COPY_STRING(pDriverPath);
2029 COPY_STRING(pDataFile);
2030 COPY_STRING(pConfigFile);
2031 break;
2033 case 3:
2035 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2036 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2038 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2040 COPY_STRING(pName);
2041 COPY_STRING(pEnvironment);
2042 COPY_STRING(pDriverPath);
2043 COPY_STRING(pDataFile);
2044 COPY_STRING(pConfigFile);
2045 COPY_STRING(pHelpFile);
2046 COPY_MULTIZ_STRING(pDependentFiles);
2047 COPY_STRING(pMonitorName);
2048 COPY_STRING(pDefaultDataType);
2049 break;
2051 case 4:
2053 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2054 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2056 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2058 COPY_STRING(pName);
2059 COPY_STRING(pEnvironment);
2060 COPY_STRING(pDriverPath);
2061 COPY_STRING(pDataFile);
2062 COPY_STRING(pConfigFile);
2063 COPY_STRING(pHelpFile);
2064 COPY_MULTIZ_STRING(pDependentFiles);
2065 COPY_STRING(pMonitorName);
2066 COPY_STRING(pDefaultDataType);
2067 COPY_MULTIZ_STRING(pszzPreviousNames);
2068 break;
2070 case 5:
2072 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2073 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2075 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2077 COPY_STRING(pName);
2078 COPY_STRING(pEnvironment);
2079 COPY_STRING(pDriverPath);
2080 COPY_STRING(pDataFile);
2081 COPY_STRING(pConfigFile);
2082 break;
2084 case 6:
2086 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2087 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2089 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2091 COPY_STRING(pName);
2092 COPY_STRING(pEnvironment);
2093 COPY_STRING(pDriverPath);
2094 COPY_STRING(pDataFile);
2095 COPY_STRING(pConfigFile);
2096 COPY_STRING(pHelpFile);
2097 COPY_MULTIZ_STRING(pDependentFiles);
2098 COPY_STRING(pMonitorName);
2099 COPY_STRING(pDefaultDataType);
2100 COPY_MULTIZ_STRING(pszzPreviousNames);
2101 COPY_STRING(pszMfgName);
2102 COPY_STRING(pszOEMUrl);
2103 COPY_STRING(pszHardwareID);
2104 COPY_STRING(pszProvider);
2105 break;
2107 case 8:
2109 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2110 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2112 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2114 COPY_STRING(pName);
2115 COPY_STRING(pEnvironment);
2116 COPY_STRING(pDriverPath);
2117 COPY_STRING(pDataFile);
2118 COPY_STRING(pConfigFile);
2119 COPY_STRING(pHelpFile);
2120 COPY_MULTIZ_STRING(pDependentFiles);
2121 COPY_STRING(pMonitorName);
2122 COPY_STRING(pDefaultDataType);
2123 COPY_MULTIZ_STRING(pszzPreviousNames);
2124 COPY_STRING(pszMfgName);
2125 COPY_STRING(pszOEMUrl);
2126 COPY_STRING(pszHardwareID);
2127 COPY_STRING(pszProvider);
2128 COPY_STRING(pszPrintProcessor);
2129 COPY_STRING(pszVendorSetup);
2130 COPY_MULTIZ_STRING(pszzColorProfiles);
2131 COPY_STRING(pszInfPath);
2132 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2133 break;
2137 default:
2138 FIXME("for level %u\n", level);
2141 pDriversW += di_sizeof[level];
2142 out += di_sizeof[level];
2143 id++;
2146 #undef COPY_STRING
2147 #undef COPY_MULTIZ_STRING
2151 /***********************************************************
2152 * printer_info_AtoW
2154 static void *printer_info_AtoW( const void *data, DWORD level )
2156 void *ret;
2157 UNICODE_STRING usBuffer;
2159 if (!data) return NULL;
2161 if (level < 1 || level > 9) return NULL;
2163 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2164 if (!ret) return NULL;
2166 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2168 switch (level)
2170 case 2:
2172 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2173 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2175 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2176 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2177 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2178 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2179 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2180 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2181 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2182 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2183 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2184 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2185 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2186 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2187 break;
2190 case 8:
2191 case 9:
2193 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2194 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2196 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2197 break;
2200 default:
2201 FIXME( "Unhandled level %d\n", level );
2202 HeapFree( GetProcessHeap(), 0, ret );
2203 return NULL;
2206 return ret;
2209 /***********************************************************
2210 * free_printer_info
2212 static void free_printer_info( void *data, DWORD level )
2214 if (!data) return;
2216 switch (level)
2218 case 2:
2220 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2222 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2223 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2224 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2225 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2226 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2227 HeapFree( GetProcessHeap(), 0, piW->pComment );
2228 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2229 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2230 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2231 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2232 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2233 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2234 break;
2237 case 8:
2238 case 9:
2240 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2242 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2243 break;
2246 default:
2247 FIXME( "Unhandled level %d\n", level );
2250 HeapFree( GetProcessHeap(), 0, data );
2251 return;
2254 /******************************************************************
2255 * DeviceCapabilities [WINSPOOL.@]
2256 * DeviceCapabilitiesA [WINSPOOL.@]
2259 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2260 LPSTR pOutput, LPDEVMODEA lpdm)
2262 INT ret;
2264 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice), debugstr_a(pPort), cap, pOutput, lpdm);
2266 if (!GDI_CallDeviceCapabilities16)
2268 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2269 (LPCSTR)104 );
2270 if (!GDI_CallDeviceCapabilities16) return -1;
2272 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2274 /* If DC_PAPERSIZE map POINT16s to POINTs */
2275 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2276 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2277 POINT *pt = (POINT *)pOutput;
2278 INT i;
2279 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2280 for(i = 0; i < ret; i++, pt++)
2282 pt->x = tmp[i].x;
2283 pt->y = tmp[i].y;
2285 HeapFree( GetProcessHeap(), 0, tmp );
2287 return ret;
2291 /*****************************************************************************
2292 * DeviceCapabilitiesW [WINSPOOL.@]
2294 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2297 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2298 WORD fwCapability, LPWSTR pOutput,
2299 const DEVMODEW *pDevMode)
2301 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2302 LPSTR pDeviceA = strdupWtoA(pDevice);
2303 LPSTR pPortA = strdupWtoA(pPort);
2304 INT ret;
2306 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability, pOutput, pDevMode);
2308 if(pOutput && (fwCapability == DC_BINNAMES ||
2309 fwCapability == DC_FILEDEPENDENCIES ||
2310 fwCapability == DC_PAPERNAMES)) {
2311 /* These need A -> W translation */
2312 INT size = 0, i;
2313 LPSTR pOutputA;
2314 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2315 dmA);
2316 if(ret == -1)
2317 return ret;
2318 switch(fwCapability) {
2319 case DC_BINNAMES:
2320 size = 24;
2321 break;
2322 case DC_PAPERNAMES:
2323 case DC_FILEDEPENDENCIES:
2324 size = 64;
2325 break;
2327 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2328 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2329 dmA);
2330 for(i = 0; i < ret; i++)
2331 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2332 pOutput + (i * size), size);
2333 HeapFree(GetProcessHeap(), 0, pOutputA);
2334 } else {
2335 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2336 (LPSTR)pOutput, dmA);
2338 HeapFree(GetProcessHeap(),0,pPortA);
2339 HeapFree(GetProcessHeap(),0,pDeviceA);
2340 HeapFree(GetProcessHeap(),0,dmA);
2341 return ret;
2344 /******************************************************************
2345 * DocumentPropertiesA [WINSPOOL.@]
2347 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2349 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2350 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2351 LPDEVMODEA pDevModeInput,DWORD fMode )
2353 LPSTR lpName = pDeviceName;
2354 static CHAR port[] = "LPT1:";
2355 LONG ret;
2357 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2358 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2361 if(!pDeviceName || !*pDeviceName) {
2362 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2363 if(!lpNameW) {
2364 ERR("no name from hPrinter?\n");
2365 SetLastError(ERROR_INVALID_HANDLE);
2366 return -1;
2368 lpName = strdupWtoA(lpNameW);
2371 if (!GDI_CallExtDeviceMode16)
2373 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2374 (LPCSTR)102 );
2375 if (!GDI_CallExtDeviceMode16) {
2376 ERR("No CallExtDeviceMode16?\n");
2377 return -1;
2380 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2381 pDevModeInput, NULL, fMode);
2383 if(!pDeviceName)
2384 HeapFree(GetProcessHeap(),0,lpName);
2385 return ret;
2389 /*****************************************************************************
2390 * DocumentPropertiesW (WINSPOOL.@)
2392 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2394 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2395 LPWSTR pDeviceName,
2396 LPDEVMODEW pDevModeOutput,
2397 LPDEVMODEW pDevModeInput, DWORD fMode)
2400 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2401 LPDEVMODEA pDevModeInputA;
2402 LPDEVMODEA pDevModeOutputA = NULL;
2403 LONG ret;
2405 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2406 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2407 fMode);
2408 if(pDevModeOutput) {
2409 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2410 if(ret < 0) return ret;
2411 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2413 pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2414 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2415 pDevModeInputA, fMode);
2416 if(pDevModeOutput) {
2417 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2418 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2420 if(fMode == 0 && ret > 0)
2421 ret += (CCHDEVICENAME + CCHFORMNAME);
2422 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2423 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2424 return ret;
2427 /*****************************************************************************
2428 * IsValidDevmodeA [WINSPOOL.@]
2430 * Validate a DEVMODE structure and fix errors if possible.
2433 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2435 FIXME("(%p,%ld): stub\n", pDevMode, size);
2437 if(!pDevMode)
2438 return FALSE;
2440 return TRUE;
2443 /*****************************************************************************
2444 * IsValidDevmodeW [WINSPOOL.@]
2446 * Validate a DEVMODE structure and fix errors if possible.
2449 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2451 FIXME("(%p,%ld): stub\n", pDevMode, size);
2453 if(!pDevMode)
2454 return FALSE;
2456 return TRUE;
2459 /******************************************************************
2460 * OpenPrinterA [WINSPOOL.@]
2462 * See OpenPrinterW.
2465 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2466 LPPRINTER_DEFAULTSA pDefault)
2468 UNICODE_STRING lpPrinterNameW;
2469 UNICODE_STRING usBuffer;
2470 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2471 PWSTR pwstrPrinterNameW;
2472 BOOL ret;
2474 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName), phPrinter, pDefault);
2476 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2478 if(pDefault) {
2479 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2480 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2481 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2482 pDefaultW = &DefaultW;
2484 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2485 if(pDefault) {
2486 RtlFreeUnicodeString(&usBuffer);
2487 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2489 RtlFreeUnicodeString(&lpPrinterNameW);
2490 return ret;
2493 /******************************************************************
2494 * OpenPrinterW [WINSPOOL.@]
2496 * Open a Printer / Printserver or a Printer-Object
2498 * PARAMS
2499 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2500 * phPrinter [O] The resulting Handle is stored here
2501 * pDefault [I] PTR to Default Printer Settings or NULL
2503 * RETURNS
2504 * Success: TRUE
2505 * Failure: FALSE
2507 * NOTES
2508 * lpPrinterName is one of:
2509 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2510 *| Printer: "PrinterName"
2511 *| Printer-Object: "PrinterName,Job xxx"
2512 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2513 *| XcvPort: "Servername,XcvPort PortName"
2515 * BUGS
2516 *| Printer-Object not supported
2517 *| pDefaults is ignored
2520 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2523 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2525 if(!phPrinter) {
2526 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2527 SetLastError(ERROR_INVALID_PARAMETER);
2528 return FALSE;
2531 /* Get the unique handle of the printer or Printserver */
2532 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2534 if (*phPrinter)
2536 HKEY key;
2537 DWORD deleting = 0, size = sizeof( deleting ), type;
2538 DWORD status;
2539 WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key );
2540 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2541 WaitForSingleObject( init_mutex, INFINITE );
2542 status = get_dword_from_reg( key, StatusW );
2543 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2544 ReleaseMutex( init_mutex );
2545 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2546 update_driver( *phPrinter );
2547 RegCloseKey( key );
2550 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2551 return (*phPrinter != 0);
2554 /******************************************************************
2555 * AddMonitorA [WINSPOOL.@]
2557 * See AddMonitorW.
2560 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2562 LPWSTR nameW = NULL;
2563 INT len;
2564 BOOL res;
2565 LPMONITOR_INFO_2A mi2a;
2566 MONITOR_INFO_2W mi2w;
2568 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2569 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2570 debugstr_a(mi2a ? mi2a->pName : NULL),
2571 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2572 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2574 if (Level != 2) {
2575 SetLastError(ERROR_INVALID_LEVEL);
2576 return FALSE;
2579 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2580 if (mi2a == NULL) {
2581 return FALSE;
2584 if (pName) {
2585 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2586 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2587 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2590 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2591 if (mi2a->pName) {
2592 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2593 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2594 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2596 if (mi2a->pEnvironment) {
2597 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2598 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2599 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2601 if (mi2a->pDLLName) {
2602 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2603 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2604 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2607 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2609 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2610 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2611 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2613 HeapFree(GetProcessHeap(), 0, nameW);
2614 return (res);
2617 /******************************************************************************
2618 * AddMonitorW [WINSPOOL.@]
2620 * Install a Printmonitor
2622 * PARAMS
2623 * pName [I] Servername or NULL (local Computer)
2624 * Level [I] Structure-Level (Must be 2)
2625 * pMonitors [I] PTR to MONITOR_INFO_2
2627 * RETURNS
2628 * Success: TRUE
2629 * Failure: FALSE
2631 * NOTES
2632 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2635 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2637 LPMONITOR_INFO_2W mi2w;
2639 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2640 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2641 debugstr_w(mi2w ? mi2w->pName : NULL),
2642 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2643 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2645 if ((backend == NULL) && !load_backend()) return FALSE;
2647 if (Level != 2) {
2648 SetLastError(ERROR_INVALID_LEVEL);
2649 return FALSE;
2652 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2653 if (mi2w == NULL) {
2654 return FALSE;
2657 return backend->fpAddMonitor(pName, Level, pMonitors);
2660 /******************************************************************
2661 * DeletePrinterDriverA [WINSPOOL.@]
2664 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2666 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2669 /******************************************************************
2670 * DeletePrinterDriverW [WINSPOOL.@]
2673 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2675 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2678 /******************************************************************
2679 * DeleteMonitorA [WINSPOOL.@]
2681 * See DeleteMonitorW.
2684 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2686 LPWSTR nameW = NULL;
2687 LPWSTR EnvironmentW = NULL;
2688 LPWSTR MonitorNameW = NULL;
2689 BOOL res;
2690 INT len;
2692 if (pName) {
2693 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2694 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2695 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2698 if (pEnvironment) {
2699 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2700 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2701 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2703 if (pMonitorName) {
2704 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2705 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2706 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2709 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2711 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2712 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2713 HeapFree(GetProcessHeap(), 0, nameW);
2714 return (res);
2717 /******************************************************************
2718 * DeleteMonitorW [WINSPOOL.@]
2720 * Delete a specific Printmonitor from a Printing-Environment
2722 * PARAMS
2723 * pName [I] Servername or NULL (local Computer)
2724 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2725 * pMonitorName [I] Name of the Monitor, that should be deleted
2727 * RETURNS
2728 * Success: TRUE
2729 * Failure: FALSE
2731 * NOTES
2732 * pEnvironment is ignored in Windows for the local Computer.
2735 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2738 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2739 debugstr_w(pMonitorName));
2741 if ((backend == NULL) && !load_backend()) return FALSE;
2743 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2747 /******************************************************************
2748 * DeletePortA [WINSPOOL.@]
2750 * See DeletePortW.
2753 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2755 LPWSTR nameW = NULL;
2756 LPWSTR portW = NULL;
2757 INT len;
2758 DWORD res;
2760 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2762 /* convert servername to unicode */
2763 if (pName) {
2764 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2765 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2766 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2769 /* convert portname to unicode */
2770 if (pPortName) {
2771 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2772 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2773 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2776 res = DeletePortW(nameW, hWnd, portW);
2777 HeapFree(GetProcessHeap(), 0, nameW);
2778 HeapFree(GetProcessHeap(), 0, portW);
2779 return res;
2782 /******************************************************************
2783 * DeletePortW [WINSPOOL.@]
2785 * Delete a specific Port
2787 * PARAMS
2788 * pName [I] Servername or NULL (local Computer)
2789 * hWnd [I] Handle to parent Window for the Dialog-Box
2790 * pPortName [I] Name of the Port, that should be deleted
2792 * RETURNS
2793 * Success: TRUE
2794 * Failure: FALSE
2797 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2799 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2801 if ((backend == NULL) && !load_backend()) return FALSE;
2803 if (!pPortName) {
2804 SetLastError(RPC_X_NULL_REF_POINTER);
2805 return FALSE;
2808 return backend->fpDeletePort(pName, hWnd, pPortName);
2811 /******************************************************************************
2812 * WritePrinter [WINSPOOL.@]
2814 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2816 opened_printer_t *printer;
2817 BOOL ret = FALSE;
2819 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2821 EnterCriticalSection(&printer_handles_cs);
2822 printer = get_opened_printer(hPrinter);
2823 if(!printer)
2825 SetLastError(ERROR_INVALID_HANDLE);
2826 goto end;
2829 if(!printer->doc)
2831 SetLastError(ERROR_SPL_NO_STARTDOC);
2832 goto end;
2835 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2836 end:
2837 LeaveCriticalSection(&printer_handles_cs);
2838 return ret;
2841 /*****************************************************************************
2842 * AddFormA [WINSPOOL.@]
2844 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2846 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2847 return 1;
2850 /*****************************************************************************
2851 * AddFormW [WINSPOOL.@]
2853 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2855 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2856 return 1;
2859 /*****************************************************************************
2860 * AddJobA [WINSPOOL.@]
2862 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2864 BOOL ret;
2865 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2866 DWORD needed;
2868 if(Level != 1) {
2869 SetLastError(ERROR_INVALID_LEVEL);
2870 return FALSE;
2873 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2875 if(ret) {
2876 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2877 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2878 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2879 if(*pcbNeeded > cbBuf) {
2880 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2881 ret = FALSE;
2882 } else {
2883 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2884 addjobA->JobId = addjobW->JobId;
2885 addjobA->Path = (char *)(addjobA + 1);
2886 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2889 return ret;
2892 /*****************************************************************************
2893 * AddJobW [WINSPOOL.@]
2895 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2897 opened_printer_t *printer;
2898 job_t *job;
2899 BOOL ret = FALSE;
2900 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2901 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2902 WCHAR path[MAX_PATH], filename[MAX_PATH];
2903 DWORD len;
2904 ADDJOB_INFO_1W *addjob;
2906 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2908 EnterCriticalSection(&printer_handles_cs);
2910 printer = get_opened_printer(hPrinter);
2912 if(!printer) {
2913 SetLastError(ERROR_INVALID_HANDLE);
2914 goto end;
2917 if(Level != 1) {
2918 SetLastError(ERROR_INVALID_LEVEL);
2919 goto end;
2922 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2923 if(!job)
2924 goto end;
2926 job->job_id = InterlockedIncrement(&next_job_id);
2928 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2929 if(path[len - 1] != '\\')
2930 path[len++] = '\\';
2931 memcpy(path + len, spool_path, sizeof(spool_path));
2932 sprintfW(filename, fmtW, path, job->job_id);
2934 len = strlenW(filename);
2935 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2936 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2937 job->portname = NULL;
2938 job->document_title = strdupW(default_doc_title);
2939 job->printer_name = strdupW(printer->name);
2940 job->devmode = dup_devmode( printer->devmode );
2941 list_add_tail(&printer->queue->jobs, &job->entry);
2943 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2944 if(*pcbNeeded <= cbBuf) {
2945 addjob = (ADDJOB_INFO_1W*)pData;
2946 addjob->JobId = job->job_id;
2947 addjob->Path = (WCHAR *)(addjob + 1);
2948 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2949 ret = TRUE;
2950 } else
2951 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2953 end:
2954 LeaveCriticalSection(&printer_handles_cs);
2955 return ret;
2958 /*****************************************************************************
2959 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2961 * Return the PATH for the Print-Processors
2963 * See GetPrintProcessorDirectoryW.
2967 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2968 DWORD level, LPBYTE Info,
2969 DWORD cbBuf, LPDWORD pcbNeeded)
2971 LPWSTR serverW = NULL;
2972 LPWSTR envW = NULL;
2973 BOOL ret;
2974 INT len;
2976 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2977 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2980 if (server) {
2981 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2982 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2983 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2986 if (env) {
2987 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2988 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2989 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2992 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2993 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2995 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2996 cbBuf, pcbNeeded);
2998 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2999 cbBuf, NULL, NULL) > 0;
3002 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3003 HeapFree(GetProcessHeap(), 0, envW);
3004 HeapFree(GetProcessHeap(), 0, serverW);
3005 return ret;
3008 /*****************************************************************************
3009 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3011 * Return the PATH for the Print-Processors
3013 * PARAMS
3014 * server [I] Servername (NT only) or NULL (local Computer)
3015 * env [I] Printing-Environment (see below) or NULL (Default)
3016 * level [I] Structure-Level (must be 1)
3017 * Info [O] PTR to Buffer that receives the Result
3018 * cbBuf [I] Size of Buffer at "Info"
3019 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3020 * required for the Buffer at "Info"
3022 * RETURNS
3023 * Success: TRUE and in pcbNeeded the Bytes used in Info
3024 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3025 * if cbBuf is too small
3027 * Native Values returned in Info on Success:
3028 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3029 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3030 *| win9x(Windows 4.0): "%winsysdir%"
3032 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3034 * BUGS
3035 * Only NULL or "" is supported for server
3038 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3039 DWORD level, LPBYTE Info,
3040 DWORD cbBuf, LPDWORD pcbNeeded)
3043 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3044 Info, cbBuf, pcbNeeded);
3046 if ((backend == NULL) && !load_backend()) return FALSE;
3048 if (level != 1) {
3049 /* (Level != 1) is ignored in win9x */
3050 SetLastError(ERROR_INVALID_LEVEL);
3051 return FALSE;
3054 if (pcbNeeded == NULL) {
3055 /* (pcbNeeded == NULL) is ignored in win9x */
3056 SetLastError(RPC_X_NULL_REF_POINTER);
3057 return FALSE;
3060 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3063 /*****************************************************************************
3064 * WINSPOOL_OpenDriverReg [internal]
3066 * opens the registry for the printer drivers depending on the given input
3067 * variable pEnvironment
3069 * RETURNS:
3070 * the opened hkey on success
3071 * NULL on error
3073 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3075 HKEY retval = NULL;
3076 LPWSTR buffer;
3077 const printenv_t * env;
3079 TRACE("(%s)\n", debugstr_w(pEnvironment));
3081 env = validate_envW(pEnvironment);
3082 if (!env) return NULL;
3084 buffer = HeapAlloc( GetProcessHeap(), 0,
3085 (strlenW(DriversW) + strlenW(env->envname) +
3086 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3087 if(buffer) {
3088 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3089 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3090 HeapFree(GetProcessHeap(), 0, buffer);
3092 return retval;
3095 /*****************************************************************************
3096 * set_devices_and_printerports [internal]
3098 * set the [Devices] and [PrinterPorts] entries for a printer.
3101 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3103 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3104 WCHAR *devline;
3105 HKEY hkey;
3107 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3109 /* FIXME: the driver must change to "winspool" */
3110 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3111 if (devline) {
3112 lstrcpyW(devline, driver_nt);
3113 lstrcatW(devline, commaW);
3114 lstrcatW(devline, pi->pPortName);
3116 TRACE("using %s\n", debugstr_w(devline));
3117 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
3118 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3119 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3120 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3121 RegCloseKey(hkey);
3124 lstrcatW(devline, timeout_15_45);
3125 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
3126 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3127 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3128 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3129 RegCloseKey(hkey);
3131 HeapFree(GetProcessHeap(), 0, devline);
3135 /*****************************************************************************
3136 * AddPrinterW [WINSPOOL.@]
3138 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3140 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3141 LPDEVMODEW dm;
3142 HANDLE retval;
3143 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3144 LONG size;
3146 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3148 if(pName != NULL) {
3149 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3150 SetLastError(ERROR_INVALID_PARAMETER);
3151 return 0;
3153 if(Level != 2) {
3154 ERR("Level = %d, unsupported!\n", Level);
3155 SetLastError(ERROR_INVALID_LEVEL);
3156 return 0;
3158 if(!pPrinter) {
3159 SetLastError(ERROR_INVALID_PARAMETER);
3160 return 0;
3162 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3163 ERROR_SUCCESS) {
3164 ERR("Can't create Printers key\n");
3165 return 0;
3167 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3168 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3169 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3170 RegCloseKey(hkeyPrinter);
3171 RegCloseKey(hkeyPrinters);
3172 return 0;
3174 RegCloseKey(hkeyPrinter);
3176 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3177 if(!hkeyDrivers) {
3178 ERR("Can't create Drivers key\n");
3179 RegCloseKey(hkeyPrinters);
3180 return 0;
3182 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3183 ERROR_SUCCESS) {
3184 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3185 RegCloseKey(hkeyPrinters);
3186 RegCloseKey(hkeyDrivers);
3187 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3188 return 0;
3190 RegCloseKey(hkeyDriver);
3191 RegCloseKey(hkeyDrivers);
3193 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3194 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3195 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3196 RegCloseKey(hkeyPrinters);
3197 return 0;
3200 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3201 ERROR_SUCCESS) {
3202 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3203 SetLastError(ERROR_INVALID_PRINTER_NAME);
3204 RegCloseKey(hkeyPrinters);
3205 return 0;
3208 set_devices_and_printerports(pi);
3210 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3211 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3212 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3213 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3214 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3215 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3216 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3217 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3218 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3219 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3220 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3221 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3222 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3223 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3224 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3225 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3226 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3227 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3229 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3231 if (size < 0)
3233 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3234 size = sizeof(DEVMODEW);
3236 if(pi->pDevMode)
3237 dm = pi->pDevMode;
3238 else
3240 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3241 dm->dmSize = size;
3242 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3244 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3245 HeapFree( GetProcessHeap(), 0, dm );
3246 dm = NULL;
3248 else
3250 /* set devmode to printer name */
3251 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3255 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3256 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3258 RegCloseKey(hkeyPrinter);
3259 RegCloseKey(hkeyPrinters);
3260 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3261 ERR("OpenPrinter failing\n");
3262 return 0;
3264 return retval;
3267 /*****************************************************************************
3268 * AddPrinterA [WINSPOOL.@]
3270 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3272 UNICODE_STRING pNameW;
3273 PWSTR pwstrNameW;
3274 PRINTER_INFO_2W *piW;
3275 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3276 HANDLE ret;
3278 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3279 if(Level != 2) {
3280 ERR("Level = %d, unsupported!\n", Level);
3281 SetLastError(ERROR_INVALID_LEVEL);
3282 return 0;
3284 pwstrNameW = asciitounicode(&pNameW,pName);
3285 piW = printer_info_AtoW( piA, Level );
3287 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3289 free_printer_info( piW, Level );
3290 RtlFreeUnicodeString(&pNameW);
3291 return ret;
3295 /*****************************************************************************
3296 * ClosePrinter [WINSPOOL.@]
3298 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3300 UINT_PTR i = (UINT_PTR)hPrinter;
3301 opened_printer_t *printer = NULL;
3302 BOOL ret = FALSE;
3304 TRACE("(%p)\n", hPrinter);
3306 EnterCriticalSection(&printer_handles_cs);
3308 if ((i > 0) && (i <= nb_printer_handles))
3309 printer = printer_handles[i - 1];
3312 if(printer)
3314 struct list *cursor, *cursor2;
3316 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3318 if (printer->backend_printer) {
3319 backend->fpClosePrinter(printer->backend_printer);
3322 if(printer->doc)
3323 EndDocPrinter(hPrinter);
3325 if(InterlockedDecrement(&printer->queue->ref) == 0)
3327 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3329 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3330 ScheduleJob(hPrinter, job->job_id);
3332 HeapFree(GetProcessHeap(), 0, printer->queue);
3335 free_printer_entry( printer );
3336 printer_handles[i - 1] = NULL;
3337 ret = TRUE;
3339 LeaveCriticalSection(&printer_handles_cs);
3340 return ret;
3343 /*****************************************************************************
3344 * DeleteFormA [WINSPOOL.@]
3346 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3348 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3349 return 1;
3352 /*****************************************************************************
3353 * DeleteFormW [WINSPOOL.@]
3355 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3357 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3358 return 1;
3361 /*****************************************************************************
3362 * DeletePrinter [WINSPOOL.@]
3364 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3366 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3367 HKEY hkeyPrinters, hkey;
3368 WCHAR def[MAX_PATH];
3369 DWORD size = sizeof( def ) / sizeof( def[0] );
3371 if(!lpNameW) {
3372 SetLastError(ERROR_INVALID_HANDLE);
3373 return FALSE;
3375 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3376 RegDeleteTreeW(hkeyPrinters, lpNameW);
3377 RegCloseKey(hkeyPrinters);
3379 WriteProfileStringW(devicesW, lpNameW, NULL);
3380 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3382 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3383 RegDeleteValueW(hkey, lpNameW);
3384 RegCloseKey(hkey);
3387 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3388 RegDeleteValueW(hkey, lpNameW);
3389 RegCloseKey(hkey);
3392 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3394 WriteProfileStringW( windowsW, deviceW, NULL );
3395 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3397 RegDeleteValueW( hkey, deviceW );
3398 RegCloseKey( hkey );
3400 SetDefaultPrinterW( NULL );
3403 return TRUE;
3406 /*****************************************************************************
3407 * SetPrinterA [WINSPOOL.@]
3409 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3411 BYTE *dataW = data;
3412 BOOL ret;
3414 if (level != 0)
3416 dataW = printer_info_AtoW( data, level );
3417 if (!dataW) return FALSE;
3420 ret = SetPrinterW( printer, level, dataW, command );
3422 if (dataW != data) free_printer_info( dataW, level );
3424 return ret;
3427 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3429 set_reg_szW( key, NameW, pi->pPrinterName );
3430 set_reg_szW( key, Share_NameW, pi->pShareName );
3431 set_reg_szW( key, PortW, pi->pPortName );
3432 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3433 set_reg_szW( key, DescriptionW, pi->pComment );
3434 set_reg_szW( key, LocationW, pi->pLocation );
3436 if (pi->pDevMode)
3437 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3439 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3440 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3441 set_reg_szW( key, DatatypeW, pi->pDatatype );
3442 set_reg_szW( key, ParametersW, pi->pParameters );
3444 set_reg_DWORD( key, AttributesW, pi->Attributes );
3445 set_reg_DWORD( key, PriorityW, pi->Priority );
3446 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3447 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3448 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3451 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3453 if (!pi->pDevMode) return FALSE;
3455 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3456 return TRUE;
3459 /******************************************************************************
3460 * SetPrinterW [WINSPOOL.@]
3462 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3464 HKEY key;
3465 BOOL ret = FALSE;
3467 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3469 if (command != 0) FIXME( "Ignoring command %d\n", command );
3471 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3472 return FALSE;
3474 switch (level)
3476 case 2:
3478 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3479 set_printer_2( key, pi2 );
3480 ret = TRUE;
3481 break;
3484 case 9:
3486 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3487 ret = set_printer_9( key, pi );
3488 break;
3491 default:
3492 FIXME( "Unimplemented level %d\n", level );
3493 SetLastError( ERROR_INVALID_LEVEL );
3496 RegCloseKey( key );
3497 return ret;
3500 /*****************************************************************************
3501 * SetJobA [WINSPOOL.@]
3503 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3504 LPBYTE pJob, DWORD Command)
3506 BOOL ret;
3507 LPBYTE JobW;
3508 UNICODE_STRING usBuffer;
3510 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3512 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3513 are all ignored by SetJob, so we don't bother copying them */
3514 switch(Level)
3516 case 0:
3517 JobW = NULL;
3518 break;
3519 case 1:
3521 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3522 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3524 JobW = (LPBYTE)info1W;
3525 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3526 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3527 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3528 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3529 info1W->Status = info1A->Status;
3530 info1W->Priority = info1A->Priority;
3531 info1W->Position = info1A->Position;
3532 info1W->PagesPrinted = info1A->PagesPrinted;
3533 break;
3535 case 2:
3537 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3538 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3540 JobW = (LPBYTE)info2W;
3541 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3542 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3543 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3544 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3545 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3546 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3547 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3548 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3549 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3550 info2W->Status = info2A->Status;
3551 info2W->Priority = info2A->Priority;
3552 info2W->Position = info2A->Position;
3553 info2W->StartTime = info2A->StartTime;
3554 info2W->UntilTime = info2A->UntilTime;
3555 info2W->PagesPrinted = info2A->PagesPrinted;
3556 break;
3558 case 3:
3559 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3560 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3561 break;
3562 default:
3563 SetLastError(ERROR_INVALID_LEVEL);
3564 return FALSE;
3567 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3569 switch(Level)
3571 case 1:
3573 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3574 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3575 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3576 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3577 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3578 break;
3580 case 2:
3582 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3583 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3584 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3585 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3586 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3587 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3588 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3589 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3590 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3591 break;
3594 HeapFree(GetProcessHeap(), 0, JobW);
3596 return ret;
3599 /*****************************************************************************
3600 * SetJobW [WINSPOOL.@]
3602 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3603 LPBYTE pJob, DWORD Command)
3605 BOOL ret = FALSE;
3606 job_t *job;
3608 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3609 FIXME("Ignoring everything other than document title\n");
3611 EnterCriticalSection(&printer_handles_cs);
3612 job = get_job(hPrinter, JobId);
3613 if(!job)
3614 goto end;
3616 switch(Level)
3618 case 0:
3619 break;
3620 case 1:
3622 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3623 HeapFree(GetProcessHeap(), 0, job->document_title);
3624 job->document_title = strdupW(info1->pDocument);
3625 break;
3627 case 2:
3629 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3630 HeapFree(GetProcessHeap(), 0, job->document_title);
3631 job->document_title = strdupW(info2->pDocument);
3632 HeapFree(GetProcessHeap(), 0, job->devmode);
3633 job->devmode = dup_devmode( info2->pDevMode );
3634 break;
3636 case 3:
3637 break;
3638 default:
3639 SetLastError(ERROR_INVALID_LEVEL);
3640 goto end;
3642 ret = TRUE;
3643 end:
3644 LeaveCriticalSection(&printer_handles_cs);
3645 return ret;
3648 /*****************************************************************************
3649 * EndDocPrinter [WINSPOOL.@]
3651 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3653 opened_printer_t *printer;
3654 BOOL ret = FALSE;
3655 TRACE("(%p)\n", hPrinter);
3657 EnterCriticalSection(&printer_handles_cs);
3659 printer = get_opened_printer(hPrinter);
3660 if(!printer)
3662 SetLastError(ERROR_INVALID_HANDLE);
3663 goto end;
3666 if(!printer->doc)
3668 SetLastError(ERROR_SPL_NO_STARTDOC);
3669 goto end;
3672 CloseHandle(printer->doc->hf);
3673 ScheduleJob(hPrinter, printer->doc->job_id);
3674 HeapFree(GetProcessHeap(), 0, printer->doc);
3675 printer->doc = NULL;
3676 ret = TRUE;
3677 end:
3678 LeaveCriticalSection(&printer_handles_cs);
3679 return ret;
3682 /*****************************************************************************
3683 * EndPagePrinter [WINSPOOL.@]
3685 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3687 FIXME("(%p): stub\n", hPrinter);
3688 return TRUE;
3691 /*****************************************************************************
3692 * StartDocPrinterA [WINSPOOL.@]
3694 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3696 UNICODE_STRING usBuffer;
3697 DOC_INFO_2W doc2W;
3698 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3699 DWORD ret;
3701 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3702 or one (DOC_INFO_3) extra DWORDs */
3704 switch(Level) {
3705 case 2:
3706 doc2W.JobId = doc2->JobId;
3707 /* fall through */
3708 case 3:
3709 doc2W.dwMode = doc2->dwMode;
3710 /* fall through */
3711 case 1:
3712 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3713 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3714 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3715 break;
3717 default:
3718 SetLastError(ERROR_INVALID_LEVEL);
3719 return FALSE;
3722 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3724 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3725 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3726 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3728 return ret;
3731 /*****************************************************************************
3732 * StartDocPrinterW [WINSPOOL.@]
3734 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3736 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3737 opened_printer_t *printer;
3738 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3739 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3740 JOB_INFO_1W job_info;
3741 DWORD needed, ret = 0;
3742 HANDLE hf;
3743 WCHAR *filename;
3744 job_t *job;
3746 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3747 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3748 debugstr_w(doc->pDatatype));
3750 if(Level < 1 || Level > 3)
3752 SetLastError(ERROR_INVALID_LEVEL);
3753 return 0;
3756 EnterCriticalSection(&printer_handles_cs);
3757 printer = get_opened_printer(hPrinter);
3758 if(!printer)
3760 SetLastError(ERROR_INVALID_HANDLE);
3761 goto end;
3764 if(printer->doc)
3766 SetLastError(ERROR_INVALID_PRINTER_STATE);
3767 goto end;
3770 /* Even if we're printing to a file we still add a print job, we'll
3771 just ignore the spool file name */
3773 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3775 ERR("AddJob failed gle %u\n", GetLastError());
3776 goto end;
3779 /* use pOutputFile only, when it is a real filename */
3780 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3781 filename = doc->pOutputFile;
3782 else
3783 filename = addjob->Path;
3785 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3786 if(hf == INVALID_HANDLE_VALUE)
3787 goto end;
3789 memset(&job_info, 0, sizeof(job_info));
3790 job_info.pDocument = doc->pDocName;
3791 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3793 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3794 printer->doc->hf = hf;
3795 ret = printer->doc->job_id = addjob->JobId;
3796 job = get_job(hPrinter, ret);
3797 job->portname = strdupW(doc->pOutputFile);
3799 end:
3800 LeaveCriticalSection(&printer_handles_cs);
3802 return ret;
3805 /*****************************************************************************
3806 * StartPagePrinter [WINSPOOL.@]
3808 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3810 FIXME("(%p): stub\n", hPrinter);
3811 return TRUE;
3814 /*****************************************************************************
3815 * GetFormA [WINSPOOL.@]
3817 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3818 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3820 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3821 Level,pForm,cbBuf,pcbNeeded);
3822 return FALSE;
3825 /*****************************************************************************
3826 * GetFormW [WINSPOOL.@]
3828 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3829 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3831 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3832 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3833 return FALSE;
3836 /*****************************************************************************
3837 * SetFormA [WINSPOOL.@]
3839 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3840 LPBYTE pForm)
3842 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3843 return FALSE;
3846 /*****************************************************************************
3847 * SetFormW [WINSPOOL.@]
3849 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3850 LPBYTE pForm)
3852 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3853 return FALSE;
3856 /*****************************************************************************
3857 * ReadPrinter [WINSPOOL.@]
3859 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3860 LPDWORD pNoBytesRead)
3862 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3863 return FALSE;
3866 /*****************************************************************************
3867 * ResetPrinterA [WINSPOOL.@]
3869 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3871 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3872 return FALSE;
3875 /*****************************************************************************
3876 * ResetPrinterW [WINSPOOL.@]
3878 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3880 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3881 return FALSE;
3884 /*****************************************************************************
3885 * get_filename_from_reg [internal]
3887 * Get ValueName from hkey storing result in out
3888 * when the Value in the registry has only a filename, use driverdir as prefix
3889 * outlen is space left in out
3890 * String is stored either as unicode or ascii
3894 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3895 LPBYTE out, DWORD outlen, LPDWORD needed)
3897 WCHAR filename[MAX_PATH];
3898 DWORD size;
3899 DWORD type;
3900 LONG ret;
3901 LPWSTR buffer = filename;
3902 LPWSTR ptr;
3904 *needed = 0;
3905 size = sizeof(filename);
3906 buffer[0] = '\0';
3907 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3908 if (ret == ERROR_MORE_DATA) {
3909 TRACE("need dynamic buffer: %u\n", size);
3910 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3911 if (!buffer) {
3912 /* No Memory is bad */
3913 return FALSE;
3915 buffer[0] = '\0';
3916 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3919 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3920 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3921 return FALSE;
3924 ptr = buffer;
3925 while (ptr) {
3926 /* do we have a full path ? */
3927 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3928 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3930 if (!ret) {
3931 /* we must build the full Path */
3932 *needed += dirlen;
3933 if ((out) && (outlen > dirlen)) {
3934 lstrcpyW((LPWSTR)out, driverdir);
3935 out += dirlen;
3936 outlen -= dirlen;
3938 else
3939 out = NULL;
3942 /* write the filename */
3943 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3944 if ((out) && (outlen >= size)) {
3945 lstrcpyW((LPWSTR)out, ptr);
3946 out += size;
3947 outlen -= size;
3949 else
3950 out = NULL;
3951 *needed += size;
3952 ptr += lstrlenW(ptr)+1;
3953 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3956 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3958 /* write the multisz-termination */
3959 if (type == REG_MULTI_SZ) {
3960 size = sizeof(WCHAR);
3962 *needed += size;
3963 if (out && (outlen >= size)) {
3964 memset (out, 0, size);
3967 return TRUE;
3970 /*****************************************************************************
3971 * WINSPOOL_GetStringFromReg
3973 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3974 * String is stored as unicode.
3976 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3977 DWORD buflen, DWORD *needed)
3979 DWORD sz = buflen, type;
3980 LONG ret;
3982 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3983 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3984 WARN("Got ret = %d\n", ret);
3985 *needed = 0;
3986 return FALSE;
3988 /* add space for terminating '\0' */
3989 sz += sizeof(WCHAR);
3990 *needed = sz;
3992 if (ptr)
3993 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3995 return TRUE;
3998 /*****************************************************************************
3999 * WINSPOOL_GetDefaultDevMode
4001 * Get a default DevMode values for wineps.
4003 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr, DWORD buflen, DWORD *needed)
4005 static const WCHAR winepsW[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4007 if (buflen >= sizeof(DEVMODEW))
4009 DEVMODEW *dm = (DEVMODEW *)ptr;
4011 /* the driver will update registry with real values */
4012 memset(dm, 0, sizeof(*dm));
4013 dm->dmSize = sizeof(*dm);
4014 lstrcpyW(dm->dmDeviceName, winepsW);
4016 *needed = sizeof(DEVMODEW);
4019 /*****************************************************************************
4020 * WINSPOOL_GetDevModeFromReg
4022 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4023 * DevMode is stored either as unicode or ascii.
4025 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4026 LPBYTE ptr,
4027 DWORD buflen, DWORD *needed)
4029 DWORD sz = buflen, type;
4030 LONG ret;
4032 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4033 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4034 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4035 if (sz < sizeof(DEVMODEA))
4037 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4038 return FALSE;
4040 /* ensures that dmSize is not erratically bogus if registry is invalid */
4041 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4042 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4043 sz += (CCHDEVICENAME + CCHFORMNAME);
4044 if (ptr && (buflen >= sz)) {
4045 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4046 memcpy(ptr, dmW, sz);
4047 HeapFree(GetProcessHeap(),0,dmW);
4049 *needed = sz;
4050 return TRUE;
4053 /*********************************************************************
4054 * WINSPOOL_GetPrinter_1
4056 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4058 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4059 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4061 DWORD size, left = cbBuf;
4062 BOOL space = (cbBuf > 0);
4063 LPBYTE ptr = buf;
4065 *pcbNeeded = 0;
4067 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4068 if(space && size <= left) {
4069 pi1->pName = (LPWSTR)ptr;
4070 ptr += size;
4071 left -= size;
4072 } else
4073 space = FALSE;
4074 *pcbNeeded += size;
4077 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4078 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4079 if(space && size <= left) {
4080 pi1->pDescription = (LPWSTR)ptr;
4081 ptr += size;
4082 left -= size;
4083 } else
4084 space = FALSE;
4085 *pcbNeeded += size;
4088 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4089 if(space && size <= left) {
4090 pi1->pComment = (LPWSTR)ptr;
4091 ptr += size;
4092 left -= size;
4093 } else
4094 space = FALSE;
4095 *pcbNeeded += size;
4098 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4100 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4101 memset(pi1, 0, sizeof(*pi1));
4103 return space;
4105 /*********************************************************************
4106 * WINSPOOL_GetPrinter_2
4108 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4110 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4111 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4113 DWORD size, left = cbBuf;
4114 BOOL space = (cbBuf > 0);
4115 LPBYTE ptr = buf;
4117 *pcbNeeded = 0;
4119 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4120 if(space && size <= left) {
4121 pi2->pPrinterName = (LPWSTR)ptr;
4122 ptr += size;
4123 left -= size;
4124 } else
4125 space = FALSE;
4126 *pcbNeeded += size;
4128 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4129 if(space && size <= left) {
4130 pi2->pShareName = (LPWSTR)ptr;
4131 ptr += size;
4132 left -= size;
4133 } else
4134 space = FALSE;
4135 *pcbNeeded += size;
4137 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4138 if(space && size <= left) {
4139 pi2->pPortName = (LPWSTR)ptr;
4140 ptr += size;
4141 left -= size;
4142 } else
4143 space = FALSE;
4144 *pcbNeeded += size;
4146 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4147 if(space && size <= left) {
4148 pi2->pDriverName = (LPWSTR)ptr;
4149 ptr += size;
4150 left -= size;
4151 } else
4152 space = FALSE;
4153 *pcbNeeded += size;
4155 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4156 if(space && size <= left) {
4157 pi2->pComment = (LPWSTR)ptr;
4158 ptr += size;
4159 left -= size;
4160 } else
4161 space = FALSE;
4162 *pcbNeeded += size;
4164 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4165 if(space && size <= left) {
4166 pi2->pLocation = (LPWSTR)ptr;
4167 ptr += size;
4168 left -= size;
4169 } else
4170 space = FALSE;
4171 *pcbNeeded += size;
4173 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4174 if(space && size <= left) {
4175 pi2->pDevMode = (LPDEVMODEW)ptr;
4176 ptr += size;
4177 left -= size;
4178 } else
4179 space = FALSE;
4180 *pcbNeeded += size;
4182 else
4184 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4185 if(space && size <= left) {
4186 pi2->pDevMode = (LPDEVMODEW)ptr;
4187 ptr += size;
4188 left -= size;
4189 } else
4190 space = FALSE;
4191 *pcbNeeded += size;
4193 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4194 if(space && size <= left) {
4195 pi2->pSepFile = (LPWSTR)ptr;
4196 ptr += size;
4197 left -= size;
4198 } else
4199 space = FALSE;
4200 *pcbNeeded += size;
4202 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4203 if(space && size <= left) {
4204 pi2->pPrintProcessor = (LPWSTR)ptr;
4205 ptr += size;
4206 left -= size;
4207 } else
4208 space = FALSE;
4209 *pcbNeeded += size;
4211 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4212 if(space && size <= left) {
4213 pi2->pDatatype = (LPWSTR)ptr;
4214 ptr += size;
4215 left -= size;
4216 } else
4217 space = FALSE;
4218 *pcbNeeded += size;
4220 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4221 if(space && size <= left) {
4222 pi2->pParameters = (LPWSTR)ptr;
4223 ptr += size;
4224 left -= size;
4225 } else
4226 space = FALSE;
4227 *pcbNeeded += size;
4229 if(pi2) {
4230 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4231 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4232 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4233 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4234 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4237 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4238 memset(pi2, 0, sizeof(*pi2));
4240 return space;
4243 /*********************************************************************
4244 * WINSPOOL_GetPrinter_4
4246 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4248 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4249 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4251 DWORD size, left = cbBuf;
4252 BOOL space = (cbBuf > 0);
4253 LPBYTE ptr = buf;
4255 *pcbNeeded = 0;
4257 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4258 if(space && size <= left) {
4259 pi4->pPrinterName = (LPWSTR)ptr;
4260 ptr += size;
4261 left -= size;
4262 } else
4263 space = FALSE;
4264 *pcbNeeded += size;
4266 if(pi4) {
4267 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4270 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4271 memset(pi4, 0, sizeof(*pi4));
4273 return space;
4276 /*********************************************************************
4277 * WINSPOOL_GetPrinter_5
4279 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4281 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4282 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4284 DWORD size, left = cbBuf;
4285 BOOL space = (cbBuf > 0);
4286 LPBYTE ptr = buf;
4288 *pcbNeeded = 0;
4290 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4291 if(space && size <= left) {
4292 pi5->pPrinterName = (LPWSTR)ptr;
4293 ptr += size;
4294 left -= size;
4295 } else
4296 space = FALSE;
4297 *pcbNeeded += size;
4299 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4300 if(space && size <= left) {
4301 pi5->pPortName = (LPWSTR)ptr;
4302 ptr += size;
4303 left -= size;
4304 } else
4305 space = FALSE;
4306 *pcbNeeded += size;
4308 if(pi5) {
4309 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4310 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4311 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4314 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4315 memset(pi5, 0, sizeof(*pi5));
4317 return space;
4320 /*********************************************************************
4321 * WINSPOOL_GetPrinter_7
4323 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4325 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4326 DWORD cbBuf, LPDWORD pcbNeeded)
4328 DWORD size, left = cbBuf;
4329 BOOL space = (cbBuf > 0);
4330 LPBYTE ptr = buf;
4332 *pcbNeeded = 0;
4334 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4336 ptr = NULL;
4337 size = sizeof(pi7->pszObjectGUID);
4339 if (space && size <= left) {
4340 pi7->pszObjectGUID = (LPWSTR)ptr;
4341 ptr += size;
4342 left -= size;
4343 } else
4344 space = FALSE;
4345 *pcbNeeded += size;
4346 if (pi7) {
4347 /* We do not have a Directory Service */
4348 pi7->dwAction = DSPRINT_UNPUBLISH;
4351 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4352 memset(pi7, 0, sizeof(*pi7));
4354 return space;
4357 /*********************************************************************
4358 * WINSPOOL_GetPrinter_9
4360 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4362 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4363 DWORD cbBuf, LPDWORD pcbNeeded)
4365 DWORD size;
4366 BOOL space = (cbBuf > 0);
4368 *pcbNeeded = 0;
4370 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4371 if(space && size <= cbBuf) {
4372 pi9->pDevMode = (LPDEVMODEW)buf;
4373 } else
4374 space = FALSE;
4375 *pcbNeeded += size;
4377 else
4379 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4380 if(space && size <= cbBuf) {
4381 pi9->pDevMode = (LPDEVMODEW)buf;
4382 } else
4383 space = FALSE;
4384 *pcbNeeded += size;
4387 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4388 memset(pi9, 0, sizeof(*pi9));
4390 return space;
4393 /*****************************************************************************
4394 * GetPrinterW [WINSPOOL.@]
4396 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4397 DWORD cbBuf, LPDWORD pcbNeeded)
4399 DWORD size, needed = 0, err;
4400 LPBYTE ptr = NULL;
4401 HKEY hkeyPrinter;
4402 BOOL ret;
4404 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4406 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4407 if (err)
4409 SetLastError( err );
4410 return FALSE;
4413 switch(Level) {
4414 case 2:
4416 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4418 size = sizeof(PRINTER_INFO_2W);
4419 if(size <= cbBuf) {
4420 ptr = pPrinter + size;
4421 cbBuf -= size;
4422 memset(pPrinter, 0, size);
4423 } else {
4424 pi2 = NULL;
4425 cbBuf = 0;
4427 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4428 needed += size;
4429 break;
4432 case 4:
4434 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4436 size = sizeof(PRINTER_INFO_4W);
4437 if(size <= cbBuf) {
4438 ptr = pPrinter + size;
4439 cbBuf -= size;
4440 memset(pPrinter, 0, size);
4441 } else {
4442 pi4 = NULL;
4443 cbBuf = 0;
4445 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4446 needed += size;
4447 break;
4451 case 5:
4453 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4455 size = sizeof(PRINTER_INFO_5W);
4456 if(size <= cbBuf) {
4457 ptr = pPrinter + size;
4458 cbBuf -= size;
4459 memset(pPrinter, 0, size);
4460 } else {
4461 pi5 = NULL;
4462 cbBuf = 0;
4465 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4466 needed += size;
4467 break;
4471 case 6:
4473 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4475 size = sizeof(PRINTER_INFO_6);
4476 if (size <= cbBuf) {
4477 /* FIXME: We do not update the status yet */
4478 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4479 ret = TRUE;
4480 } else {
4481 ret = FALSE;
4484 needed += size;
4485 break;
4488 case 7:
4490 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4492 size = sizeof(PRINTER_INFO_7W);
4493 if (size <= cbBuf) {
4494 ptr = pPrinter + size;
4495 cbBuf -= size;
4496 memset(pPrinter, 0, size);
4497 } else {
4498 pi7 = NULL;
4499 cbBuf = 0;
4502 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4503 needed += size;
4504 break;
4508 case 8:
4509 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4510 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4511 /* fall through */
4512 case 9:
4514 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4516 size = sizeof(PRINTER_INFO_9W);
4517 if(size <= cbBuf) {
4518 ptr = pPrinter + size;
4519 cbBuf -= size;
4520 memset(pPrinter, 0, size);
4521 } else {
4522 pi9 = NULL;
4523 cbBuf = 0;
4526 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4527 needed += size;
4528 break;
4532 default:
4533 FIXME("Unimplemented level %d\n", Level);
4534 SetLastError(ERROR_INVALID_LEVEL);
4535 RegCloseKey(hkeyPrinter);
4536 return FALSE;
4539 RegCloseKey(hkeyPrinter);
4541 TRACE("returning %d needed = %d\n", ret, needed);
4542 if(pcbNeeded) *pcbNeeded = needed;
4543 if(!ret)
4544 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4545 return ret;
4548 /*****************************************************************************
4549 * GetPrinterA [WINSPOOL.@]
4551 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4552 DWORD cbBuf, LPDWORD pcbNeeded)
4554 BOOL ret;
4555 LPBYTE buf = NULL;
4557 if (cbBuf)
4558 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4560 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4561 if (ret)
4562 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4563 HeapFree(GetProcessHeap(), 0, buf);
4565 return ret;
4568 /*****************************************************************************
4569 * WINSPOOL_EnumPrintersW
4571 * Implementation of EnumPrintersW
4573 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4574 DWORD dwLevel, LPBYTE lpbPrinters,
4575 DWORD cbBuf, LPDWORD lpdwNeeded,
4576 LPDWORD lpdwReturned)
4579 HKEY hkeyPrinters, hkeyPrinter;
4580 WCHAR PrinterName[255];
4581 DWORD needed = 0, number = 0;
4582 DWORD used, i, left;
4583 PBYTE pi, buf;
4585 if(lpbPrinters)
4586 memset(lpbPrinters, 0, cbBuf);
4587 if(lpdwReturned)
4588 *lpdwReturned = 0;
4589 if(lpdwNeeded)
4590 *lpdwNeeded = 0;
4592 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4593 if(dwType == PRINTER_ENUM_DEFAULT)
4594 return TRUE;
4596 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4597 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4598 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4599 if (!dwType) {
4600 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4601 return TRUE;
4606 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4607 FIXME("dwType = %08x\n", dwType);
4608 SetLastError(ERROR_INVALID_FLAGS);
4609 return FALSE;
4612 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4613 ERROR_SUCCESS) {
4614 ERR("Can't create Printers key\n");
4615 return FALSE;
4618 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4619 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4620 RegCloseKey(hkeyPrinters);
4621 ERR("Can't query Printers key\n");
4622 return FALSE;
4624 TRACE("Found %d printers\n", number);
4626 switch(dwLevel) {
4627 case 1:
4628 used = number * sizeof(PRINTER_INFO_1W);
4629 break;
4630 case 2:
4631 used = number * sizeof(PRINTER_INFO_2W);
4632 break;
4633 case 4:
4634 used = number * sizeof(PRINTER_INFO_4W);
4635 break;
4636 case 5:
4637 used = number * sizeof(PRINTER_INFO_5W);
4638 break;
4640 default:
4641 SetLastError(ERROR_INVALID_LEVEL);
4642 RegCloseKey(hkeyPrinters);
4643 return FALSE;
4645 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4647 for(i = 0; i < number; i++) {
4648 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4649 ERROR_SUCCESS) {
4650 ERR("Can't enum key number %d\n", i);
4651 RegCloseKey(hkeyPrinters);
4652 return FALSE;
4654 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4655 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4656 ERROR_SUCCESS) {
4657 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4658 RegCloseKey(hkeyPrinters);
4659 return FALSE;
4662 if(cbBuf > used) {
4663 buf = lpbPrinters + used;
4664 left = cbBuf - used;
4665 } else {
4666 buf = NULL;
4667 left = 0;
4670 switch(dwLevel) {
4671 case 1:
4672 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4673 left, &needed);
4674 used += needed;
4675 if(pi) pi += sizeof(PRINTER_INFO_1W);
4676 break;
4677 case 2:
4678 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4679 left, &needed);
4680 used += needed;
4681 if(pi) pi += sizeof(PRINTER_INFO_2W);
4682 break;
4683 case 4:
4684 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4685 left, &needed);
4686 used += needed;
4687 if(pi) pi += sizeof(PRINTER_INFO_4W);
4688 break;
4689 case 5:
4690 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4691 left, &needed);
4692 used += needed;
4693 if(pi) pi += sizeof(PRINTER_INFO_5W);
4694 break;
4695 default:
4696 ERR("Shouldn't be here!\n");
4697 RegCloseKey(hkeyPrinter);
4698 RegCloseKey(hkeyPrinters);
4699 return FALSE;
4701 RegCloseKey(hkeyPrinter);
4703 RegCloseKey(hkeyPrinters);
4705 if(lpdwNeeded)
4706 *lpdwNeeded = used;
4708 if(used > cbBuf) {
4709 if(lpbPrinters)
4710 memset(lpbPrinters, 0, cbBuf);
4711 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4712 return FALSE;
4714 if(lpdwReturned)
4715 *lpdwReturned = number;
4716 SetLastError(ERROR_SUCCESS);
4717 return TRUE;
4721 /******************************************************************
4722 * EnumPrintersW [WINSPOOL.@]
4724 * Enumerates the available printers, print servers and print
4725 * providers, depending on the specified flags, name and level.
4727 * RETURNS:
4729 * If level is set to 1:
4730 * Returns an array of PRINTER_INFO_1 data structures in the
4731 * lpbPrinters buffer.
4733 * If level is set to 2:
4734 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4735 * Returns an array of PRINTER_INFO_2 data structures in the
4736 * lpbPrinters buffer. Note that according to MSDN also an
4737 * OpenPrinter should be performed on every remote printer.
4739 * If level is set to 4 (officially WinNT only):
4740 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4741 * Fast: Only the registry is queried to retrieve printer names,
4742 * no connection to the driver is made.
4743 * Returns an array of PRINTER_INFO_4 data structures in the
4744 * lpbPrinters buffer.
4746 * If level is set to 5 (officially WinNT4/Win9x only):
4747 * Fast: Only the registry is queried to retrieve printer names,
4748 * no connection to the driver is made.
4749 * Returns an array of PRINTER_INFO_5 data structures in the
4750 * lpbPrinters buffer.
4752 * If level set to 3 or 6+:
4753 * returns zero (failure!)
4755 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4756 * for information.
4758 * BUGS:
4759 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4760 * - Only levels 2, 4 and 5 are implemented at the moment.
4761 * - 16-bit printer drivers are not enumerated.
4762 * - Returned amount of bytes used/needed does not match the real Windoze
4763 * implementation (as in this implementation, all strings are part
4764 * of the buffer, whereas Win32 keeps them somewhere else)
4765 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4767 * NOTE:
4768 * - In a regular Wine installation, no registry settings for printers
4769 * exist, which makes this function return an empty list.
4771 BOOL WINAPI EnumPrintersW(
4772 DWORD dwType, /* [in] Types of print objects to enumerate */
4773 LPWSTR lpszName, /* [in] name of objects to enumerate */
4774 DWORD dwLevel, /* [in] type of printer info structure */
4775 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4776 DWORD cbBuf, /* [in] max size of buffer in bytes */
4777 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4778 LPDWORD lpdwReturned /* [out] number of entries returned */
4781 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4782 lpdwNeeded, lpdwReturned);
4785 /******************************************************************
4786 * EnumPrintersA [WINSPOOL.@]
4788 * See EnumPrintersW
4791 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4792 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4794 BOOL ret;
4795 UNICODE_STRING pNameU;
4796 LPWSTR pNameW;
4797 LPBYTE pPrintersW;
4799 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4800 pPrinters, cbBuf, pcbNeeded, pcReturned);
4802 pNameW = asciitounicode(&pNameU, pName);
4804 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4805 MS Office need this */
4806 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4808 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4810 RtlFreeUnicodeString(&pNameU);
4811 if (ret) {
4812 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4814 HeapFree(GetProcessHeap(), 0, pPrintersW);
4815 return ret;
4818 /*****************************************************************************
4819 * WINSPOOL_GetDriverInfoFromReg [internal]
4821 * Enters the information from the registry into the DRIVER_INFO struct
4823 * RETURNS
4824 * zero if the printer driver does not exist in the registry
4825 * (only if Level > 1) otherwise nonzero
4827 static BOOL WINSPOOL_GetDriverInfoFromReg(
4828 HKEY hkeyDrivers,
4829 LPWSTR DriverName,
4830 const printenv_t * env,
4831 DWORD Level,
4832 LPBYTE ptr, /* DRIVER_INFO */
4833 LPBYTE pDriverStrings, /* strings buffer */
4834 DWORD cbBuf, /* size of string buffer */
4835 LPDWORD pcbNeeded) /* space needed for str. */
4837 DWORD size, tmp;
4838 HKEY hkeyDriver;
4839 WCHAR driverdir[MAX_PATH];
4840 DWORD dirlen;
4841 LPBYTE strPtr = pDriverStrings;
4842 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4844 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4845 debugstr_w(DriverName), env,
4846 Level, di, pDriverStrings, cbBuf);
4848 if (di) ZeroMemory(di, di_sizeof[Level]);
4850 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4851 if (*pcbNeeded <= cbBuf)
4852 strcpyW((LPWSTR)strPtr, DriverName);
4854 /* pName for level 1 has a different offset! */
4855 if (Level == 1) {
4856 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4857 return TRUE;
4860 /* .cVersion and .pName for level > 1 */
4861 if (di) {
4862 di->cVersion = env->driverversion;
4863 di->pName = (LPWSTR) strPtr;
4864 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4867 /* Reserve Space for the largest subdir and a Backslash*/
4868 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4869 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4870 /* Should never Fail */
4871 return FALSE;
4873 lstrcatW(driverdir, env->versionsubdir);
4874 lstrcatW(driverdir, backslashW);
4876 /* dirlen must not include the terminating zero */
4877 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4879 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4880 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4881 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4882 return FALSE;
4885 /* pEnvironment */
4886 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4888 *pcbNeeded += size;
4889 if (*pcbNeeded <= cbBuf) {
4890 lstrcpyW((LPWSTR)strPtr, env->envname);
4891 if (di) di->pEnvironment = (LPWSTR)strPtr;
4892 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4895 /* .pDriverPath is the Graphics rendering engine.
4896 The full Path is required to avoid a crash in some apps */
4897 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4898 *pcbNeeded += size;
4899 if (*pcbNeeded <= cbBuf)
4900 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4902 if (di) di->pDriverPath = (LPWSTR)strPtr;
4903 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4906 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4907 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4908 *pcbNeeded += size;
4909 if (*pcbNeeded <= cbBuf)
4910 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4912 if (di) di->pDataFile = (LPWSTR)strPtr;
4913 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4916 /* .pConfigFile is the Driver user Interface */
4917 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4918 *pcbNeeded += size;
4919 if (*pcbNeeded <= cbBuf)
4920 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4922 if (di) di->pConfigFile = (LPWSTR)strPtr;
4923 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4926 if (Level == 2 ) {
4927 RegCloseKey(hkeyDriver);
4928 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4929 return TRUE;
4932 if (Level == 5 ) {
4933 RegCloseKey(hkeyDriver);
4934 FIXME("level 5: incomplete\n");
4935 return TRUE;
4938 /* .pHelpFile */
4939 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4940 *pcbNeeded += size;
4941 if (*pcbNeeded <= cbBuf)
4942 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4944 if (di) di->pHelpFile = (LPWSTR)strPtr;
4945 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4948 /* .pDependentFiles */
4949 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4950 *pcbNeeded += size;
4951 if (*pcbNeeded <= cbBuf)
4952 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4954 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4955 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4957 else if (GetVersion() & 0x80000000) {
4958 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4959 size = 2 * sizeof(WCHAR);
4960 *pcbNeeded += size;
4961 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4963 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4964 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4967 /* .pMonitorName is the optional Language Monitor */
4968 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4969 *pcbNeeded += size;
4970 if (*pcbNeeded <= cbBuf)
4971 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4973 if (di) di->pMonitorName = (LPWSTR)strPtr;
4974 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4977 /* .pDefaultDataType */
4978 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4979 *pcbNeeded += size;
4980 if(*pcbNeeded <= cbBuf)
4981 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4983 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4984 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4987 if (Level == 3 ) {
4988 RegCloseKey(hkeyDriver);
4989 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4990 return TRUE;
4993 /* .pszzPreviousNames */
4994 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4995 *pcbNeeded += size;
4996 if(*pcbNeeded <= cbBuf)
4997 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4999 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
5000 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5003 if (Level == 4 ) {
5004 RegCloseKey(hkeyDriver);
5005 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5006 return TRUE;
5009 /* support is missing, but not important enough for a FIXME */
5010 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5012 /* .pszMfgName */
5013 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5014 *pcbNeeded += size;
5015 if(*pcbNeeded <= cbBuf)
5016 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5018 if (di) di->pszMfgName = (LPWSTR)strPtr;
5019 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5022 /* .pszOEMUrl */
5023 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5024 *pcbNeeded += size;
5025 if(*pcbNeeded <= cbBuf)
5026 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5028 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5029 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5032 /* .pszHardwareID */
5033 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5034 *pcbNeeded += size;
5035 if(*pcbNeeded <= cbBuf)
5036 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5038 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5039 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5042 /* .pszProvider */
5043 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5044 *pcbNeeded += size;
5045 if(*pcbNeeded <= cbBuf)
5046 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5048 if (di) di->pszProvider = (LPWSTR)strPtr;
5049 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5052 if (Level == 6 ) {
5053 RegCloseKey(hkeyDriver);
5054 return TRUE;
5057 /* support is missing, but not important enough for a FIXME */
5058 TRACE("level 8: incomplete\n");
5060 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5061 RegCloseKey(hkeyDriver);
5062 return TRUE;
5065 /*****************************************************************************
5066 * GetPrinterDriverW [WINSPOOL.@]
5068 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5069 DWORD Level, LPBYTE pDriverInfo,
5070 DWORD cbBuf, LPDWORD pcbNeeded)
5072 LPCWSTR name;
5073 WCHAR DriverName[100];
5074 DWORD ret, type, size, needed = 0;
5075 LPBYTE ptr = NULL;
5076 HKEY hkeyPrinter, hkeyDrivers;
5077 const printenv_t * env;
5079 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5080 Level,pDriverInfo,cbBuf, pcbNeeded);
5082 if (cbBuf > 0)
5083 ZeroMemory(pDriverInfo, cbBuf);
5085 if (!(name = get_opened_printer_name(hPrinter))) {
5086 SetLastError(ERROR_INVALID_HANDLE);
5087 return FALSE;
5090 if (Level < 1 || Level == 7 || Level > 8) {
5091 SetLastError(ERROR_INVALID_LEVEL);
5092 return FALSE;
5095 env = validate_envW(pEnvironment);
5096 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5098 ret = open_printer_reg_key( name, &hkeyPrinter );
5099 if (ret)
5101 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5102 SetLastError( ret );
5103 return FALSE;
5106 size = sizeof(DriverName);
5107 DriverName[0] = 0;
5108 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5109 (LPBYTE)DriverName, &size);
5110 RegCloseKey(hkeyPrinter);
5111 if(ret != ERROR_SUCCESS) {
5112 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5113 return FALSE;
5116 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5117 if(!hkeyDrivers) {
5118 ERR("Can't create Drivers key\n");
5119 return FALSE;
5122 size = di_sizeof[Level];
5123 if ((size <= cbBuf) && pDriverInfo)
5124 ptr = pDriverInfo + size;
5126 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5127 env, Level, pDriverInfo, ptr,
5128 (cbBuf < size) ? 0 : cbBuf - size,
5129 &needed)) {
5130 RegCloseKey(hkeyDrivers);
5131 return FALSE;
5134 RegCloseKey(hkeyDrivers);
5136 if(pcbNeeded) *pcbNeeded = size + needed;
5137 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5138 if(cbBuf >= size + needed) return TRUE;
5139 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5140 return FALSE;
5143 /*****************************************************************************
5144 * GetPrinterDriverA [WINSPOOL.@]
5146 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5147 DWORD Level, LPBYTE pDriverInfo,
5148 DWORD cbBuf, LPDWORD pcbNeeded)
5150 BOOL ret;
5151 UNICODE_STRING pEnvW;
5152 PWSTR pwstrEnvW;
5153 LPBYTE buf = NULL;
5155 if (cbBuf)
5157 ZeroMemory(pDriverInfo, cbBuf);
5158 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5161 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5162 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5163 cbBuf, pcbNeeded);
5164 if (ret)
5165 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5167 HeapFree(GetProcessHeap(), 0, buf);
5169 RtlFreeUnicodeString(&pEnvW);
5170 return ret;
5173 /*****************************************************************************
5174 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5176 * Return the PATH for the Printer-Drivers (UNICODE)
5178 * PARAMS
5179 * pName [I] Servername (NT only) or NULL (local Computer)
5180 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5181 * Level [I] Structure-Level (must be 1)
5182 * pDriverDirectory [O] PTR to Buffer that receives the Result
5183 * cbBuf [I] Size of Buffer at pDriverDirectory
5184 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5185 * required for pDriverDirectory
5187 * RETURNS
5188 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5189 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5190 * if cbBuf is too small
5192 * Native Values returned in pDriverDirectory on Success:
5193 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5194 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5195 *| win9x(Windows 4.0): "%winsysdir%"
5197 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5199 * FIXME
5200 *- Only NULL or "" is supported for pName
5203 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5204 DWORD Level, LPBYTE pDriverDirectory,
5205 DWORD cbBuf, LPDWORD pcbNeeded)
5207 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5208 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5210 if ((backend == NULL) && !load_backend()) return FALSE;
5212 if (Level != 1) {
5213 /* (Level != 1) is ignored in win9x */
5214 SetLastError(ERROR_INVALID_LEVEL);
5215 return FALSE;
5217 if (pcbNeeded == NULL) {
5218 /* (pcbNeeded == NULL) is ignored in win9x */
5219 SetLastError(RPC_X_NULL_REF_POINTER);
5220 return FALSE;
5223 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5224 pDriverDirectory, cbBuf, pcbNeeded);
5229 /*****************************************************************************
5230 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5232 * Return the PATH for the Printer-Drivers (ANSI)
5234 * See GetPrinterDriverDirectoryW.
5236 * NOTES
5237 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5240 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5241 DWORD Level, LPBYTE pDriverDirectory,
5242 DWORD cbBuf, LPDWORD pcbNeeded)
5244 UNICODE_STRING nameW, environmentW;
5245 BOOL ret;
5246 DWORD pcbNeededW;
5247 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5248 WCHAR *driverDirectoryW = NULL;
5250 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5251 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5253 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5255 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5256 else nameW.Buffer = NULL;
5257 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5258 else environmentW.Buffer = NULL;
5260 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5261 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5262 if (ret) {
5263 DWORD needed;
5264 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5265 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5266 if(pcbNeeded)
5267 *pcbNeeded = needed;
5268 ret = needed <= cbBuf;
5269 } else
5270 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5272 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5274 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5275 RtlFreeUnicodeString(&environmentW);
5276 RtlFreeUnicodeString(&nameW);
5278 return ret;
5281 /*****************************************************************************
5282 * AddPrinterDriverA [WINSPOOL.@]
5284 * See AddPrinterDriverW.
5287 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5289 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5290 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5293 /******************************************************************************
5294 * AddPrinterDriverW (WINSPOOL.@)
5296 * Install a Printer Driver
5298 * PARAMS
5299 * pName [I] Servername or NULL (local Computer)
5300 * level [I] Level for the supplied DRIVER_INFO_*W struct
5301 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5303 * RESULTS
5304 * Success: TRUE
5305 * Failure: FALSE
5308 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5310 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5311 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5314 /*****************************************************************************
5315 * AddPrintProcessorA [WINSPOOL.@]
5317 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5318 LPSTR pPrintProcessorName)
5320 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5321 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5322 return FALSE;
5325 /*****************************************************************************
5326 * AddPrintProcessorW [WINSPOOL.@]
5328 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5329 LPWSTR pPrintProcessorName)
5331 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5332 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5333 return TRUE;
5336 /*****************************************************************************
5337 * AddPrintProvidorA [WINSPOOL.@]
5339 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5341 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5342 return FALSE;
5345 /*****************************************************************************
5346 * AddPrintProvidorW [WINSPOOL.@]
5348 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5350 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5351 return FALSE;
5354 /*****************************************************************************
5355 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5357 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5358 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5360 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5361 pDevModeOutput, pDevModeInput);
5362 return 0;
5365 /*****************************************************************************
5366 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5368 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5369 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5371 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5372 pDevModeOutput, pDevModeInput);
5373 return 0;
5376 /*****************************************************************************
5377 * PrinterProperties [WINSPOOL.@]
5379 * Displays a dialog to set the properties of the printer.
5381 * RETURNS
5382 * nonzero on success or zero on failure
5384 * BUGS
5385 * implemented as stub only
5387 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5388 HANDLE hPrinter /* [in] handle to printer object */
5390 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5391 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5392 return FALSE;
5395 /*****************************************************************************
5396 * EnumJobsA [WINSPOOL.@]
5399 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5400 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5401 LPDWORD pcReturned)
5403 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5404 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5406 if(pcbNeeded) *pcbNeeded = 0;
5407 if(pcReturned) *pcReturned = 0;
5408 return FALSE;
5412 /*****************************************************************************
5413 * EnumJobsW [WINSPOOL.@]
5416 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5417 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5418 LPDWORD pcReturned)
5420 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5421 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5423 if(pcbNeeded) *pcbNeeded = 0;
5424 if(pcReturned) *pcReturned = 0;
5425 return FALSE;
5428 /*****************************************************************************
5429 * WINSPOOL_EnumPrinterDrivers [internal]
5431 * Delivers information about all printer drivers installed on the
5432 * localhost or a given server
5434 * RETURNS
5435 * nonzero on success or zero on failure. If the buffer for the returned
5436 * information is too small the function will return an error
5438 * BUGS
5439 * - only implemented for localhost, foreign hosts will return an error
5441 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5442 DWORD Level, LPBYTE pDriverInfo,
5443 DWORD driver_index,
5444 DWORD cbBuf, LPDWORD pcbNeeded,
5445 LPDWORD pcFound, DWORD data_offset)
5447 { HKEY hkeyDrivers;
5448 DWORD i, size = 0;
5449 const printenv_t * env;
5451 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5452 debugstr_w(pName), debugstr_w(pEnvironment),
5453 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5455 env = validate_envW(pEnvironment);
5456 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5458 *pcFound = 0;
5460 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5461 if(!hkeyDrivers) {
5462 ERR("Can't open Drivers key\n");
5463 return FALSE;
5466 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5467 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5468 RegCloseKey(hkeyDrivers);
5469 ERR("Can't query Drivers key\n");
5470 return FALSE;
5472 TRACE("Found %d Drivers\n", *pcFound);
5474 /* get size of single struct
5475 * unicode and ascii structure have the same size
5477 size = di_sizeof[Level];
5479 if (data_offset == 0)
5480 data_offset = size * (*pcFound);
5481 *pcbNeeded = data_offset;
5483 for( i = 0; i < *pcFound; i++) {
5484 WCHAR DriverNameW[255];
5485 PBYTE table_ptr = NULL;
5486 PBYTE data_ptr = NULL;
5487 DWORD needed = 0;
5489 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5490 != ERROR_SUCCESS) {
5491 ERR("Can't enum key number %d\n", i);
5492 RegCloseKey(hkeyDrivers);
5493 return FALSE;
5496 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5497 table_ptr = pDriverInfo + (driver_index + i) * size;
5498 if (pDriverInfo && *pcbNeeded <= cbBuf)
5499 data_ptr = pDriverInfo + *pcbNeeded;
5501 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5502 env, Level, table_ptr, data_ptr,
5503 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5504 &needed)) {
5505 RegCloseKey(hkeyDrivers);
5506 return FALSE;
5509 *pcbNeeded += needed;
5512 RegCloseKey(hkeyDrivers);
5514 if(cbBuf < *pcbNeeded){
5515 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5516 return FALSE;
5519 return TRUE;
5522 /*****************************************************************************
5523 * EnumPrinterDriversW [WINSPOOL.@]
5525 * see function EnumPrinterDrivers for RETURNS, BUGS
5527 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5528 LPBYTE pDriverInfo, DWORD cbBuf,
5529 LPDWORD pcbNeeded, LPDWORD pcReturned)
5531 static const WCHAR allW[] = {'a','l','l',0};
5532 BOOL ret;
5533 DWORD found;
5535 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5537 SetLastError(RPC_X_NULL_REF_POINTER);
5538 return FALSE;
5541 /* check for local drivers */
5542 if((pName) && (pName[0])) {
5543 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5544 SetLastError(ERROR_ACCESS_DENIED);
5545 return FALSE;
5548 /* check input parameter */
5549 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5550 SetLastError(ERROR_INVALID_LEVEL);
5551 return FALSE;
5554 if(pDriverInfo && cbBuf > 0)
5555 memset( pDriverInfo, 0, cbBuf);
5557 /* Exception: pull all printers */
5558 if (pEnvironment && !strcmpW(pEnvironment, allW))
5560 DWORD i, needed, bufsize = cbBuf;
5561 DWORD total_found = 0;
5562 DWORD data_offset;
5564 /* Precompute the overall total; we need this to know
5565 where pointers end and data begins (i.e. data_offset) */
5566 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5568 needed = found = 0;
5569 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5570 NULL, 0, 0, &needed, &found, 0);
5571 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5572 total_found += found;
5575 data_offset = di_sizeof[Level] * total_found;
5577 *pcReturned = 0;
5578 *pcbNeeded = 0;
5579 total_found = 0;
5580 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5582 needed = found = 0;
5583 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5584 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5585 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5586 else if (ret)
5587 *pcReturned += found;
5588 *pcbNeeded = needed;
5589 data_offset = needed;
5590 total_found += found;
5592 return ret;
5595 /* Normal behavior */
5596 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5597 0, cbBuf, pcbNeeded, &found, 0);
5598 if (ret)
5599 *pcReturned = found;
5601 return ret;
5604 /*****************************************************************************
5605 * EnumPrinterDriversA [WINSPOOL.@]
5607 * see function EnumPrinterDrivers for RETURNS, BUGS
5609 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5610 LPBYTE pDriverInfo, DWORD cbBuf,
5611 LPDWORD pcbNeeded, LPDWORD pcReturned)
5613 BOOL ret;
5614 UNICODE_STRING pNameW, pEnvironmentW;
5615 PWSTR pwstrNameW, pwstrEnvironmentW;
5616 LPBYTE buf = NULL;
5618 if (cbBuf)
5619 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5621 pwstrNameW = asciitounicode(&pNameW, pName);
5622 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5624 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5625 buf, cbBuf, pcbNeeded, pcReturned);
5626 if (ret)
5627 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5629 HeapFree(GetProcessHeap(), 0, buf);
5631 RtlFreeUnicodeString(&pNameW);
5632 RtlFreeUnicodeString(&pEnvironmentW);
5634 return ret;
5637 /******************************************************************************
5638 * EnumPortsA (WINSPOOL.@)
5640 * See EnumPortsW.
5643 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5644 LPDWORD pcbNeeded, LPDWORD pcReturned)
5646 BOOL res;
5647 LPBYTE bufferW = NULL;
5648 LPWSTR nameW = NULL;
5649 DWORD needed = 0;
5650 DWORD numentries = 0;
5651 INT len;
5653 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5654 cbBuf, pcbNeeded, pcReturned);
5656 /* convert servername to unicode */
5657 if (pName) {
5658 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5659 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5660 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5662 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5663 needed = cbBuf * sizeof(WCHAR);
5664 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5665 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5667 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5668 if (pcbNeeded) needed = *pcbNeeded;
5669 /* HeapReAlloc return NULL, when bufferW was NULL */
5670 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5671 HeapAlloc(GetProcessHeap(), 0, needed);
5673 /* Try again with the large Buffer */
5674 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5676 needed = pcbNeeded ? *pcbNeeded : 0;
5677 numentries = pcReturned ? *pcReturned : 0;
5680 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5681 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5683 if (res) {
5684 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5685 DWORD entrysize = 0;
5686 DWORD index;
5687 LPSTR ptr;
5688 LPPORT_INFO_2W pi2w;
5689 LPPORT_INFO_2A pi2a;
5691 needed = 0;
5692 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5694 /* First pass: calculate the size for all Entries */
5695 pi2w = (LPPORT_INFO_2W) bufferW;
5696 pi2a = (LPPORT_INFO_2A) pPorts;
5697 index = 0;
5698 while (index < numentries) {
5699 index++;
5700 needed += entrysize; /* PORT_INFO_?A */
5701 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5703 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5704 NULL, 0, NULL, NULL);
5705 if (Level > 1) {
5706 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5707 NULL, 0, NULL, NULL);
5708 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5709 NULL, 0, NULL, NULL);
5711 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5712 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5713 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5716 /* check for errors and quit on failure */
5717 if (cbBuf < needed) {
5718 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5719 res = FALSE;
5720 goto cleanup;
5722 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5723 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5724 cbBuf -= len ; /* free Bytes in the user-Buffer */
5725 pi2w = (LPPORT_INFO_2W) bufferW;
5726 pi2a = (LPPORT_INFO_2A) pPorts;
5727 index = 0;
5728 /* Second Pass: Fill the User Buffer (if we have one) */
5729 while ((index < numentries) && pPorts) {
5730 index++;
5731 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5732 pi2a->pPortName = ptr;
5733 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5734 ptr, cbBuf , NULL, NULL);
5735 ptr += len;
5736 cbBuf -= len;
5737 if (Level > 1) {
5738 pi2a->pMonitorName = ptr;
5739 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5740 ptr, cbBuf, NULL, NULL);
5741 ptr += len;
5742 cbBuf -= len;
5744 pi2a->pDescription = ptr;
5745 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5746 ptr, cbBuf, NULL, NULL);
5747 ptr += len;
5748 cbBuf -= len;
5750 pi2a->fPortType = pi2w->fPortType;
5751 pi2a->Reserved = 0; /* documented: "must be zero" */
5754 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5755 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5756 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5760 cleanup:
5761 if (pcbNeeded) *pcbNeeded = needed;
5762 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5764 HeapFree(GetProcessHeap(), 0, nameW);
5765 HeapFree(GetProcessHeap(), 0, bufferW);
5767 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5768 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5770 return (res);
5774 /******************************************************************************
5775 * EnumPortsW (WINSPOOL.@)
5777 * Enumerate available Ports
5779 * PARAMS
5780 * pName [I] Servername or NULL (local Computer)
5781 * Level [I] Structure-Level (1 or 2)
5782 * pPorts [O] PTR to Buffer that receives the Result
5783 * cbBuf [I] Size of Buffer at pPorts
5784 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5785 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5787 * RETURNS
5788 * Success: TRUE
5789 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5792 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5795 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5796 cbBuf, pcbNeeded, pcReturned);
5798 if ((backend == NULL) && !load_backend()) return FALSE;
5800 /* Level is not checked in win9x */
5801 if (!Level || (Level > 2)) {
5802 WARN("level (%d) is ignored in win9x\n", Level);
5803 SetLastError(ERROR_INVALID_LEVEL);
5804 return FALSE;
5806 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5807 SetLastError(RPC_X_NULL_REF_POINTER);
5808 return FALSE;
5811 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5814 /******************************************************************************
5815 * GetDefaultPrinterW (WINSPOOL.@)
5817 * FIXME
5818 * This function must read the value from data 'device' of key
5819 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5821 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5823 BOOL retval = TRUE;
5824 DWORD insize, len;
5825 WCHAR *buffer, *ptr;
5827 if (!namesize)
5829 SetLastError(ERROR_INVALID_PARAMETER);
5830 return FALSE;
5833 /* make the buffer big enough for the stuff from the profile/registry,
5834 * the content must fit into the local buffer to compute the correct
5835 * size even if the extern buffer is too small or not given.
5836 * (20 for ,driver,port) */
5837 insize = *namesize;
5838 len = max(100, (insize + 20));
5839 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5841 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5843 SetLastError (ERROR_FILE_NOT_FOUND);
5844 retval = FALSE;
5845 goto end;
5847 TRACE("%s\n", debugstr_w(buffer));
5849 if ((ptr = strchrW(buffer, ',')) == NULL)
5851 SetLastError(ERROR_INVALID_NAME);
5852 retval = FALSE;
5853 goto end;
5856 *ptr = 0;
5857 *namesize = strlenW(buffer) + 1;
5858 if(!name || (*namesize > insize))
5860 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5861 retval = FALSE;
5862 goto end;
5864 strcpyW(name, buffer);
5866 end:
5867 HeapFree( GetProcessHeap(), 0, buffer);
5868 return retval;
5872 /******************************************************************************
5873 * GetDefaultPrinterA (WINSPOOL.@)
5875 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5877 BOOL retval = TRUE;
5878 DWORD insize = 0;
5879 WCHAR *bufferW = NULL;
5881 if (!namesize)
5883 SetLastError(ERROR_INVALID_PARAMETER);
5884 return FALSE;
5887 if(name && *namesize) {
5888 insize = *namesize;
5889 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5892 if(!GetDefaultPrinterW( bufferW, namesize)) {
5893 retval = FALSE;
5894 goto end;
5897 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5898 NULL, NULL);
5899 if (!*namesize)
5901 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5902 retval = FALSE;
5904 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5906 end:
5907 HeapFree( GetProcessHeap(), 0, bufferW);
5908 return retval;
5912 /******************************************************************************
5913 * SetDefaultPrinterW (WINSPOOL.204)
5915 * Set the Name of the Default Printer
5917 * PARAMS
5918 * pszPrinter [I] Name of the Printer or NULL
5920 * RETURNS
5921 * Success: True
5922 * Failure: FALSE
5924 * NOTES
5925 * When the Parameter is NULL or points to an Empty String and
5926 * a Default Printer was already present, then this Function changes nothing.
5927 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5928 * the First enumerated local Printer is used.
5931 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5933 WCHAR default_printer[MAX_PATH];
5934 LPWSTR buffer = NULL;
5935 HKEY hreg;
5936 DWORD size;
5937 DWORD namelen;
5938 LONG lres;
5940 TRACE("(%s)\n", debugstr_w(pszPrinter));
5941 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5943 default_printer[0] = '\0';
5944 size = sizeof(default_printer)/sizeof(WCHAR);
5946 /* if we have a default Printer, do nothing. */
5947 if (GetDefaultPrinterW(default_printer, &size))
5948 return TRUE;
5950 pszPrinter = NULL;
5951 /* we have no default Printer: search local Printers and use the first */
5952 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5954 default_printer[0] = '\0';
5955 size = sizeof(default_printer)/sizeof(WCHAR);
5956 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5958 pszPrinter = default_printer;
5959 TRACE("using %s\n", debugstr_w(pszPrinter));
5961 RegCloseKey(hreg);
5964 if (pszPrinter == NULL) {
5965 TRACE("no local printer found\n");
5966 SetLastError(ERROR_FILE_NOT_FOUND);
5967 return FALSE;
5971 /* "pszPrinter" is never empty or NULL here. */
5972 namelen = lstrlenW(pszPrinter);
5973 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5974 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5975 if (!buffer ||
5976 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5977 HeapFree(GetProcessHeap(), 0, buffer);
5978 SetLastError(ERROR_FILE_NOT_FOUND);
5979 return FALSE;
5982 /* read the devices entry for the printer (driver,port) to build the string for the
5983 default device entry (printer,driver,port) */
5984 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5985 buffer[namelen] = ',';
5986 namelen++; /* move index to the start of the driver */
5988 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5989 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5990 if (!lres) {
5991 TRACE("set device to %s\n", debugstr_w(buffer));
5993 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5994 TRACE("failed to set the device entry: %d\n", GetLastError());
5995 lres = ERROR_INVALID_PRINTER_NAME;
5998 /* remove the next section, when INIFileMapping is implemented */
6000 HKEY hdev;
6001 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
6002 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6003 RegCloseKey(hdev);
6007 else
6009 if (lres != ERROR_FILE_NOT_FOUND)
6010 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6012 SetLastError(ERROR_INVALID_PRINTER_NAME);
6015 RegCloseKey(hreg);
6016 HeapFree(GetProcessHeap(), 0, buffer);
6017 return (lres == ERROR_SUCCESS);
6020 /******************************************************************************
6021 * SetDefaultPrinterA (WINSPOOL.202)
6023 * See SetDefaultPrinterW.
6026 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6028 LPWSTR bufferW = NULL;
6029 BOOL res;
6031 TRACE("(%s)\n", debugstr_a(pszPrinter));
6032 if(pszPrinter) {
6033 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6034 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6035 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6037 res = SetDefaultPrinterW(bufferW);
6038 HeapFree(GetProcessHeap(), 0, bufferW);
6039 return res;
6042 /******************************************************************************
6043 * SetPrinterDataExA (WINSPOOL.@)
6045 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6046 LPCSTR pValueName, DWORD Type,
6047 LPBYTE pData, DWORD cbData)
6049 HKEY hkeyPrinter, hkeySubkey;
6050 DWORD ret;
6052 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6053 debugstr_a(pValueName), Type, pData, cbData);
6055 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6056 != ERROR_SUCCESS)
6057 return ret;
6059 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6060 != ERROR_SUCCESS) {
6061 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6062 RegCloseKey(hkeyPrinter);
6063 return ret;
6065 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6066 RegCloseKey(hkeySubkey);
6067 RegCloseKey(hkeyPrinter);
6068 return ret;
6071 /******************************************************************************
6072 * SetPrinterDataExW (WINSPOOL.@)
6074 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6075 LPCWSTR pValueName, DWORD Type,
6076 LPBYTE pData, DWORD cbData)
6078 HKEY hkeyPrinter, hkeySubkey;
6079 DWORD ret;
6081 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6082 debugstr_w(pValueName), Type, pData, cbData);
6084 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6085 != ERROR_SUCCESS)
6086 return ret;
6088 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6089 != ERROR_SUCCESS) {
6090 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6091 RegCloseKey(hkeyPrinter);
6092 return ret;
6094 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6095 RegCloseKey(hkeySubkey);
6096 RegCloseKey(hkeyPrinter);
6097 return ret;
6100 /******************************************************************************
6101 * SetPrinterDataA (WINSPOOL.@)
6103 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6104 LPBYTE pData, DWORD cbData)
6106 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6107 pData, cbData);
6110 /******************************************************************************
6111 * SetPrinterDataW (WINSPOOL.@)
6113 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6114 LPBYTE pData, DWORD cbData)
6116 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6117 pData, cbData);
6120 /******************************************************************************
6121 * GetPrinterDataExA (WINSPOOL.@)
6123 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6124 LPCSTR pValueName, LPDWORD pType,
6125 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6127 opened_printer_t *printer;
6128 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6129 DWORD ret;
6131 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6132 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6134 printer = get_opened_printer(hPrinter);
6135 if(!printer) return ERROR_INVALID_HANDLE;
6137 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6138 if (ret) return ret;
6140 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6142 if (printer->name) {
6144 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6145 if (ret) {
6146 RegCloseKey(hkeyPrinters);
6147 return ret;
6149 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6150 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6151 RegCloseKey(hkeyPrinter);
6152 RegCloseKey(hkeyPrinters);
6153 return ret;
6156 *pcbNeeded = nSize;
6157 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6158 0, pType, pData, pcbNeeded);
6160 if (!ret && !pData) ret = ERROR_MORE_DATA;
6162 RegCloseKey(hkeySubkey);
6163 RegCloseKey(hkeyPrinter);
6164 RegCloseKey(hkeyPrinters);
6166 TRACE("--> %d\n", ret);
6167 return ret;
6170 /******************************************************************************
6171 * GetPrinterDataExW (WINSPOOL.@)
6173 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6174 LPCWSTR pValueName, LPDWORD pType,
6175 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6177 opened_printer_t *printer;
6178 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6179 DWORD ret;
6181 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6182 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6184 printer = get_opened_printer(hPrinter);
6185 if(!printer) return ERROR_INVALID_HANDLE;
6187 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6188 if (ret) return ret;
6190 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6192 if (printer->name) {
6194 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6195 if (ret) {
6196 RegCloseKey(hkeyPrinters);
6197 return ret;
6199 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6200 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6201 RegCloseKey(hkeyPrinter);
6202 RegCloseKey(hkeyPrinters);
6203 return ret;
6206 *pcbNeeded = nSize;
6207 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6208 0, pType, pData, pcbNeeded);
6210 if (!ret && !pData) ret = ERROR_MORE_DATA;
6212 RegCloseKey(hkeySubkey);
6213 RegCloseKey(hkeyPrinter);
6214 RegCloseKey(hkeyPrinters);
6216 TRACE("--> %d\n", ret);
6217 return ret;
6220 /******************************************************************************
6221 * GetPrinterDataA (WINSPOOL.@)
6223 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6224 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6226 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6227 pData, nSize, pcbNeeded);
6230 /******************************************************************************
6231 * GetPrinterDataW (WINSPOOL.@)
6233 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6234 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6236 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6237 pData, nSize, pcbNeeded);
6240 /*******************************************************************************
6241 * EnumPrinterDataExW [WINSPOOL.@]
6243 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6244 LPBYTE pEnumValues, DWORD cbEnumValues,
6245 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6247 HKEY hkPrinter, hkSubKey;
6248 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6249 cbValueNameLen, cbMaxValueLen, cbValueLen,
6250 cbBufSize, dwType;
6251 LPWSTR lpValueName;
6252 HANDLE hHeap;
6253 PBYTE lpValue;
6254 PPRINTER_ENUM_VALUESW ppev;
6256 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6258 if (pKeyName == NULL || *pKeyName == 0)
6259 return ERROR_INVALID_PARAMETER;
6261 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6262 if (ret != ERROR_SUCCESS)
6264 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6265 hPrinter, ret);
6266 return ret;
6269 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6270 if (ret != ERROR_SUCCESS)
6272 r = RegCloseKey (hkPrinter);
6273 if (r != ERROR_SUCCESS)
6274 WARN ("RegCloseKey returned %i\n", r);
6275 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6276 debugstr_w (pKeyName), ret);
6277 return ret;
6280 ret = RegCloseKey (hkPrinter);
6281 if (ret != ERROR_SUCCESS)
6283 ERR ("RegCloseKey returned %i\n", ret);
6284 r = RegCloseKey (hkSubKey);
6285 if (r != ERROR_SUCCESS)
6286 WARN ("RegCloseKey returned %i\n", r);
6287 return ret;
6290 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6291 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6292 if (ret != ERROR_SUCCESS)
6294 r = RegCloseKey (hkSubKey);
6295 if (r != ERROR_SUCCESS)
6296 WARN ("RegCloseKey returned %i\n", r);
6297 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6298 return ret;
6301 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6302 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6304 if (cValues == 0) /* empty key */
6306 r = RegCloseKey (hkSubKey);
6307 if (r != ERROR_SUCCESS)
6308 WARN ("RegCloseKey returned %i\n", r);
6309 *pcbEnumValues = *pnEnumValues = 0;
6310 return ERROR_SUCCESS;
6313 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6315 hHeap = GetProcessHeap ();
6316 if (hHeap == NULL)
6318 ERR ("GetProcessHeap failed\n");
6319 r = RegCloseKey (hkSubKey);
6320 if (r != ERROR_SUCCESS)
6321 WARN ("RegCloseKey returned %i\n", r);
6322 return ERROR_OUTOFMEMORY;
6325 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6326 if (lpValueName == NULL)
6328 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6329 r = RegCloseKey (hkSubKey);
6330 if (r != ERROR_SUCCESS)
6331 WARN ("RegCloseKey returned %i\n", r);
6332 return ERROR_OUTOFMEMORY;
6335 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6336 if (lpValue == NULL)
6338 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6339 if (HeapFree (hHeap, 0, lpValueName) == 0)
6340 WARN ("HeapFree failed with code %i\n", GetLastError ());
6341 r = RegCloseKey (hkSubKey);
6342 if (r != ERROR_SUCCESS)
6343 WARN ("RegCloseKey returned %i\n", r);
6344 return ERROR_OUTOFMEMORY;
6347 TRACE ("pass 1: calculating buffer required for all names and values\n");
6349 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6351 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6353 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6355 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6356 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6357 NULL, NULL, lpValue, &cbValueLen);
6358 if (ret != ERROR_SUCCESS)
6360 if (HeapFree (hHeap, 0, lpValue) == 0)
6361 WARN ("HeapFree failed with code %i\n", GetLastError ());
6362 if (HeapFree (hHeap, 0, lpValueName) == 0)
6363 WARN ("HeapFree failed with code %i\n", GetLastError ());
6364 r = RegCloseKey (hkSubKey);
6365 if (r != ERROR_SUCCESS)
6366 WARN ("RegCloseKey returned %i\n", r);
6367 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6368 return ret;
6371 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6372 debugstr_w (lpValueName), dwIndex,
6373 cbValueNameLen + 1, cbValueLen);
6375 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6376 cbBufSize += cbValueLen;
6379 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6381 *pcbEnumValues = cbBufSize;
6382 *pnEnumValues = cValues;
6384 if (cbEnumValues < cbBufSize) /* buffer too small */
6386 if (HeapFree (hHeap, 0, lpValue) == 0)
6387 WARN ("HeapFree failed with code %i\n", GetLastError ());
6388 if (HeapFree (hHeap, 0, lpValueName) == 0)
6389 WARN ("HeapFree failed with code %i\n", GetLastError ());
6390 r = RegCloseKey (hkSubKey);
6391 if (r != ERROR_SUCCESS)
6392 WARN ("RegCloseKey returned %i\n", r);
6393 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6394 return ERROR_MORE_DATA;
6397 TRACE ("pass 2: copying all names and values to buffer\n");
6399 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6400 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6402 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6404 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6405 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6406 NULL, &dwType, lpValue, &cbValueLen);
6407 if (ret != ERROR_SUCCESS)
6409 if (HeapFree (hHeap, 0, lpValue) == 0)
6410 WARN ("HeapFree failed with code %i\n", GetLastError ());
6411 if (HeapFree (hHeap, 0, lpValueName) == 0)
6412 WARN ("HeapFree failed with code %i\n", GetLastError ());
6413 r = RegCloseKey (hkSubKey);
6414 if (r != ERROR_SUCCESS)
6415 WARN ("RegCloseKey returned %i\n", r);
6416 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6417 return ret;
6420 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6421 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6422 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6423 pEnumValues += cbValueNameLen;
6425 /* return # of *bytes* (including trailing \0), not # of chars */
6426 ppev[dwIndex].cbValueName = cbValueNameLen;
6428 ppev[dwIndex].dwType = dwType;
6430 memcpy (pEnumValues, lpValue, cbValueLen);
6431 ppev[dwIndex].pData = pEnumValues;
6432 pEnumValues += cbValueLen;
6434 ppev[dwIndex].cbData = cbValueLen;
6436 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6437 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6440 if (HeapFree (hHeap, 0, lpValue) == 0)
6442 ret = GetLastError ();
6443 ERR ("HeapFree failed with code %i\n", ret);
6444 if (HeapFree (hHeap, 0, lpValueName) == 0)
6445 WARN ("HeapFree failed with code %i\n", GetLastError ());
6446 r = RegCloseKey (hkSubKey);
6447 if (r != ERROR_SUCCESS)
6448 WARN ("RegCloseKey returned %i\n", r);
6449 return ret;
6452 if (HeapFree (hHeap, 0, lpValueName) == 0)
6454 ret = GetLastError ();
6455 ERR ("HeapFree failed with code %i\n", ret);
6456 r = RegCloseKey (hkSubKey);
6457 if (r != ERROR_SUCCESS)
6458 WARN ("RegCloseKey returned %i\n", r);
6459 return ret;
6462 ret = RegCloseKey (hkSubKey);
6463 if (ret != ERROR_SUCCESS)
6465 ERR ("RegCloseKey returned %i\n", ret);
6466 return ret;
6469 return ERROR_SUCCESS;
6472 /*******************************************************************************
6473 * EnumPrinterDataExA [WINSPOOL.@]
6475 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6476 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6477 * what Windows 2000 SP1 does.
6480 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6481 LPBYTE pEnumValues, DWORD cbEnumValues,
6482 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6484 INT len;
6485 LPWSTR pKeyNameW;
6486 DWORD ret, dwIndex, dwBufSize;
6487 HANDLE hHeap;
6488 LPSTR pBuffer;
6490 TRACE ("%p %s\n", hPrinter, pKeyName);
6492 if (pKeyName == NULL || *pKeyName == 0)
6493 return ERROR_INVALID_PARAMETER;
6495 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6496 if (len == 0)
6498 ret = GetLastError ();
6499 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6500 return ret;
6503 hHeap = GetProcessHeap ();
6504 if (hHeap == NULL)
6506 ERR ("GetProcessHeap failed\n");
6507 return ERROR_OUTOFMEMORY;
6510 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6511 if (pKeyNameW == NULL)
6513 ERR ("Failed to allocate %i bytes from process heap\n",
6514 (LONG)(len * sizeof (WCHAR)));
6515 return ERROR_OUTOFMEMORY;
6518 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6520 ret = GetLastError ();
6521 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6522 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6523 WARN ("HeapFree failed with code %i\n", GetLastError ());
6524 return ret;
6527 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6528 pcbEnumValues, pnEnumValues);
6529 if (ret != ERROR_SUCCESS)
6531 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6532 WARN ("HeapFree failed with code %i\n", GetLastError ());
6533 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6534 return ret;
6537 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6539 ret = GetLastError ();
6540 ERR ("HeapFree failed with code %i\n", ret);
6541 return ret;
6544 if (*pnEnumValues == 0) /* empty key */
6545 return ERROR_SUCCESS;
6547 dwBufSize = 0;
6548 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6550 PPRINTER_ENUM_VALUESW ppev =
6551 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6553 if (dwBufSize < ppev->cbValueName)
6554 dwBufSize = ppev->cbValueName;
6556 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6557 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6558 dwBufSize = ppev->cbData;
6561 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6563 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6564 if (pBuffer == NULL)
6566 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6567 return ERROR_OUTOFMEMORY;
6570 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6572 PPRINTER_ENUM_VALUESW ppev =
6573 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6575 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6576 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6577 NULL);
6578 if (len == 0)
6580 ret = GetLastError ();
6581 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6582 if (HeapFree (hHeap, 0, pBuffer) == 0)
6583 WARN ("HeapFree failed with code %i\n", GetLastError ());
6584 return ret;
6587 memcpy (ppev->pValueName, pBuffer, len);
6589 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6591 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6592 ppev->dwType != REG_MULTI_SZ)
6593 continue;
6595 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6596 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6597 if (len == 0)
6599 ret = GetLastError ();
6600 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6601 if (HeapFree (hHeap, 0, pBuffer) == 0)
6602 WARN ("HeapFree failed with code %i\n", GetLastError ());
6603 return ret;
6606 memcpy (ppev->pData, pBuffer, len);
6608 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6609 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6612 if (HeapFree (hHeap, 0, pBuffer) == 0)
6614 ret = GetLastError ();
6615 ERR ("HeapFree failed with code %i\n", ret);
6616 return ret;
6619 return ERROR_SUCCESS;
6622 /******************************************************************************
6623 * AbortPrinter (WINSPOOL.@)
6625 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6627 FIXME("(%p), stub!\n", hPrinter);
6628 return TRUE;
6631 /******************************************************************************
6632 * AddPortA (WINSPOOL.@)
6634 * See AddPortW.
6637 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6639 LPWSTR nameW = NULL;
6640 LPWSTR monitorW = NULL;
6641 DWORD len;
6642 BOOL res;
6644 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6646 if (pName) {
6647 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6648 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6649 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6652 if (pMonitorName) {
6653 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6654 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6655 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6657 res = AddPortW(nameW, hWnd, monitorW);
6658 HeapFree(GetProcessHeap(), 0, nameW);
6659 HeapFree(GetProcessHeap(), 0, monitorW);
6660 return res;
6663 /******************************************************************************
6664 * AddPortW (WINSPOOL.@)
6666 * Add a Port for a specific Monitor
6668 * PARAMS
6669 * pName [I] Servername or NULL (local Computer)
6670 * hWnd [I] Handle to parent Window for the Dialog-Box
6671 * pMonitorName [I] Name of the Monitor that manage the Port
6673 * RETURNS
6674 * Success: TRUE
6675 * Failure: FALSE
6678 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6680 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6682 if ((backend == NULL) && !load_backend()) return FALSE;
6684 if (!pMonitorName) {
6685 SetLastError(RPC_X_NULL_REF_POINTER);
6686 return FALSE;
6689 return backend->fpAddPort(pName, hWnd, pMonitorName);
6692 /******************************************************************************
6693 * AddPortExA (WINSPOOL.@)
6695 * See AddPortExW.
6698 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6700 PORT_INFO_2W pi2W;
6701 PORT_INFO_2A * pi2A;
6702 LPWSTR nameW = NULL;
6703 LPWSTR monitorW = NULL;
6704 DWORD len;
6705 BOOL res;
6707 pi2A = (PORT_INFO_2A *) pBuffer;
6709 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6710 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6712 if ((level < 1) || (level > 2)) {
6713 SetLastError(ERROR_INVALID_LEVEL);
6714 return FALSE;
6717 if (!pi2A) {
6718 SetLastError(ERROR_INVALID_PARAMETER);
6719 return FALSE;
6722 if (pName) {
6723 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6724 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6725 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6728 if (pMonitorName) {
6729 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6730 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6731 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6734 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6736 if (pi2A->pPortName) {
6737 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6738 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6739 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6742 if (level > 1) {
6743 if (pi2A->pMonitorName) {
6744 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6745 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6746 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6749 if (pi2A->pDescription) {
6750 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6751 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6752 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6754 pi2W.fPortType = pi2A->fPortType;
6755 pi2W.Reserved = pi2A->Reserved;
6758 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6760 HeapFree(GetProcessHeap(), 0, nameW);
6761 HeapFree(GetProcessHeap(), 0, monitorW);
6762 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6763 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6764 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6765 return res;
6769 /******************************************************************************
6770 * AddPortExW (WINSPOOL.@)
6772 * Add a Port for a specific Monitor, without presenting a user interface
6774 * PARAMS
6775 * pName [I] Servername or NULL (local Computer)
6776 * level [I] Structure-Level (1 or 2) for pBuffer
6777 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6778 * pMonitorName [I] Name of the Monitor that manage the Port
6780 * RETURNS
6781 * Success: TRUE
6782 * Failure: FALSE
6785 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6787 PORT_INFO_2W * pi2;
6789 pi2 = (PORT_INFO_2W *) pBuffer;
6791 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6792 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6793 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6794 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6796 if ((backend == NULL) && !load_backend()) return FALSE;
6798 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6799 SetLastError(ERROR_INVALID_PARAMETER);
6800 return FALSE;
6803 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6806 /******************************************************************************
6807 * AddPrinterConnectionA (WINSPOOL.@)
6809 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6811 FIXME("%s\n", debugstr_a(pName));
6812 return FALSE;
6815 /******************************************************************************
6816 * AddPrinterConnectionW (WINSPOOL.@)
6818 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6820 FIXME("%s\n", debugstr_w(pName));
6821 return FALSE;
6824 /******************************************************************************
6825 * AddPrinterDriverExW (WINSPOOL.@)
6827 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6829 * PARAMS
6830 * pName [I] Servername or NULL (local Computer)
6831 * level [I] Level for the supplied DRIVER_INFO_*W struct
6832 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6833 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6835 * RESULTS
6836 * Success: TRUE
6837 * Failure: FALSE
6840 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6842 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6844 if ((backend == NULL) && !load_backend()) return FALSE;
6846 if (level < 2 || level == 5 || level == 7 || level > 8) {
6847 SetLastError(ERROR_INVALID_LEVEL);
6848 return FALSE;
6851 if (!pDriverInfo) {
6852 SetLastError(ERROR_INVALID_PARAMETER);
6853 return FALSE;
6856 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6859 /******************************************************************************
6860 * AddPrinterDriverExA (WINSPOOL.@)
6862 * See AddPrinterDriverExW.
6865 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6867 DRIVER_INFO_8A *diA;
6868 DRIVER_INFO_8W diW;
6869 LPWSTR nameW = NULL;
6870 DWORD lenA;
6871 DWORD len;
6872 DWORD res = FALSE;
6874 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6876 diA = (DRIVER_INFO_8A *) pDriverInfo;
6877 ZeroMemory(&diW, sizeof(diW));
6879 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6880 SetLastError(ERROR_INVALID_LEVEL);
6881 return FALSE;
6884 if (diA == NULL) {
6885 SetLastError(ERROR_INVALID_PARAMETER);
6886 return FALSE;
6889 /* convert servername to unicode */
6890 if (pName) {
6891 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6892 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6893 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6896 /* common fields */
6897 diW.cVersion = diA->cVersion;
6899 if (diA->pName) {
6900 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6901 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6902 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6905 if (diA->pEnvironment) {
6906 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6907 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6908 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6911 if (diA->pDriverPath) {
6912 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6913 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6914 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6917 if (diA->pDataFile) {
6918 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6919 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6920 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6923 if (diA->pConfigFile) {
6924 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6925 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6926 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6929 if ((Level > 2) && diA->pDependentFiles) {
6930 lenA = multi_sz_lenA(diA->pDependentFiles);
6931 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6932 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6933 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6936 if ((Level > 2) && diA->pMonitorName) {
6937 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6938 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6939 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6942 if ((Level > 3) && diA->pDefaultDataType) {
6943 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6944 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6945 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6948 if ((Level > 3) && diA->pszzPreviousNames) {
6949 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6950 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6951 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6952 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6955 if ((Level > 5) && diA->pszMfgName) {
6956 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6957 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6958 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6961 if ((Level > 5) && diA->pszOEMUrl) {
6962 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6963 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6964 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6967 if ((Level > 5) && diA->pszHardwareID) {
6968 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6969 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6970 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6973 if ((Level > 5) && diA->pszProvider) {
6974 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6975 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6976 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6979 if (Level > 7) {
6980 FIXME("level %u is incomplete\n", Level);
6983 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6984 TRACE("got %u with %u\n", res, GetLastError());
6985 HeapFree(GetProcessHeap(), 0, nameW);
6986 HeapFree(GetProcessHeap(), 0, diW.pName);
6987 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6988 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6989 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6990 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6991 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6992 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6993 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6994 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6995 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6996 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6997 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6998 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
7000 TRACE("=> %u with %u\n", res, GetLastError());
7001 return res;
7004 /******************************************************************************
7005 * ConfigurePortA (WINSPOOL.@)
7007 * See ConfigurePortW.
7010 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7012 LPWSTR nameW = NULL;
7013 LPWSTR portW = NULL;
7014 INT len;
7015 DWORD res;
7017 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7019 /* convert servername to unicode */
7020 if (pName) {
7021 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7022 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7023 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7026 /* convert portname to unicode */
7027 if (pPortName) {
7028 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7029 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7030 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7033 res = ConfigurePortW(nameW, hWnd, portW);
7034 HeapFree(GetProcessHeap(), 0, nameW);
7035 HeapFree(GetProcessHeap(), 0, portW);
7036 return res;
7039 /******************************************************************************
7040 * ConfigurePortW (WINSPOOL.@)
7042 * Display the Configuration-Dialog for a specific Port
7044 * PARAMS
7045 * pName [I] Servername or NULL (local Computer)
7046 * hWnd [I] Handle to parent Window for the Dialog-Box
7047 * pPortName [I] Name of the Port, that should be configured
7049 * RETURNS
7050 * Success: TRUE
7051 * Failure: FALSE
7054 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7057 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7059 if ((backend == NULL) && !load_backend()) return FALSE;
7061 if (!pPortName) {
7062 SetLastError(RPC_X_NULL_REF_POINTER);
7063 return FALSE;
7066 return backend->fpConfigurePort(pName, hWnd, pPortName);
7069 /******************************************************************************
7070 * ConnectToPrinterDlg (WINSPOOL.@)
7072 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7074 FIXME("%p %x\n", hWnd, Flags);
7075 return NULL;
7078 /******************************************************************************
7079 * DeletePrinterConnectionA (WINSPOOL.@)
7081 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7083 FIXME("%s\n", debugstr_a(pName));
7084 return TRUE;
7087 /******************************************************************************
7088 * DeletePrinterConnectionW (WINSPOOL.@)
7090 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7092 FIXME("%s\n", debugstr_w(pName));
7093 return TRUE;
7096 /******************************************************************************
7097 * DeletePrinterDriverExW (WINSPOOL.@)
7099 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7100 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7102 HKEY hkey_drivers;
7103 BOOL ret = FALSE;
7105 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7106 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7108 if(pName && pName[0])
7110 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7111 SetLastError(ERROR_INVALID_PARAMETER);
7112 return FALSE;
7115 if(dwDeleteFlag)
7117 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7118 SetLastError(ERROR_INVALID_PARAMETER);
7119 return FALSE;
7122 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7124 if(!hkey_drivers)
7126 ERR("Can't open drivers key\n");
7127 return FALSE;
7130 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7131 ret = TRUE;
7133 RegCloseKey(hkey_drivers);
7135 return ret;
7138 /******************************************************************************
7139 * DeletePrinterDriverExA (WINSPOOL.@)
7141 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7142 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7144 UNICODE_STRING NameW, EnvW, DriverW;
7145 BOOL ret;
7147 asciitounicode(&NameW, pName);
7148 asciitounicode(&EnvW, pEnvironment);
7149 asciitounicode(&DriverW, pDriverName);
7151 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7153 RtlFreeUnicodeString(&DriverW);
7154 RtlFreeUnicodeString(&EnvW);
7155 RtlFreeUnicodeString(&NameW);
7157 return ret;
7160 /******************************************************************************
7161 * DeletePrinterDataExW (WINSPOOL.@)
7163 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7164 LPCWSTR pValueName)
7166 FIXME("%p %s %s\n", hPrinter,
7167 debugstr_w(pKeyName), debugstr_w(pValueName));
7168 return ERROR_INVALID_PARAMETER;
7171 /******************************************************************************
7172 * DeletePrinterDataExA (WINSPOOL.@)
7174 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7175 LPCSTR pValueName)
7177 FIXME("%p %s %s\n", hPrinter,
7178 debugstr_a(pKeyName), debugstr_a(pValueName));
7179 return ERROR_INVALID_PARAMETER;
7182 /******************************************************************************
7183 * DeletePrintProcessorA (WINSPOOL.@)
7185 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7187 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7188 debugstr_a(pPrintProcessorName));
7189 return TRUE;
7192 /******************************************************************************
7193 * DeletePrintProcessorW (WINSPOOL.@)
7195 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7197 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7198 debugstr_w(pPrintProcessorName));
7199 return TRUE;
7202 /******************************************************************************
7203 * DeletePrintProvidorA (WINSPOOL.@)
7205 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7207 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7208 debugstr_a(pPrintProviderName));
7209 return TRUE;
7212 /******************************************************************************
7213 * DeletePrintProvidorW (WINSPOOL.@)
7215 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7217 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7218 debugstr_w(pPrintProviderName));
7219 return TRUE;
7222 /******************************************************************************
7223 * EnumFormsA (WINSPOOL.@)
7225 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7226 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7228 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7229 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7230 return FALSE;
7233 /******************************************************************************
7234 * EnumFormsW (WINSPOOL.@)
7236 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7237 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7239 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7240 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7241 return FALSE;
7244 /*****************************************************************************
7245 * EnumMonitorsA [WINSPOOL.@]
7247 * See EnumMonitorsW.
7250 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7251 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7253 BOOL res;
7254 LPBYTE bufferW = NULL;
7255 LPWSTR nameW = NULL;
7256 DWORD needed = 0;
7257 DWORD numentries = 0;
7258 INT len;
7260 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7261 cbBuf, pcbNeeded, pcReturned);
7263 /* convert servername to unicode */
7264 if (pName) {
7265 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7266 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7267 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7269 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7270 needed = cbBuf * sizeof(WCHAR);
7271 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7272 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7274 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7275 if (pcbNeeded) needed = *pcbNeeded;
7276 /* HeapReAlloc return NULL, when bufferW was NULL */
7277 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7278 HeapAlloc(GetProcessHeap(), 0, needed);
7280 /* Try again with the large Buffer */
7281 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7283 numentries = pcReturned ? *pcReturned : 0;
7284 needed = 0;
7286 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7287 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7289 if (res) {
7290 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7291 DWORD entrysize = 0;
7292 DWORD index;
7293 LPSTR ptr;
7294 LPMONITOR_INFO_2W mi2w;
7295 LPMONITOR_INFO_2A mi2a;
7297 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7298 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7300 /* First pass: calculate the size for all Entries */
7301 mi2w = (LPMONITOR_INFO_2W) bufferW;
7302 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7303 index = 0;
7304 while (index < numentries) {
7305 index++;
7306 needed += entrysize; /* MONITOR_INFO_?A */
7307 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7309 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7310 NULL, 0, NULL, NULL);
7311 if (Level > 1) {
7312 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7313 NULL, 0, NULL, NULL);
7314 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7315 NULL, 0, NULL, NULL);
7317 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7318 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7319 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7322 /* check for errors and quit on failure */
7323 if (cbBuf < needed) {
7324 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7325 res = FALSE;
7326 goto emA_cleanup;
7328 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7329 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7330 cbBuf -= len ; /* free Bytes in the user-Buffer */
7331 mi2w = (LPMONITOR_INFO_2W) bufferW;
7332 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7333 index = 0;
7334 /* Second Pass: Fill the User Buffer (if we have one) */
7335 while ((index < numentries) && pMonitors) {
7336 index++;
7337 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7338 mi2a->pName = ptr;
7339 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7340 ptr, cbBuf , NULL, NULL);
7341 ptr += len;
7342 cbBuf -= len;
7343 if (Level > 1) {
7344 mi2a->pEnvironment = ptr;
7345 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7346 ptr, cbBuf, NULL, NULL);
7347 ptr += len;
7348 cbBuf -= len;
7350 mi2a->pDLLName = ptr;
7351 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7352 ptr, cbBuf, NULL, NULL);
7353 ptr += len;
7354 cbBuf -= len;
7356 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7357 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7358 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7361 emA_cleanup:
7362 if (pcbNeeded) *pcbNeeded = needed;
7363 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7365 HeapFree(GetProcessHeap(), 0, nameW);
7366 HeapFree(GetProcessHeap(), 0, bufferW);
7368 TRACE("returning %d with %d (%d byte for %d entries)\n",
7369 (res), GetLastError(), needed, numentries);
7371 return (res);
7375 /*****************************************************************************
7376 * EnumMonitorsW [WINSPOOL.@]
7378 * Enumerate available Port-Monitors
7380 * PARAMS
7381 * pName [I] Servername or NULL (local Computer)
7382 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7383 * pMonitors [O] PTR to Buffer that receives the Result
7384 * cbBuf [I] Size of Buffer at pMonitors
7385 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7386 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7388 * RETURNS
7389 * Success: TRUE
7390 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7393 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7394 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7397 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7398 cbBuf, pcbNeeded, pcReturned);
7400 if ((backend == NULL) && !load_backend()) return FALSE;
7402 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7403 SetLastError(RPC_X_NULL_REF_POINTER);
7404 return FALSE;
7407 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7410 /******************************************************************************
7411 * SpoolerInit (WINSPOOL.@)
7413 * Initialize the Spooler
7415 * RETURNS
7416 * Success: TRUE
7417 * Failure: FALSE
7419 * NOTES
7420 * The function fails on windows, when the spooler service is not running
7423 BOOL WINAPI SpoolerInit(void)
7426 if ((backend == NULL) && !load_backend()) return FALSE;
7427 return TRUE;
7430 /******************************************************************************
7431 * XcvDataW (WINSPOOL.@)
7433 * Execute commands in the Printmonitor DLL
7435 * PARAMS
7436 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7437 * pszDataName [i] Name of the command to execute
7438 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7439 * cbInputData [i] Size in Bytes of Buffer at pInputData
7440 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7441 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7442 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7443 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7445 * RETURNS
7446 * Success: TRUE
7447 * Failure: FALSE
7449 * NOTES
7450 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7451 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7453 * Minimal List of commands, that a Printmonitor DLL should support:
7455 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7456 *| "AddPort" : Add a Port
7457 *| "DeletePort": Delete a Port
7459 * Many Printmonitors support additional commands. Examples for localspl.dll:
7460 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7461 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7464 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7465 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7466 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7468 opened_printer_t *printer;
7470 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7471 pInputData, cbInputData, pOutputData,
7472 cbOutputData, pcbOutputNeeded, pdwStatus);
7474 if ((backend == NULL) && !load_backend()) return FALSE;
7476 printer = get_opened_printer(hXcv);
7477 if (!printer || (!printer->backend_printer)) {
7478 SetLastError(ERROR_INVALID_HANDLE);
7479 return FALSE;
7482 if (!pcbOutputNeeded) {
7483 SetLastError(ERROR_INVALID_PARAMETER);
7484 return FALSE;
7487 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7488 SetLastError(RPC_X_NULL_REF_POINTER);
7489 return FALSE;
7492 *pcbOutputNeeded = 0;
7494 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7495 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7499 /*****************************************************************************
7500 * EnumPrinterDataA [WINSPOOL.@]
7503 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7504 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7505 DWORD cbData, LPDWORD pcbData )
7507 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7508 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7509 return ERROR_NO_MORE_ITEMS;
7512 /*****************************************************************************
7513 * EnumPrinterDataW [WINSPOOL.@]
7516 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7517 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7518 DWORD cbData, LPDWORD pcbData )
7520 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7521 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7522 return ERROR_NO_MORE_ITEMS;
7525 /*****************************************************************************
7526 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7529 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7530 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7531 LPDWORD pcbNeeded, LPDWORD pcReturned)
7533 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7534 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7535 pcbNeeded, pcReturned);
7536 return FALSE;
7539 /*****************************************************************************
7540 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7543 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7544 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7545 LPDWORD pcbNeeded, LPDWORD pcReturned)
7547 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7548 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7549 pcbNeeded, pcReturned);
7550 return FALSE;
7553 /*****************************************************************************
7554 * EnumPrintProcessorsA [WINSPOOL.@]
7556 * See EnumPrintProcessorsW.
7559 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7560 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7562 BOOL res;
7563 LPBYTE bufferW = NULL;
7564 LPWSTR nameW = NULL;
7565 LPWSTR envW = NULL;
7566 DWORD needed = 0;
7567 DWORD numentries = 0;
7568 INT len;
7570 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7571 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7573 /* convert names to unicode */
7574 if (pName) {
7575 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7576 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7577 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7579 if (pEnvironment) {
7580 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7581 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7582 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7585 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7586 needed = cbBuf * sizeof(WCHAR);
7587 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7588 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7590 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7591 if (pcbNeeded) needed = *pcbNeeded;
7592 /* HeapReAlloc return NULL, when bufferW was NULL */
7593 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7594 HeapAlloc(GetProcessHeap(), 0, needed);
7596 /* Try again with the large Buffer */
7597 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7599 numentries = pcReturned ? *pcReturned : 0;
7600 needed = 0;
7602 if (res) {
7603 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7604 DWORD index;
7605 LPSTR ptr;
7606 PPRINTPROCESSOR_INFO_1W ppiw;
7607 PPRINTPROCESSOR_INFO_1A ppia;
7609 /* First pass: calculate the size for all Entries */
7610 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7611 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7612 index = 0;
7613 while (index < numentries) {
7614 index++;
7615 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7616 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7618 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7619 NULL, 0, NULL, NULL);
7621 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7622 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7625 /* check for errors and quit on failure */
7626 if (cbBuf < needed) {
7627 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7628 res = FALSE;
7629 goto epp_cleanup;
7632 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7633 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7634 cbBuf -= len ; /* free Bytes in the user-Buffer */
7635 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7636 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7637 index = 0;
7638 /* Second Pass: Fill the User Buffer (if we have one) */
7639 while ((index < numentries) && pPPInfo) {
7640 index++;
7641 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7642 ppia->pName = ptr;
7643 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7644 ptr, cbBuf , NULL, NULL);
7645 ptr += len;
7646 cbBuf -= len;
7648 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7649 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7653 epp_cleanup:
7654 if (pcbNeeded) *pcbNeeded = needed;
7655 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7657 HeapFree(GetProcessHeap(), 0, nameW);
7658 HeapFree(GetProcessHeap(), 0, envW);
7659 HeapFree(GetProcessHeap(), 0, bufferW);
7661 TRACE("returning %d with %d (%d byte for %d entries)\n",
7662 (res), GetLastError(), needed, numentries);
7664 return (res);
7667 /*****************************************************************************
7668 * EnumPrintProcessorsW [WINSPOOL.@]
7670 * Enumerate available Print Processors
7672 * PARAMS
7673 * pName [I] Servername or NULL (local Computer)
7674 * pEnvironment [I] Printing-Environment or NULL (Default)
7675 * Level [I] Structure-Level (Only 1 is allowed)
7676 * pPPInfo [O] PTR to Buffer that receives the Result
7677 * cbBuf [I] Size of Buffer at pPPInfo
7678 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7679 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7681 * RETURNS
7682 * Success: TRUE
7683 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7686 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7687 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7690 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7691 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7693 if ((backend == NULL) && !load_backend()) return FALSE;
7695 if (!pcbNeeded || !pcReturned) {
7696 SetLastError(RPC_X_NULL_REF_POINTER);
7697 return FALSE;
7700 if (!pPPInfo && (cbBuf > 0)) {
7701 SetLastError(ERROR_INVALID_USER_BUFFER);
7702 return FALSE;
7705 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7706 cbBuf, pcbNeeded, pcReturned);
7709 /*****************************************************************************
7710 * ExtDeviceMode [WINSPOOL.@]
7713 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7714 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7715 DWORD fMode)
7717 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7718 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7719 debugstr_a(pProfile), fMode);
7720 return -1;
7723 /*****************************************************************************
7724 * FindClosePrinterChangeNotification [WINSPOOL.@]
7727 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7729 FIXME("Stub: %p\n", hChange);
7730 return TRUE;
7733 /*****************************************************************************
7734 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7737 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7738 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7740 FIXME("Stub: %p %x %x %p\n",
7741 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7742 return INVALID_HANDLE_VALUE;
7745 /*****************************************************************************
7746 * FindNextPrinterChangeNotification [WINSPOOL.@]
7749 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7750 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7752 FIXME("Stub: %p %p %p %p\n",
7753 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7754 return FALSE;
7757 /*****************************************************************************
7758 * FreePrinterNotifyInfo [WINSPOOL.@]
7761 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7763 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7764 return TRUE;
7767 /*****************************************************************************
7768 * string_to_buf
7770 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7771 * ansi depending on the unicode parameter.
7773 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7775 if(!str)
7777 *size = 0;
7778 return TRUE;
7781 if(unicode)
7783 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7784 if(*size <= cb)
7786 memcpy(ptr, str, *size);
7787 return TRUE;
7789 return FALSE;
7791 else
7793 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7794 if(*size <= cb)
7796 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7797 return TRUE;
7799 return FALSE;
7803 /*****************************************************************************
7804 * get_job_info_1
7806 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7807 LPDWORD pcbNeeded, BOOL unicode)
7809 DWORD size, left = cbBuf;
7810 BOOL space = (cbBuf > 0);
7811 LPBYTE ptr = buf;
7813 *pcbNeeded = 0;
7815 if(space)
7817 ji1->JobId = job->job_id;
7820 string_to_buf(job->document_title, ptr, left, &size, unicode);
7821 if(space && size <= left)
7823 ji1->pDocument = (LPWSTR)ptr;
7824 ptr += size;
7825 left -= size;
7827 else
7828 space = FALSE;
7829 *pcbNeeded += size;
7831 if (job->printer_name)
7833 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7834 if(space && size <= left)
7836 ji1->pPrinterName = (LPWSTR)ptr;
7837 ptr += size;
7838 left -= size;
7840 else
7841 space = FALSE;
7842 *pcbNeeded += size;
7845 return space;
7848 /*****************************************************************************
7849 * get_job_info_2
7851 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7852 LPDWORD pcbNeeded, BOOL unicode)
7854 DWORD size, left = cbBuf;
7855 DWORD shift;
7856 BOOL space = (cbBuf > 0);
7857 LPBYTE ptr = buf;
7858 LPDEVMODEA dmA = NULL;
7859 LPDEVMODEW devmode;
7861 *pcbNeeded = 0;
7863 if(space)
7865 ji2->JobId = job->job_id;
7868 string_to_buf(job->document_title, ptr, left, &size, unicode);
7869 if(space && size <= left)
7871 ji2->pDocument = (LPWSTR)ptr;
7872 ptr += size;
7873 left -= size;
7875 else
7876 space = FALSE;
7877 *pcbNeeded += size;
7879 if (job->printer_name)
7881 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7882 if(space && size <= left)
7884 ji2->pPrinterName = (LPWSTR)ptr;
7885 ptr += size;
7886 left -= size;
7888 else
7889 space = FALSE;
7890 *pcbNeeded += size;
7893 if (job->devmode)
7895 if (!unicode)
7897 dmA = DEVMODEdupWtoA(job->devmode);
7898 devmode = (LPDEVMODEW) dmA;
7899 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7901 else
7903 devmode = job->devmode;
7904 size = devmode->dmSize + devmode->dmDriverExtra;
7907 if (!devmode)
7908 FIXME("Can't convert DEVMODE W to A\n");
7909 else
7911 /* align DEVMODE to a DWORD boundary */
7912 shift = (4 - (*pcbNeeded & 3)) & 3;
7913 size += shift;
7915 if (size <= left)
7917 ptr += shift;
7918 memcpy(ptr, devmode, size-shift);
7919 ji2->pDevMode = (LPDEVMODEW)ptr;
7920 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7921 ptr += size-shift;
7922 left -= size;
7924 else
7925 space = FALSE;
7926 *pcbNeeded +=size;
7930 return space;
7933 /*****************************************************************************
7934 * get_job_info
7936 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7937 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7939 BOOL ret = FALSE;
7940 DWORD needed = 0, size;
7941 job_t *job;
7942 LPBYTE ptr = pJob;
7944 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7946 EnterCriticalSection(&printer_handles_cs);
7947 job = get_job(hPrinter, JobId);
7948 if(!job)
7949 goto end;
7951 switch(Level)
7953 case 1:
7954 size = sizeof(JOB_INFO_1W);
7955 if(cbBuf >= size)
7957 cbBuf -= size;
7958 ptr += size;
7959 memset(pJob, 0, size);
7961 else
7962 cbBuf = 0;
7963 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7964 needed += size;
7965 break;
7967 case 2:
7968 size = sizeof(JOB_INFO_2W);
7969 if(cbBuf >= size)
7971 cbBuf -= size;
7972 ptr += size;
7973 memset(pJob, 0, size);
7975 else
7976 cbBuf = 0;
7977 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7978 needed += size;
7979 break;
7981 case 3:
7982 size = sizeof(JOB_INFO_3);
7983 if(cbBuf >= size)
7985 cbBuf -= size;
7986 memset(pJob, 0, size);
7987 ret = TRUE;
7989 else
7990 cbBuf = 0;
7991 needed = size;
7992 break;
7994 default:
7995 SetLastError(ERROR_INVALID_LEVEL);
7996 goto end;
7998 if(pcbNeeded)
7999 *pcbNeeded = needed;
8000 end:
8001 LeaveCriticalSection(&printer_handles_cs);
8002 return ret;
8005 /*****************************************************************************
8006 * GetJobA [WINSPOOL.@]
8009 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8010 DWORD cbBuf, LPDWORD pcbNeeded)
8012 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8015 /*****************************************************************************
8016 * GetJobW [WINSPOOL.@]
8019 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8020 DWORD cbBuf, LPDWORD pcbNeeded)
8022 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8025 /*****************************************************************************
8026 * schedule_pipe
8028 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8030 #ifdef HAVE_FORK
8031 char *unixname, *cmdA;
8032 DWORD len;
8033 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8034 BOOL ret = FALSE;
8035 char buf[1024];
8036 pid_t pid, wret;
8037 int status;
8039 if(!(unixname = wine_get_unix_file_name(filename)))
8040 return FALSE;
8042 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8043 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8044 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8046 TRACE("printing with: %s\n", cmdA);
8048 if((file_fd = open(unixname, O_RDONLY)) == -1)
8049 goto end;
8051 if (pipe(fds))
8053 ERR("pipe() failed!\n");
8054 goto end;
8057 if ((pid = fork()) == 0)
8059 close(0);
8060 dup2(fds[0], 0);
8061 close(fds[1]);
8063 /* reset signals that we previously set to SIG_IGN */
8064 signal(SIGPIPE, SIG_DFL);
8066 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8067 _exit(1);
8069 else if (pid == -1)
8071 ERR("fork() failed!\n");
8072 goto end;
8075 close(fds[0]);
8076 fds[0] = -1;
8077 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8078 write(fds[1], buf, no_read);
8080 close(fds[1]);
8081 fds[1] = -1;
8083 /* reap child */
8084 do {
8085 wret = waitpid(pid, &status, 0);
8086 } while (wret < 0 && errno == EINTR);
8087 if (wret < 0)
8089 ERR("waitpid() failed!\n");
8090 goto end;
8092 if (!WIFEXITED(status) || WEXITSTATUS(status))
8094 ERR("child process failed! %d\n", status);
8095 goto end;
8098 ret = TRUE;
8100 end:
8101 if(file_fd != -1) close(file_fd);
8102 if(fds[0] != -1) close(fds[0]);
8103 if(fds[1] != -1) close(fds[1]);
8105 HeapFree(GetProcessHeap(), 0, cmdA);
8106 HeapFree(GetProcessHeap(), 0, unixname);
8107 return ret;
8108 #else
8109 return FALSE;
8110 #endif
8113 /*****************************************************************************
8114 * schedule_lpr
8116 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8118 WCHAR *cmd;
8119 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8120 BOOL r;
8122 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8123 sprintfW(cmd, fmtW, printer_name);
8125 r = schedule_pipe(cmd, filename);
8127 HeapFree(GetProcessHeap(), 0, cmd);
8128 return r;
8131 #ifdef SONAME_LIBCUPS
8132 /*****************************************************************************
8133 * get_cups_jobs_ticket_options
8135 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8136 * The CUPS scheduler only looks for these in Print-File requests, and since
8137 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8138 * parsed.
8140 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8142 FILE *fp = fopen( file, "r" );
8143 char buf[257]; /* DSC max of 256 + '\0' */
8144 const char *ps_adobe = "%!PS-Adobe-";
8145 const char *cups_job = "%cupsJobTicket:";
8147 if (!fp) return num_options;
8148 if (!fgets( buf, sizeof(buf), fp )) goto end;
8149 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8150 while (fgets( buf, sizeof(buf), fp ))
8152 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8153 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8156 end:
8157 fclose( fp );
8158 return num_options;
8160 #endif
8162 /*****************************************************************************
8163 * schedule_cups
8165 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8167 #ifdef SONAME_LIBCUPS
8168 if(pcupsPrintFile)
8170 char *unixname, *queue, *unix_doc_title;
8171 DWORD len;
8172 BOOL ret;
8173 int num_options = 0, i;
8174 cups_option_t *options = NULL;
8176 if(!(unixname = wine_get_unix_file_name(filename)))
8177 return FALSE;
8179 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8180 queue = HeapAlloc(GetProcessHeap(), 0, len);
8181 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8183 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8184 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8185 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8187 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8189 TRACE( "printing via cups with options:\n" );
8190 for (i = 0; i < num_options; i++)
8191 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8193 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8195 pcupsFreeOptions( num_options, options );
8197 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8198 HeapFree(GetProcessHeap(), 0, queue);
8199 HeapFree(GetProcessHeap(), 0, unixname);
8200 return ret;
8202 else
8203 #endif
8205 return schedule_lpr(printer_name, filename);
8209 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8211 LPWSTR filename;
8213 switch(msg)
8215 case WM_INITDIALOG:
8216 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8217 return TRUE;
8219 case WM_COMMAND:
8220 if(HIWORD(wparam) == BN_CLICKED)
8222 if(LOWORD(wparam) == IDOK)
8224 HANDLE hf;
8225 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8226 LPWSTR *output;
8228 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8229 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8231 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8233 WCHAR caption[200], message[200];
8234 int mb_ret;
8236 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8237 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8238 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8239 if(mb_ret == IDCANCEL)
8241 HeapFree(GetProcessHeap(), 0, filename);
8242 return TRUE;
8245 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8246 if(hf == INVALID_HANDLE_VALUE)
8248 WCHAR caption[200], message[200];
8250 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8251 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8252 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8253 HeapFree(GetProcessHeap(), 0, filename);
8254 return TRUE;
8256 CloseHandle(hf);
8257 DeleteFileW(filename);
8258 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8259 *output = filename;
8260 EndDialog(hwnd, IDOK);
8261 return TRUE;
8263 if(LOWORD(wparam) == IDCANCEL)
8265 EndDialog(hwnd, IDCANCEL);
8266 return TRUE;
8269 return FALSE;
8271 return FALSE;
8274 /*****************************************************************************
8275 * get_filename
8277 static BOOL get_filename(LPWSTR *filename)
8279 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8280 file_dlg_proc, (LPARAM)filename) == IDOK;
8283 /*****************************************************************************
8284 * schedule_file
8286 static BOOL schedule_file(LPCWSTR filename)
8288 LPWSTR output = NULL;
8290 if(get_filename(&output))
8292 BOOL r;
8293 TRACE("copy to %s\n", debugstr_w(output));
8294 r = CopyFileW(filename, output, FALSE);
8295 HeapFree(GetProcessHeap(), 0, output);
8296 return r;
8298 return FALSE;
8301 /*****************************************************************************
8302 * schedule_unixfile
8304 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8306 int in_fd, out_fd, no_read;
8307 char buf[1024];
8308 BOOL ret = FALSE;
8309 char *unixname, *outputA;
8310 DWORD len;
8312 if(!(unixname = wine_get_unix_file_name(filename)))
8313 return FALSE;
8315 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8316 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8317 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8319 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8320 in_fd = open(unixname, O_RDONLY);
8321 if(out_fd == -1 || in_fd == -1)
8322 goto end;
8324 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8325 write(out_fd, buf, no_read);
8327 ret = TRUE;
8328 end:
8329 if(in_fd != -1) close(in_fd);
8330 if(out_fd != -1) close(out_fd);
8331 HeapFree(GetProcessHeap(), 0, outputA);
8332 HeapFree(GetProcessHeap(), 0, unixname);
8333 return ret;
8336 /*****************************************************************************
8337 * ScheduleJob [WINSPOOL.@]
8340 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8342 opened_printer_t *printer;
8343 BOOL ret = FALSE;
8344 struct list *cursor, *cursor2;
8346 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8347 EnterCriticalSection(&printer_handles_cs);
8348 printer = get_opened_printer(hPrinter);
8349 if(!printer)
8350 goto end;
8352 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8354 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8355 HANDLE hf;
8357 if(job->job_id != dwJobID) continue;
8359 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8360 if(hf != INVALID_HANDLE_VALUE)
8362 PRINTER_INFO_5W *pi5 = NULL;
8363 LPWSTR portname = job->portname;
8364 DWORD needed;
8365 HKEY hkey;
8366 WCHAR output[1024];
8367 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8368 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8370 if (!portname)
8372 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8373 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8374 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8375 portname = pi5->pPortName;
8377 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8378 debugstr_w(portname));
8380 output[0] = 0;
8382 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8383 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8385 DWORD type, count = sizeof(output);
8386 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8387 RegCloseKey(hkey);
8389 if(output[0] == '|')
8391 ret = schedule_pipe(output + 1, job->filename);
8393 else if(output[0])
8395 ret = schedule_unixfile(output, job->filename);
8397 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8399 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8401 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8403 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8405 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8407 ret = schedule_file(job->filename);
8409 else
8411 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8413 HeapFree(GetProcessHeap(), 0, pi5);
8414 CloseHandle(hf);
8415 DeleteFileW(job->filename);
8417 list_remove(cursor);
8418 HeapFree(GetProcessHeap(), 0, job->document_title);
8419 HeapFree(GetProcessHeap(), 0, job->printer_name);
8420 HeapFree(GetProcessHeap(), 0, job->portname);
8421 HeapFree(GetProcessHeap(), 0, job->filename);
8422 HeapFree(GetProcessHeap(), 0, job->devmode);
8423 HeapFree(GetProcessHeap(), 0, job);
8424 break;
8426 end:
8427 LeaveCriticalSection(&printer_handles_cs);
8428 return ret;
8431 /*****************************************************************************
8432 * StartDocDlgA [WINSPOOL.@]
8434 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8436 UNICODE_STRING usBuffer;
8437 DOCINFOW docW;
8438 LPWSTR retW;
8439 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8440 LPSTR ret = NULL;
8442 docW.cbSize = sizeof(docW);
8443 if (doc->lpszDocName)
8445 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8446 if (!(docW.lpszDocName = docnameW)) return NULL;
8448 if (doc->lpszOutput)
8450 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8451 if (!(docW.lpszOutput = outputW)) return NULL;
8453 if (doc->lpszDatatype)
8455 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8456 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8458 docW.fwType = doc->fwType;
8460 retW = StartDocDlgW(hPrinter, &docW);
8462 if(retW)
8464 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8465 ret = HeapAlloc(GetProcessHeap(), 0, len);
8466 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8467 HeapFree(GetProcessHeap(), 0, retW);
8470 HeapFree(GetProcessHeap(), 0, datatypeW);
8471 HeapFree(GetProcessHeap(), 0, outputW);
8472 HeapFree(GetProcessHeap(), 0, docnameW);
8474 return ret;
8477 /*****************************************************************************
8478 * StartDocDlgW [WINSPOOL.@]
8480 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8481 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8482 * port is "FILE:". Also returns the full path if passed a relative path.
8484 * The caller should free the returned string from the process heap.
8486 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8488 LPWSTR ret = NULL;
8489 DWORD len, attr;
8491 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8493 PRINTER_INFO_5W *pi5;
8494 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8495 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8496 return NULL;
8497 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8498 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8499 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8501 HeapFree(GetProcessHeap(), 0, pi5);
8502 return NULL;
8504 HeapFree(GetProcessHeap(), 0, pi5);
8507 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8509 LPWSTR name;
8511 if (get_filename(&name))
8513 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8515 HeapFree(GetProcessHeap(), 0, name);
8516 return NULL;
8518 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8519 GetFullPathNameW(name, len, ret, NULL);
8520 HeapFree(GetProcessHeap(), 0, name);
8522 return ret;
8525 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8526 return NULL;
8528 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8529 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8531 attr = GetFileAttributesW(ret);
8532 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8534 HeapFree(GetProcessHeap(), 0, ret);
8535 ret = NULL;
8537 return ret;