msvcp90: Make a couple more numpunct_*_use_facet() functions static.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blobbb530de837f84d7c56c472acc71b062d31fee71d
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 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
806 *modtime = 0;
807 ppd = pcupsGetPPD( name );
809 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
811 if (!ppd) return HTTP_NOT_FOUND;
813 if (rename( ppd, buffer ) == -1)
815 BOOL res = copy_file( ppd, buffer );
816 unlink( ppd );
817 if (!res) return HTTP_NOT_FOUND;
819 return HTTP_OK;
822 static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
824 time_t modtime = 0;
825 http_status_t http_status;
826 char *unix_name = wine_get_unix_file_name( ppd );
828 TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
830 if (!unix_name) return FALSE;
832 http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
833 unix_name, strlen( unix_name ) + 1 );
834 HeapFree( GetProcessHeap(), 0, unix_name );
836 if (http_status == HTTP_OK) return TRUE;
838 TRACE( "failed to get ppd for printer %s from cups, calling fallback\n", debugstr_a(printer_name) );
839 return get_fallback_ppd( printer_name, ppd );
842 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
844 const char *value;
845 WCHAR *ret;
846 int len;
848 value = pcupsGetOption( name, num_options, options );
849 if (!value) return NULL;
851 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
852 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
853 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
855 return ret;
858 static BOOL CUPS_LoadPrinters(void)
860 int i, nrofdests;
861 BOOL hadprinter = FALSE, haddefault = FALSE;
862 cups_dest_t *dests;
863 PRINTER_INFO_2W pi2;
864 WCHAR *port, *ppd_dir = NULL, *ppd;
865 HKEY hkeyPrinter, hkeyPrinters;
866 char loaderror[256];
867 WCHAR nameW[MAX_PATH];
868 HANDLE added_printer;
870 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
871 if (!cupshandle) {
872 TRACE("%s\n", loaderror);
873 return FALSE;
875 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
877 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
878 CUPS_FUNCS;
879 #undef DO_FUNC
880 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 );
881 CUPS_OPT_FUNCS;
882 #undef DO_FUNC
884 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
885 ERROR_SUCCESS) {
886 ERR("Can't create Printers key\n");
887 return FALSE;
890 nrofdests = pcupsGetDests(&dests);
891 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
892 for (i=0;i<nrofdests;i++) {
893 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
895 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
896 lstrcpyW(port, CUPS_Port);
897 lstrcatW(port, nameW);
899 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
900 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
901 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
902 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
903 and continue */
904 TRACE("Printer already exists\n");
905 /* overwrite old LPR:* port */
906 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
907 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
908 /* flag that the PPD file should be checked for an update */
909 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
910 RegCloseKey(hkeyPrinter);
911 } else {
912 BOOL added_driver = FALSE;
914 if (!ppd_dir) ppd_dir = get_ppd_dir();
915 ppd = get_ppd_filename( ppd_dir, nameW );
916 if (get_cups_ppd( dests[i].name, ppd ))
918 added_driver = add_printer_driver( nameW, ppd );
919 unlink_ppd( ppd );
921 HeapFree( GetProcessHeap(), 0, ppd );
922 if (!added_driver) continue;
924 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
925 pi2.pPrinterName = nameW;
926 pi2.pDatatype = rawW;
927 pi2.pPrintProcessor = WinPrintW;
928 pi2.pDriverName = nameW;
929 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
930 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
931 pi2.pPortName = port;
932 pi2.pParameters = emptyStringW;
933 pi2.pShareName = emptyStringW;
934 pi2.pSepFile = emptyStringW;
936 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
937 if (added_printer) ClosePrinter( added_printer );
938 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
939 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
941 HeapFree( GetProcessHeap(), 0, pi2.pComment );
942 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
944 HeapFree( GetProcessHeap(), 0, port );
946 hadprinter = TRUE;
947 if (dests[i].is_default) {
948 SetDefaultPrinterW(nameW);
949 haddefault = TRUE;
953 if (ppd_dir)
955 RemoveDirectoryW( ppd_dir );
956 HeapFree( GetProcessHeap(), 0, ppd_dir );
959 if (hadprinter && !haddefault) {
960 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
961 SetDefaultPrinterW(nameW);
963 pcupsFreeDests(nrofdests, dests);
964 RegCloseKey(hkeyPrinters);
965 return TRUE;
968 #endif
970 static char *get_queue_name( HANDLE printer, BOOL *cups )
972 WCHAR *port, *name = NULL;
973 DWORD err, needed, type;
974 char *ret = NULL;
975 HKEY key;
977 *cups = FALSE;
979 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
980 if (err) return NULL;
981 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
982 if (err) goto end;
983 port = HeapAlloc( GetProcessHeap(), 0, needed );
984 if (!port) goto end;
985 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
987 if (!strncmpW( port, CUPS_Port, sizeof(CUPS_Port) / sizeof(WCHAR) -1 ))
989 name = port + sizeof(CUPS_Port) / sizeof(WCHAR) - 1;
990 *cups = TRUE;
992 else if (!strncmpW( port, LPR_Port, sizeof(LPR_Port) / sizeof(WCHAR) -1 ))
993 name = port + sizeof(LPR_Port) / sizeof(WCHAR) - 1;
994 if (name)
996 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
997 ret = HeapAlloc( GetProcessHeap(), 0, needed );
998 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1000 HeapFree( GetProcessHeap(), 0, port );
1001 end:
1002 RegCloseKey( key );
1003 return ret;
1007 static void set_ppd_overrides( HANDLE printer )
1009 WCHAR *wstr = NULL;
1010 int size = 0;
1011 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1012 OSStatus status;
1013 PMPrintSession session = NULL;
1014 PMPageFormat format = NULL;
1015 PMPaper paper;
1016 CFStringRef paper_name;
1017 CFRange range;
1019 status = PMCreateSession( &session );
1020 if (status) goto end;
1022 status = PMCreatePageFormat( &format );
1023 if (status) goto end;
1025 status = PMSessionDefaultPageFormat( session, format );
1026 if (status) goto end;
1028 status = PMGetPageFormatPaper( format, &paper );
1029 if (status) goto end;
1031 status = PMPaperGetPPDPaperName( paper, &paper_name );
1032 if (status) goto end;
1034 range.location = 0;
1035 range.length = CFStringGetLength( paper_name );
1036 size = (range.length + 1) * sizeof(WCHAR);
1038 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1039 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1040 wstr[range.length] = 0;
1042 end:
1043 if (format) PMRelease( format );
1044 if (session) PMRelease( session );
1045 #endif
1047 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1048 HeapFree( GetProcessHeap(), 0, wstr );
1051 static BOOL update_driver( HANDLE printer )
1053 BOOL ret, is_cups;
1054 const WCHAR *name = get_opened_printer_name( printer );
1055 WCHAR *ppd_dir, *ppd;
1056 char *queue_name;
1058 if (!name) return FALSE;
1059 queue_name = get_queue_name( printer, &is_cups );
1060 if (!queue_name) return FALSE;
1062 ppd_dir = get_ppd_dir();
1063 ppd = get_ppd_filename( ppd_dir, name );
1065 #ifdef SONAME_LIBCUPS
1066 if (is_cups)
1067 ret = get_cups_ppd( queue_name, ppd );
1068 else
1069 #endif
1070 ret = get_fallback_ppd( queue_name, ppd );
1072 if (ret)
1074 TRACE( "updating driver %s\n", debugstr_w( name ) );
1075 ret = add_printer_driver( name, ppd );
1076 unlink_ppd( ppd );
1078 HeapFree( GetProcessHeap(), 0, ppd_dir );
1079 HeapFree( GetProcessHeap(), 0, ppd );
1080 HeapFree( GetProcessHeap(), 0, queue_name );
1082 set_ppd_overrides( printer );
1084 /* call into the driver to update the devmode */
1085 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1087 return ret;
1090 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1092 PRINTER_INFO_2A pinfo2a;
1093 const char *r;
1094 size_t name_len;
1095 char *e,*s,*name,*prettyname,*devname;
1096 BOOL ret = FALSE, set_default = FALSE;
1097 char *port = NULL, *env_default;
1098 HKEY hkeyPrinter, hkeyPrinters = NULL;
1099 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1100 HANDLE added_printer;
1102 while (isspace(*pent)) pent++;
1103 r = strchr(pent,':');
1104 if (r)
1105 name_len = r - pent;
1106 else
1107 name_len = strlen(pent);
1108 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1109 memcpy(name, pent, name_len);
1110 name[name_len] = '\0';
1111 if (r)
1112 pent = r;
1113 else
1114 pent = "";
1116 TRACE("name=%s entry=%s\n",name, pent);
1118 if(ispunct(*name)) { /* a tc entry, not a real printer */
1119 TRACE("skipping tc entry\n");
1120 goto end;
1123 if(strstr(pent,":server")) { /* server only version so skip */
1124 TRACE("skipping server entry\n");
1125 goto end;
1128 /* Determine whether this is a postscript printer. */
1130 ret = TRUE;
1131 env_default = getenv("PRINTER");
1132 prettyname = name;
1133 /* Get longest name, usually the one at the right for later display. */
1134 while((s=strchr(prettyname,'|'))) {
1135 *s = '\0';
1136 e = s;
1137 while(isspace(*--e)) *e = '\0';
1138 TRACE("\t%s\n", debugstr_a(prettyname));
1139 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1140 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1143 e = prettyname + strlen(prettyname);
1144 while(isspace(*--e)) *e = '\0';
1145 TRACE("\t%s\n", debugstr_a(prettyname));
1146 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1148 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1149 * if it is too long, we use it as comment below. */
1150 devname = prettyname;
1151 if (strlen(devname)>=CCHDEVICENAME-1)
1152 devname = name;
1153 if (strlen(devname)>=CCHDEVICENAME-1) {
1154 ret = FALSE;
1155 goto end;
1158 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1159 sprintf(port,"LPR:%s",name);
1161 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1162 ERROR_SUCCESS) {
1163 ERR("Can't create Printers key\n");
1164 ret = FALSE;
1165 goto end;
1168 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
1170 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1171 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1172 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1173 and continue */
1174 TRACE("Printer already exists\n");
1175 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1176 /* flag that the PPD file should be checked for an update */
1177 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1178 RegCloseKey(hkeyPrinter);
1179 } else {
1180 static CHAR data_type[] = "RAW",
1181 print_proc[] = "WinPrint",
1182 comment[] = "WINEPS Printer using LPR",
1183 params[] = "<parameters?>",
1184 share_name[] = "<share name?>",
1185 sep_file[] = "<sep file?>";
1186 BOOL added_driver = FALSE;
1188 if (!ppd_dir) ppd_dir = get_ppd_dir();
1189 ppd = get_ppd_filename( ppd_dir, devnameW );
1190 if (get_fallback_ppd( devname, ppd ))
1192 added_driver = add_printer_driver( devnameW, ppd );
1193 unlink_ppd( ppd );
1195 HeapFree( GetProcessHeap(), 0, ppd );
1196 if (!added_driver) goto end;
1198 memset(&pinfo2a,0,sizeof(pinfo2a));
1199 pinfo2a.pPrinterName = devname;
1200 pinfo2a.pDatatype = data_type;
1201 pinfo2a.pPrintProcessor = print_proc;
1202 pinfo2a.pDriverName = devname;
1203 pinfo2a.pComment = comment;
1204 pinfo2a.pLocation = prettyname;
1205 pinfo2a.pPortName = port;
1206 pinfo2a.pParameters = params;
1207 pinfo2a.pShareName = share_name;
1208 pinfo2a.pSepFile = sep_file;
1210 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1211 if (added_printer) ClosePrinter( added_printer );
1212 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1213 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1216 if (isfirst || set_default)
1217 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1219 end:
1220 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1221 if (ppd_dir)
1223 RemoveDirectoryW( ppd_dir );
1224 HeapFree( GetProcessHeap(), 0, ppd_dir );
1226 HeapFree(GetProcessHeap(), 0, port);
1227 HeapFree(GetProcessHeap(), 0, name);
1228 return ret;
1231 static BOOL
1232 PRINTCAP_LoadPrinters(void) {
1233 BOOL hadprinter = FALSE;
1234 char buf[200];
1235 FILE *f;
1236 char *pent = NULL;
1237 BOOL had_bash = FALSE;
1239 f = fopen("/etc/printcap","r");
1240 if (!f)
1241 return FALSE;
1243 while(fgets(buf,sizeof(buf),f)) {
1244 char *start, *end;
1246 end=strchr(buf,'\n');
1247 if (end) *end='\0';
1249 start = buf;
1250 while(isspace(*start)) start++;
1251 if(*start == '#' || *start == '\0')
1252 continue;
1254 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1255 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1256 HeapFree(GetProcessHeap(),0,pent);
1257 pent = NULL;
1260 if (end && *--end == '\\') {
1261 *end = '\0';
1262 had_bash = TRUE;
1263 } else
1264 had_bash = FALSE;
1266 if (pent) {
1267 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1268 strcat(pent,start);
1269 } else {
1270 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1271 strcpy(pent,start);
1275 if(pent) {
1276 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1277 HeapFree(GetProcessHeap(),0,pent);
1279 fclose(f);
1280 return hadprinter;
1283 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1285 if (value)
1286 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1287 (lstrlenW(value) + 1) * sizeof(WCHAR));
1288 else
1289 return ERROR_FILE_NOT_FOUND;
1292 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1294 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1295 DWORD ret = ERROR_FILE_NOT_FOUND;
1297 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1298 and we support these drivers. NT writes DEVMODEW so somehow
1299 we'll need to distinguish between these when we support NT
1300 drivers */
1302 if (dmA)
1304 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1305 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1306 HeapFree( GetProcessHeap(), 0, dmA );
1309 return ret;
1312 /******************************************************************
1313 * get_servername_from_name (internal)
1315 * for an external server, a copy of the serverpart from the full name is returned
1318 static LPWSTR get_servername_from_name(LPCWSTR name)
1320 LPWSTR server;
1321 LPWSTR ptr;
1322 WCHAR buffer[MAX_PATH];
1323 DWORD len;
1325 if (name == NULL) return NULL;
1326 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1328 server = strdupW(&name[2]); /* skip over both backslash */
1329 if (server == NULL) return NULL;
1331 /* strip '\' and the printername */
1332 ptr = strchrW(server, '\\');
1333 if (ptr) ptr[0] = '\0';
1335 TRACE("found %s\n", debugstr_w(server));
1337 len = sizeof(buffer)/sizeof(buffer[0]);
1338 if (GetComputerNameW(buffer, &len)) {
1339 if (lstrcmpW(buffer, server) == 0) {
1340 /* The requested Servername is our computername */
1341 HeapFree(GetProcessHeap(), 0, server);
1342 return NULL;
1345 return server;
1348 /******************************************************************
1349 * get_basename_from_name (internal)
1351 * skip over the serverpart from the full name
1354 static LPCWSTR get_basename_from_name(LPCWSTR name)
1356 if (name == NULL) return NULL;
1357 if ((name[0] == '\\') && (name[1] == '\\')) {
1358 /* skip over the servername and search for the following '\' */
1359 name = strchrW(&name[2], '\\');
1360 if ((name) && (name[1])) {
1361 /* found a separator ('\') followed by a name:
1362 skip over the separator and return the rest */
1363 name++;
1365 else
1367 /* no basename present (we found only a servername) */
1368 return NULL;
1371 return name;
1374 static void free_printer_entry( opened_printer_t *printer )
1376 /* the queue is shared, so don't free that here */
1377 HeapFree( GetProcessHeap(), 0, printer->printername );
1378 HeapFree( GetProcessHeap(), 0, printer->name );
1379 HeapFree( GetProcessHeap(), 0, printer->devmode );
1380 HeapFree( GetProcessHeap(), 0, printer );
1383 /******************************************************************
1384 * get_opened_printer_entry
1385 * Get the first place empty in the opened printer table
1387 * ToDo:
1388 * - pDefault is ignored
1390 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1392 UINT_PTR handle = nb_printer_handles, i;
1393 jobqueue_t *queue = NULL;
1394 opened_printer_t *printer = NULL;
1395 LPWSTR servername;
1396 LPCWSTR printername;
1398 if ((backend == NULL) && !load_backend()) return NULL;
1400 servername = get_servername_from_name(name);
1401 if (servername) {
1402 FIXME("server %s not supported\n", debugstr_w(servername));
1403 HeapFree(GetProcessHeap(), 0, servername);
1404 SetLastError(ERROR_INVALID_PRINTER_NAME);
1405 return NULL;
1408 printername = get_basename_from_name(name);
1409 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1411 /* an empty printername is invalid */
1412 if (printername && (!printername[0])) {
1413 SetLastError(ERROR_INVALID_PARAMETER);
1414 return NULL;
1417 EnterCriticalSection(&printer_handles_cs);
1419 for (i = 0; i < nb_printer_handles; i++)
1421 if (!printer_handles[i])
1423 if(handle == nb_printer_handles)
1424 handle = i;
1426 else
1428 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1429 queue = printer_handles[i]->queue;
1433 if (handle >= nb_printer_handles)
1435 opened_printer_t **new_array;
1436 if (printer_handles)
1437 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1438 (nb_printer_handles + 16) * sizeof(*new_array) );
1439 else
1440 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1441 (nb_printer_handles + 16) * sizeof(*new_array) );
1443 if (!new_array)
1445 handle = 0;
1446 goto end;
1448 printer_handles = new_array;
1449 nb_printer_handles += 16;
1452 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1454 handle = 0;
1455 goto end;
1458 /* get a printer handle from the backend */
1459 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1460 handle = 0;
1461 goto end;
1464 /* clone the base name. This is NULL for the printserver */
1465 printer->printername = strdupW(printername);
1467 /* clone the full name */
1468 printer->name = strdupW(name);
1469 if (name && (!printer->name)) {
1470 handle = 0;
1471 goto end;
1474 if (pDefault && pDefault->pDevMode)
1475 printer->devmode = dup_devmode( pDefault->pDevMode );
1477 if(queue)
1478 printer->queue = queue;
1479 else
1481 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1482 if (!printer->queue) {
1483 handle = 0;
1484 goto end;
1486 list_init(&printer->queue->jobs);
1487 printer->queue->ref = 0;
1489 InterlockedIncrement(&printer->queue->ref);
1491 printer_handles[handle] = printer;
1492 handle++;
1493 end:
1494 LeaveCriticalSection(&printer_handles_cs);
1495 if (!handle && printer) {
1496 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1497 free_printer_entry( printer );
1500 return (HANDLE)handle;
1503 static void old_printer_check( BOOL delete_phase )
1505 PRINTER_INFO_5W* pi;
1506 DWORD needed, type, num, delete, i, size;
1507 const DWORD one = 1;
1508 HKEY key;
1509 HANDLE hprn;
1511 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1512 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1514 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1515 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1516 for (i = 0; i < num; i++)
1518 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1519 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1520 continue;
1522 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1524 if (!delete_phase)
1526 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1527 RegCloseKey( key );
1529 else
1531 delete = 0;
1532 size = sizeof( delete );
1533 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1534 RegCloseKey( key );
1535 if (delete)
1537 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1538 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1540 DeletePrinter( hprn );
1541 ClosePrinter( hprn );
1543 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1547 HeapFree(GetProcessHeap(), 0, pi);
1550 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1551 'M','U','T','E','X','_','_','\0'};
1552 static HANDLE init_mutex;
1554 void WINSPOOL_LoadSystemPrinters(void)
1556 HKEY hkey, hkeyPrinters;
1557 DWORD needed, num, i;
1558 WCHAR PrinterName[256];
1559 BOOL done = FALSE;
1561 /* FIXME: The init code should be moved to spoolsv.exe */
1562 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1563 if (!init_mutex)
1565 ERR( "Failed to create mutex\n" );
1566 return;
1568 if (GetLastError() == ERROR_ALREADY_EXISTS)
1570 WaitForSingleObject( init_mutex, INFINITE );
1571 ReleaseMutex( init_mutex );
1572 TRACE( "Init already done\n" );
1573 return;
1576 /* This ensures that all printer entries have a valid Name value. If causes
1577 problems later if they don't. If one is found to be missed we create one
1578 and set it equal to the name of the key */
1579 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1580 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1581 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1582 for(i = 0; i < num; i++) {
1583 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1584 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1585 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1586 set_reg_szW(hkey, NameW, PrinterName);
1588 RegCloseKey(hkey);
1593 RegCloseKey(hkeyPrinters);
1596 old_printer_check( FALSE );
1598 #ifdef SONAME_LIBCUPS
1599 done = CUPS_LoadPrinters();
1600 #endif
1602 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1603 PRINTCAP_LoadPrinters();
1605 old_printer_check( TRUE );
1607 ReleaseMutex( init_mutex );
1608 return;
1611 /******************************************************************
1612 * get_job
1614 * Get the pointer to the specified job.
1615 * Should hold the printer_handles_cs before calling.
1617 static job_t *get_job(HANDLE hprn, DWORD JobId)
1619 opened_printer_t *printer = get_opened_printer(hprn);
1620 job_t *job;
1622 if(!printer) return NULL;
1623 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1625 if(job->job_id == JobId)
1626 return job;
1628 return NULL;
1631 /***********************************************************
1632 * DEVMODEcpyAtoW
1634 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1636 BOOL Formname;
1637 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1638 DWORD size;
1640 Formname = (dmA->dmSize > off_formname);
1641 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1642 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1643 dmW->dmDeviceName, CCHDEVICENAME);
1644 if(!Formname) {
1645 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1646 dmA->dmSize - CCHDEVICENAME);
1647 } else {
1648 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1649 off_formname - CCHDEVICENAME);
1650 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1651 dmW->dmFormName, CCHFORMNAME);
1652 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1653 (off_formname + CCHFORMNAME));
1655 dmW->dmSize = size;
1656 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1657 dmA->dmDriverExtra);
1658 return dmW;
1661 /******************************************************************
1662 * convert_printerinfo_W_to_A [internal]
1665 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1666 DWORD level, DWORD outlen, DWORD numentries)
1668 DWORD id = 0;
1669 LPSTR ptr;
1670 INT len;
1672 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1674 len = pi_sizeof[level] * numentries;
1675 ptr = (LPSTR) out + len;
1676 outlen -= len;
1678 /* copy the numbers of all PRINTER_INFO_* first */
1679 memcpy(out, pPrintersW, len);
1681 while (id < numentries) {
1682 switch (level) {
1683 case 1:
1685 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1686 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1688 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1689 if (piW->pDescription) {
1690 piA->pDescription = ptr;
1691 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1692 ptr, outlen, NULL, NULL);
1693 ptr += len;
1694 outlen -= len;
1696 if (piW->pName) {
1697 piA->pName = ptr;
1698 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1699 ptr, outlen, NULL, NULL);
1700 ptr += len;
1701 outlen -= len;
1703 if (piW->pComment) {
1704 piA->pComment = ptr;
1705 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1706 ptr, outlen, NULL, NULL);
1707 ptr += len;
1708 outlen -= len;
1710 break;
1713 case 2:
1715 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1716 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1717 LPDEVMODEA dmA;
1719 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1720 if (piW->pServerName) {
1721 piA->pServerName = ptr;
1722 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1723 ptr, outlen, NULL, NULL);
1724 ptr += len;
1725 outlen -= len;
1727 if (piW->pPrinterName) {
1728 piA->pPrinterName = ptr;
1729 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1730 ptr, outlen, NULL, NULL);
1731 ptr += len;
1732 outlen -= len;
1734 if (piW->pShareName) {
1735 piA->pShareName = ptr;
1736 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1737 ptr, outlen, NULL, NULL);
1738 ptr += len;
1739 outlen -= len;
1741 if (piW->pPortName) {
1742 piA->pPortName = ptr;
1743 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1744 ptr, outlen, NULL, NULL);
1745 ptr += len;
1746 outlen -= len;
1748 if (piW->pDriverName) {
1749 piA->pDriverName = ptr;
1750 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1751 ptr, outlen, NULL, NULL);
1752 ptr += len;
1753 outlen -= len;
1755 if (piW->pComment) {
1756 piA->pComment = ptr;
1757 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1758 ptr, outlen, NULL, NULL);
1759 ptr += len;
1760 outlen -= len;
1762 if (piW->pLocation) {
1763 piA->pLocation = ptr;
1764 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1765 ptr, outlen, NULL, NULL);
1766 ptr += len;
1767 outlen -= len;
1770 dmA = DEVMODEdupWtoA(piW->pDevMode);
1771 if (dmA) {
1772 /* align DEVMODEA to a DWORD boundary */
1773 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1774 ptr += len;
1775 outlen -= len;
1777 piA->pDevMode = (LPDEVMODEA) ptr;
1778 len = dmA->dmSize + dmA->dmDriverExtra;
1779 memcpy(ptr, dmA, len);
1780 HeapFree(GetProcessHeap(), 0, dmA);
1782 ptr += len;
1783 outlen -= len;
1786 if (piW->pSepFile) {
1787 piA->pSepFile = ptr;
1788 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1789 ptr, outlen, NULL, NULL);
1790 ptr += len;
1791 outlen -= len;
1793 if (piW->pPrintProcessor) {
1794 piA->pPrintProcessor = ptr;
1795 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1796 ptr, outlen, NULL, NULL);
1797 ptr += len;
1798 outlen -= len;
1800 if (piW->pDatatype) {
1801 piA->pDatatype = ptr;
1802 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1803 ptr, outlen, NULL, NULL);
1804 ptr += len;
1805 outlen -= len;
1807 if (piW->pParameters) {
1808 piA->pParameters = ptr;
1809 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1810 ptr, outlen, NULL, NULL);
1811 ptr += len;
1812 outlen -= len;
1814 if (piW->pSecurityDescriptor) {
1815 piA->pSecurityDescriptor = NULL;
1816 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1818 break;
1821 case 4:
1823 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1824 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1826 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1828 if (piW->pPrinterName) {
1829 piA->pPrinterName = ptr;
1830 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1831 ptr, outlen, NULL, NULL);
1832 ptr += len;
1833 outlen -= len;
1835 if (piW->pServerName) {
1836 piA->pServerName = ptr;
1837 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1838 ptr, outlen, NULL, NULL);
1839 ptr += len;
1840 outlen -= len;
1842 break;
1845 case 5:
1847 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1848 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1850 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1852 if (piW->pPrinterName) {
1853 piA->pPrinterName = ptr;
1854 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1855 ptr, outlen, NULL, NULL);
1856 ptr += len;
1857 outlen -= len;
1859 if (piW->pPortName) {
1860 piA->pPortName = ptr;
1861 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1862 ptr, outlen, NULL, NULL);
1863 ptr += len;
1864 outlen -= len;
1866 break;
1869 case 6: /* 6A and 6W are the same structure */
1870 break;
1872 case 7:
1874 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1875 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1877 TRACE("(%u) #%u\n", level, id);
1878 if (piW->pszObjectGUID) {
1879 piA->pszObjectGUID = ptr;
1880 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1881 ptr, outlen, NULL, NULL);
1882 ptr += len;
1883 outlen -= len;
1885 break;
1888 case 8:
1889 case 9:
1891 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1892 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1893 LPDEVMODEA dmA;
1895 TRACE("(%u) #%u\n", level, id);
1896 dmA = DEVMODEdupWtoA(piW->pDevMode);
1897 if (dmA) {
1898 /* align DEVMODEA to a DWORD boundary */
1899 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1900 ptr += len;
1901 outlen -= len;
1903 piA->pDevMode = (LPDEVMODEA) ptr;
1904 len = dmA->dmSize + dmA->dmDriverExtra;
1905 memcpy(ptr, dmA, len);
1906 HeapFree(GetProcessHeap(), 0, dmA);
1908 ptr += len;
1909 outlen -= len;
1912 break;
1915 default:
1916 FIXME("for level %u\n", level);
1918 pPrintersW += pi_sizeof[level];
1919 out += pi_sizeof[level];
1920 id++;
1924 /******************************************************************
1925 * convert_driverinfo_W_to_A [internal]
1928 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1929 DWORD level, DWORD outlen, DWORD numentries)
1931 DWORD id = 0;
1932 LPSTR ptr;
1933 INT len;
1935 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1937 len = di_sizeof[level] * numentries;
1938 ptr = (LPSTR) out + len;
1939 outlen -= len;
1941 /* copy the numbers of all PRINTER_INFO_* first */
1942 memcpy(out, pDriversW, len);
1944 #define COPY_STRING(fld) \
1945 { if (diW->fld){ \
1946 diA->fld = ptr; \
1947 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1948 ptr += len; outlen -= len;\
1950 #define COPY_MULTIZ_STRING(fld) \
1951 { LPWSTR p = diW->fld; if (p){ \
1952 diA->fld = ptr; \
1953 do {\
1954 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1955 ptr += len; outlen -= len; p += len;\
1957 while(len > 1 && outlen > 0); \
1960 while (id < numentries)
1962 switch (level)
1964 case 1:
1966 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1967 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1969 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1971 COPY_STRING(pName);
1972 break;
1974 case 2:
1976 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1977 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1979 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1981 COPY_STRING(pName);
1982 COPY_STRING(pEnvironment);
1983 COPY_STRING(pDriverPath);
1984 COPY_STRING(pDataFile);
1985 COPY_STRING(pConfigFile);
1986 break;
1988 case 3:
1990 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1991 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1993 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1995 COPY_STRING(pName);
1996 COPY_STRING(pEnvironment);
1997 COPY_STRING(pDriverPath);
1998 COPY_STRING(pDataFile);
1999 COPY_STRING(pConfigFile);
2000 COPY_STRING(pHelpFile);
2001 COPY_MULTIZ_STRING(pDependentFiles);
2002 COPY_STRING(pMonitorName);
2003 COPY_STRING(pDefaultDataType);
2004 break;
2006 case 4:
2008 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2009 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2011 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2013 COPY_STRING(pName);
2014 COPY_STRING(pEnvironment);
2015 COPY_STRING(pDriverPath);
2016 COPY_STRING(pDataFile);
2017 COPY_STRING(pConfigFile);
2018 COPY_STRING(pHelpFile);
2019 COPY_MULTIZ_STRING(pDependentFiles);
2020 COPY_STRING(pMonitorName);
2021 COPY_STRING(pDefaultDataType);
2022 COPY_MULTIZ_STRING(pszzPreviousNames);
2023 break;
2025 case 5:
2027 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2028 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2030 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2032 COPY_STRING(pName);
2033 COPY_STRING(pEnvironment);
2034 COPY_STRING(pDriverPath);
2035 COPY_STRING(pDataFile);
2036 COPY_STRING(pConfigFile);
2037 break;
2039 case 6:
2041 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2042 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2044 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2046 COPY_STRING(pName);
2047 COPY_STRING(pEnvironment);
2048 COPY_STRING(pDriverPath);
2049 COPY_STRING(pDataFile);
2050 COPY_STRING(pConfigFile);
2051 COPY_STRING(pHelpFile);
2052 COPY_MULTIZ_STRING(pDependentFiles);
2053 COPY_STRING(pMonitorName);
2054 COPY_STRING(pDefaultDataType);
2055 COPY_MULTIZ_STRING(pszzPreviousNames);
2056 COPY_STRING(pszMfgName);
2057 COPY_STRING(pszOEMUrl);
2058 COPY_STRING(pszHardwareID);
2059 COPY_STRING(pszProvider);
2060 break;
2062 case 8:
2064 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2065 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2067 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2069 COPY_STRING(pName);
2070 COPY_STRING(pEnvironment);
2071 COPY_STRING(pDriverPath);
2072 COPY_STRING(pDataFile);
2073 COPY_STRING(pConfigFile);
2074 COPY_STRING(pHelpFile);
2075 COPY_MULTIZ_STRING(pDependentFiles);
2076 COPY_STRING(pMonitorName);
2077 COPY_STRING(pDefaultDataType);
2078 COPY_MULTIZ_STRING(pszzPreviousNames);
2079 COPY_STRING(pszMfgName);
2080 COPY_STRING(pszOEMUrl);
2081 COPY_STRING(pszHardwareID);
2082 COPY_STRING(pszProvider);
2083 COPY_STRING(pszPrintProcessor);
2084 COPY_STRING(pszVendorSetup);
2085 COPY_MULTIZ_STRING(pszzColorProfiles);
2086 COPY_STRING(pszInfPath);
2087 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2088 break;
2092 default:
2093 FIXME("for level %u\n", level);
2096 pDriversW += di_sizeof[level];
2097 out += di_sizeof[level];
2098 id++;
2101 #undef COPY_STRING
2102 #undef COPY_MULTIZ_STRING
2106 /***********************************************************
2107 * printer_info_AtoW
2109 static void *printer_info_AtoW( const void *data, DWORD level )
2111 void *ret;
2112 UNICODE_STRING usBuffer;
2114 if (!data) return NULL;
2116 if (level < 1 || level > 9) return NULL;
2118 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2119 if (!ret) return NULL;
2121 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2123 switch (level)
2125 case 2:
2127 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2128 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2130 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2131 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2132 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2133 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2134 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2135 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2136 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2137 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2138 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2139 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2140 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2141 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2142 break;
2145 case 8:
2146 case 9:
2148 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2149 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2151 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2152 break;
2155 default:
2156 FIXME( "Unhandled level %d\n", level );
2157 HeapFree( GetProcessHeap(), 0, ret );
2158 return NULL;
2161 return ret;
2164 /***********************************************************
2165 * free_printer_info
2167 static void free_printer_info( void *data, DWORD level )
2169 if (!data) return;
2171 switch (level)
2173 case 2:
2175 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2177 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2178 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2179 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2180 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2181 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2182 HeapFree( GetProcessHeap(), 0, piW->pComment );
2183 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2184 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2185 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2186 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2187 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2188 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2189 break;
2192 case 8:
2193 case 9:
2195 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2197 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2198 break;
2201 default:
2202 FIXME( "Unhandled level %d\n", level );
2205 HeapFree( GetProcessHeap(), 0, data );
2206 return;
2209 /******************************************************************
2210 * DeviceCapabilities [WINSPOOL.@]
2211 * DeviceCapabilitiesA [WINSPOOL.@]
2214 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2215 LPSTR pOutput, LPDEVMODEA lpdm)
2217 INT ret;
2219 if (!GDI_CallDeviceCapabilities16)
2221 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2222 (LPCSTR)104 );
2223 if (!GDI_CallDeviceCapabilities16) return -1;
2225 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2227 /* If DC_PAPERSIZE map POINT16s to POINTs */
2228 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2229 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2230 POINT *pt = (POINT *)pOutput;
2231 INT i;
2232 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2233 for(i = 0; i < ret; i++, pt++)
2235 pt->x = tmp[i].x;
2236 pt->y = tmp[i].y;
2238 HeapFree( GetProcessHeap(), 0, tmp );
2240 return ret;
2244 /*****************************************************************************
2245 * DeviceCapabilitiesW [WINSPOOL.@]
2247 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2250 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2251 WORD fwCapability, LPWSTR pOutput,
2252 const DEVMODEW *pDevMode)
2254 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2255 LPSTR pDeviceA = strdupWtoA(pDevice);
2256 LPSTR pPortA = strdupWtoA(pPort);
2257 INT ret;
2259 if(pOutput && (fwCapability == DC_BINNAMES ||
2260 fwCapability == DC_FILEDEPENDENCIES ||
2261 fwCapability == DC_PAPERNAMES)) {
2262 /* These need A -> W translation */
2263 INT size = 0, i;
2264 LPSTR pOutputA;
2265 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2266 dmA);
2267 if(ret == -1)
2268 return ret;
2269 switch(fwCapability) {
2270 case DC_BINNAMES:
2271 size = 24;
2272 break;
2273 case DC_PAPERNAMES:
2274 case DC_FILEDEPENDENCIES:
2275 size = 64;
2276 break;
2278 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2279 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2280 dmA);
2281 for(i = 0; i < ret; i++)
2282 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2283 pOutput + (i * size), size);
2284 HeapFree(GetProcessHeap(), 0, pOutputA);
2285 } else {
2286 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2287 (LPSTR)pOutput, dmA);
2289 HeapFree(GetProcessHeap(),0,pPortA);
2290 HeapFree(GetProcessHeap(),0,pDeviceA);
2291 HeapFree(GetProcessHeap(),0,dmA);
2292 return ret;
2295 /******************************************************************
2296 * DocumentPropertiesA [WINSPOOL.@]
2298 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2300 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2301 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2302 LPDEVMODEA pDevModeInput,DWORD fMode )
2304 LPSTR lpName = pDeviceName;
2305 static CHAR port[] = "LPT1:";
2306 LONG ret;
2308 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2309 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2312 if(!pDeviceName) {
2313 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2314 if(!lpNameW) {
2315 ERR("no name from hPrinter?\n");
2316 SetLastError(ERROR_INVALID_HANDLE);
2317 return -1;
2319 lpName = strdupWtoA(lpNameW);
2322 if (!GDI_CallExtDeviceMode16)
2324 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2325 (LPCSTR)102 );
2326 if (!GDI_CallExtDeviceMode16) {
2327 ERR("No CallExtDeviceMode16?\n");
2328 return -1;
2331 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2332 pDevModeInput, NULL, fMode);
2334 if(!pDeviceName)
2335 HeapFree(GetProcessHeap(),0,lpName);
2336 return ret;
2340 /*****************************************************************************
2341 * DocumentPropertiesW (WINSPOOL.@)
2343 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2345 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2346 LPWSTR pDeviceName,
2347 LPDEVMODEW pDevModeOutput,
2348 LPDEVMODEW pDevModeInput, DWORD fMode)
2351 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2352 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2353 LPDEVMODEA pDevModeOutputA = NULL;
2354 LONG ret;
2356 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2357 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2358 fMode);
2359 if(pDevModeOutput) {
2360 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2361 if(ret < 0) return ret;
2362 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2364 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2365 pDevModeInputA, fMode);
2366 if(pDevModeOutput) {
2367 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2368 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2370 if(fMode == 0 && ret > 0)
2371 ret += (CCHDEVICENAME + CCHFORMNAME);
2372 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2373 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2374 return ret;
2377 /*****************************************************************************
2378 * IsValidDevmodeA [WINSPOOL.@]
2380 * Validate a DEVMODE structure and fix errors if possible.
2383 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2385 FIXME("(%p,%ld): stub\n", pDevMode, size);
2387 if(!pDevMode)
2388 return FALSE;
2390 return TRUE;
2393 /*****************************************************************************
2394 * IsValidDevmodeW [WINSPOOL.@]
2396 * Validate a DEVMODE structure and fix errors if possible.
2399 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2401 FIXME("(%p,%ld): stub\n", pDevMode, size);
2403 if(!pDevMode)
2404 return FALSE;
2406 return TRUE;
2409 /******************************************************************
2410 * OpenPrinterA [WINSPOOL.@]
2412 * See OpenPrinterW.
2415 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2416 LPPRINTER_DEFAULTSA pDefault)
2418 UNICODE_STRING lpPrinterNameW;
2419 UNICODE_STRING usBuffer;
2420 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2421 PWSTR pwstrPrinterNameW;
2422 BOOL ret;
2424 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2426 if(pDefault) {
2427 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2428 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2429 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2430 pDefaultW = &DefaultW;
2432 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2433 if(pDefault) {
2434 RtlFreeUnicodeString(&usBuffer);
2435 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2437 RtlFreeUnicodeString(&lpPrinterNameW);
2438 return ret;
2441 /******************************************************************
2442 * OpenPrinterW [WINSPOOL.@]
2444 * Open a Printer / Printserver or a Printer-Object
2446 * PARAMS
2447 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2448 * phPrinter [O] The resulting Handle is stored here
2449 * pDefault [I] PTR to Default Printer Settings or NULL
2451 * RETURNS
2452 * Success: TRUE
2453 * Failure: FALSE
2455 * NOTES
2456 * lpPrinterName is one of:
2457 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2458 *| Printer: "PrinterName"
2459 *| Printer-Object: "PrinterName,Job xxx"
2460 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2461 *| XcvPort: "Servername,XcvPort PortName"
2463 * BUGS
2464 *| Printer-Object not supported
2465 *| pDefaults is ignored
2468 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2471 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2473 if(!phPrinter) {
2474 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2475 SetLastError(ERROR_INVALID_PARAMETER);
2476 return FALSE;
2479 /* Get the unique handle of the printer or Printserver */
2480 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2482 if (*phPrinter)
2484 HKEY key;
2485 DWORD deleting = 0, size = sizeof( deleting ), type;
2486 DWORD status;
2487 WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key );
2488 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2489 WaitForSingleObject( init_mutex, INFINITE );
2490 status = get_dword_from_reg( key, StatusW );
2491 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2492 ReleaseMutex( init_mutex );
2493 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2494 update_driver( *phPrinter );
2495 RegCloseKey( key );
2498 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2499 return (*phPrinter != 0);
2502 /******************************************************************
2503 * AddMonitorA [WINSPOOL.@]
2505 * See AddMonitorW.
2508 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2510 LPWSTR nameW = NULL;
2511 INT len;
2512 BOOL res;
2513 LPMONITOR_INFO_2A mi2a;
2514 MONITOR_INFO_2W mi2w;
2516 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2517 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2518 debugstr_a(mi2a ? mi2a->pName : NULL),
2519 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2520 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2522 if (Level != 2) {
2523 SetLastError(ERROR_INVALID_LEVEL);
2524 return FALSE;
2527 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2528 if (mi2a == NULL) {
2529 return FALSE;
2532 if (pName) {
2533 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2534 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2535 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2538 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2539 if (mi2a->pName) {
2540 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2541 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2542 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2544 if (mi2a->pEnvironment) {
2545 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2546 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2547 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2549 if (mi2a->pDLLName) {
2550 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2551 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2552 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2555 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2557 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2558 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2559 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2561 HeapFree(GetProcessHeap(), 0, nameW);
2562 return (res);
2565 /******************************************************************************
2566 * AddMonitorW [WINSPOOL.@]
2568 * Install a Printmonitor
2570 * PARAMS
2571 * pName [I] Servername or NULL (local Computer)
2572 * Level [I] Structure-Level (Must be 2)
2573 * pMonitors [I] PTR to MONITOR_INFO_2
2575 * RETURNS
2576 * Success: TRUE
2577 * Failure: FALSE
2579 * NOTES
2580 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2583 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2585 LPMONITOR_INFO_2W mi2w;
2587 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2588 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2589 debugstr_w(mi2w ? mi2w->pName : NULL),
2590 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2591 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2593 if ((backend == NULL) && !load_backend()) return FALSE;
2595 if (Level != 2) {
2596 SetLastError(ERROR_INVALID_LEVEL);
2597 return FALSE;
2600 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2601 if (mi2w == NULL) {
2602 return FALSE;
2605 return backend->fpAddMonitor(pName, Level, pMonitors);
2608 /******************************************************************
2609 * DeletePrinterDriverA [WINSPOOL.@]
2612 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2614 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2617 /******************************************************************
2618 * DeletePrinterDriverW [WINSPOOL.@]
2621 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2623 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2626 /******************************************************************
2627 * DeleteMonitorA [WINSPOOL.@]
2629 * See DeleteMonitorW.
2632 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2634 LPWSTR nameW = NULL;
2635 LPWSTR EnvironmentW = NULL;
2636 LPWSTR MonitorNameW = NULL;
2637 BOOL res;
2638 INT len;
2640 if (pName) {
2641 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2642 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2643 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2646 if (pEnvironment) {
2647 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2648 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2649 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2651 if (pMonitorName) {
2652 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2653 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2654 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2657 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2659 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2660 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2661 HeapFree(GetProcessHeap(), 0, nameW);
2662 return (res);
2665 /******************************************************************
2666 * DeleteMonitorW [WINSPOOL.@]
2668 * Delete a specific Printmonitor from a Printing-Environment
2670 * PARAMS
2671 * pName [I] Servername or NULL (local Computer)
2672 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2673 * pMonitorName [I] Name of the Monitor, that should be deleted
2675 * RETURNS
2676 * Success: TRUE
2677 * Failure: FALSE
2679 * NOTES
2680 * pEnvironment is ignored in Windows for the local Computer.
2683 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2686 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2687 debugstr_w(pMonitorName));
2689 if ((backend == NULL) && !load_backend()) return FALSE;
2691 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2695 /******************************************************************
2696 * DeletePortA [WINSPOOL.@]
2698 * See DeletePortW.
2701 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2703 LPWSTR nameW = NULL;
2704 LPWSTR portW = NULL;
2705 INT len;
2706 DWORD res;
2708 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2710 /* convert servername to unicode */
2711 if (pName) {
2712 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2713 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2714 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2717 /* convert portname to unicode */
2718 if (pPortName) {
2719 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2720 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2721 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2724 res = DeletePortW(nameW, hWnd, portW);
2725 HeapFree(GetProcessHeap(), 0, nameW);
2726 HeapFree(GetProcessHeap(), 0, portW);
2727 return res;
2730 /******************************************************************
2731 * DeletePortW [WINSPOOL.@]
2733 * Delete a specific Port
2735 * PARAMS
2736 * pName [I] Servername or NULL (local Computer)
2737 * hWnd [I] Handle to parent Window for the Dialog-Box
2738 * pPortName [I] Name of the Port, that should be deleted
2740 * RETURNS
2741 * Success: TRUE
2742 * Failure: FALSE
2745 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2747 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2749 if ((backend == NULL) && !load_backend()) return FALSE;
2751 if (!pPortName) {
2752 SetLastError(RPC_X_NULL_REF_POINTER);
2753 return FALSE;
2756 return backend->fpDeletePort(pName, hWnd, pPortName);
2759 /******************************************************************************
2760 * WritePrinter [WINSPOOL.@]
2762 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2764 opened_printer_t *printer;
2765 BOOL ret = FALSE;
2767 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2769 EnterCriticalSection(&printer_handles_cs);
2770 printer = get_opened_printer(hPrinter);
2771 if(!printer)
2773 SetLastError(ERROR_INVALID_HANDLE);
2774 goto end;
2777 if(!printer->doc)
2779 SetLastError(ERROR_SPL_NO_STARTDOC);
2780 goto end;
2783 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2784 end:
2785 LeaveCriticalSection(&printer_handles_cs);
2786 return ret;
2789 /*****************************************************************************
2790 * AddFormA [WINSPOOL.@]
2792 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2794 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2795 return 1;
2798 /*****************************************************************************
2799 * AddFormW [WINSPOOL.@]
2801 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2803 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2804 return 1;
2807 /*****************************************************************************
2808 * AddJobA [WINSPOOL.@]
2810 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2812 BOOL ret;
2813 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2814 DWORD needed;
2816 if(Level != 1) {
2817 SetLastError(ERROR_INVALID_LEVEL);
2818 return FALSE;
2821 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2823 if(ret) {
2824 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2825 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2826 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2827 if(*pcbNeeded > cbBuf) {
2828 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2829 ret = FALSE;
2830 } else {
2831 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2832 addjobA->JobId = addjobW->JobId;
2833 addjobA->Path = (char *)(addjobA + 1);
2834 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2837 return ret;
2840 /*****************************************************************************
2841 * AddJobW [WINSPOOL.@]
2843 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2845 opened_printer_t *printer;
2846 job_t *job;
2847 BOOL ret = FALSE;
2848 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2849 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2850 WCHAR path[MAX_PATH], filename[MAX_PATH];
2851 DWORD len;
2852 ADDJOB_INFO_1W *addjob;
2854 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2856 EnterCriticalSection(&printer_handles_cs);
2858 printer = get_opened_printer(hPrinter);
2860 if(!printer) {
2861 SetLastError(ERROR_INVALID_HANDLE);
2862 goto end;
2865 if(Level != 1) {
2866 SetLastError(ERROR_INVALID_LEVEL);
2867 goto end;
2870 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2871 if(!job)
2872 goto end;
2874 job->job_id = InterlockedIncrement(&next_job_id);
2876 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2877 if(path[len - 1] != '\\')
2878 path[len++] = '\\';
2879 memcpy(path + len, spool_path, sizeof(spool_path));
2880 sprintfW(filename, fmtW, path, job->job_id);
2882 len = strlenW(filename);
2883 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2884 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2885 job->portname = NULL;
2886 job->document_title = strdupW(default_doc_title);
2887 job->printer_name = strdupW(printer->name);
2888 job->devmode = dup_devmode( printer->devmode );
2889 list_add_tail(&printer->queue->jobs, &job->entry);
2891 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2892 if(*pcbNeeded <= cbBuf) {
2893 addjob = (ADDJOB_INFO_1W*)pData;
2894 addjob->JobId = job->job_id;
2895 addjob->Path = (WCHAR *)(addjob + 1);
2896 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2897 ret = TRUE;
2898 } else
2899 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2901 end:
2902 LeaveCriticalSection(&printer_handles_cs);
2903 return ret;
2906 /*****************************************************************************
2907 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2909 * Return the PATH for the Print-Processors
2911 * See GetPrintProcessorDirectoryW.
2915 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2916 DWORD level, LPBYTE Info,
2917 DWORD cbBuf, LPDWORD pcbNeeded)
2919 LPWSTR serverW = NULL;
2920 LPWSTR envW = NULL;
2921 BOOL ret;
2922 INT len;
2924 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2925 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2928 if (server) {
2929 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2930 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2931 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2934 if (env) {
2935 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2936 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2937 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2940 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2941 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2943 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2944 cbBuf, pcbNeeded);
2946 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2947 cbBuf, NULL, NULL) > 0;
2950 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2951 HeapFree(GetProcessHeap(), 0, envW);
2952 HeapFree(GetProcessHeap(), 0, serverW);
2953 return ret;
2956 /*****************************************************************************
2957 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2959 * Return the PATH for the Print-Processors
2961 * PARAMS
2962 * server [I] Servername (NT only) or NULL (local Computer)
2963 * env [I] Printing-Environment (see below) or NULL (Default)
2964 * level [I] Structure-Level (must be 1)
2965 * Info [O] PTR to Buffer that receives the Result
2966 * cbBuf [I] Size of Buffer at "Info"
2967 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2968 * required for the Buffer at "Info"
2970 * RETURNS
2971 * Success: TRUE and in pcbNeeded the Bytes used in Info
2972 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2973 * if cbBuf is too small
2975 * Native Values returned in Info on Success:
2976 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2977 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2978 *| win9x(Windows 4.0): "%winsysdir%"
2980 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2982 * BUGS
2983 * Only NULL or "" is supported for server
2986 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2987 DWORD level, LPBYTE Info,
2988 DWORD cbBuf, LPDWORD pcbNeeded)
2991 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2992 Info, cbBuf, pcbNeeded);
2994 if ((backend == NULL) && !load_backend()) return FALSE;
2996 if (level != 1) {
2997 /* (Level != 1) is ignored in win9x */
2998 SetLastError(ERROR_INVALID_LEVEL);
2999 return FALSE;
3002 if (pcbNeeded == NULL) {
3003 /* (pcbNeeded == NULL) is ignored in win9x */
3004 SetLastError(RPC_X_NULL_REF_POINTER);
3005 return FALSE;
3008 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3011 /*****************************************************************************
3012 * WINSPOOL_OpenDriverReg [internal]
3014 * opens the registry for the printer drivers depending on the given input
3015 * variable pEnvironment
3017 * RETURNS:
3018 * the opened hkey on success
3019 * NULL on error
3021 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3023 HKEY retval = NULL;
3024 LPWSTR buffer;
3025 const printenv_t * env;
3027 TRACE("(%s)\n", debugstr_w(pEnvironment));
3029 env = validate_envW(pEnvironment);
3030 if (!env) return NULL;
3032 buffer = HeapAlloc( GetProcessHeap(), 0,
3033 (strlenW(DriversW) + strlenW(env->envname) +
3034 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3035 if(buffer) {
3036 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3037 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3038 HeapFree(GetProcessHeap(), 0, buffer);
3040 return retval;
3043 /*****************************************************************************
3044 * set_devices_and_printerports [internal]
3046 * set the [Devices] and [PrinterPorts] entries for a printer.
3049 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3051 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3052 WCHAR *devline;
3053 HKEY hkey;
3055 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3057 /* FIXME: the driver must change to "winspool" */
3058 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3059 if (devline) {
3060 lstrcpyW(devline, driver_nt);
3061 lstrcatW(devline, commaW);
3062 lstrcatW(devline, pi->pPortName);
3064 TRACE("using %s\n", debugstr_w(devline));
3065 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
3066 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3067 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3068 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3069 RegCloseKey(hkey);
3072 lstrcatW(devline, timeout_15_45);
3073 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
3074 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3075 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3076 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3077 RegCloseKey(hkey);
3079 HeapFree(GetProcessHeap(), 0, devline);
3083 /*****************************************************************************
3084 * AddPrinterW [WINSPOOL.@]
3086 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3088 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3089 LPDEVMODEW dm;
3090 HANDLE retval;
3091 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3092 LONG size;
3094 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3096 if(pName != NULL) {
3097 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3098 SetLastError(ERROR_INVALID_PARAMETER);
3099 return 0;
3101 if(Level != 2) {
3102 ERR("Level = %d, unsupported!\n", Level);
3103 SetLastError(ERROR_INVALID_LEVEL);
3104 return 0;
3106 if(!pPrinter) {
3107 SetLastError(ERROR_INVALID_PARAMETER);
3108 return 0;
3110 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3111 ERROR_SUCCESS) {
3112 ERR("Can't create Printers key\n");
3113 return 0;
3115 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3116 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3117 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3118 RegCloseKey(hkeyPrinter);
3119 RegCloseKey(hkeyPrinters);
3120 return 0;
3122 RegCloseKey(hkeyPrinter);
3124 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3125 if(!hkeyDrivers) {
3126 ERR("Can't create Drivers key\n");
3127 RegCloseKey(hkeyPrinters);
3128 return 0;
3130 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3131 ERROR_SUCCESS) {
3132 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3133 RegCloseKey(hkeyPrinters);
3134 RegCloseKey(hkeyDrivers);
3135 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3136 return 0;
3138 RegCloseKey(hkeyDriver);
3139 RegCloseKey(hkeyDrivers);
3141 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3142 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3143 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3144 RegCloseKey(hkeyPrinters);
3145 return 0;
3148 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3149 ERROR_SUCCESS) {
3150 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3151 SetLastError(ERROR_INVALID_PRINTER_NAME);
3152 RegCloseKey(hkeyPrinters);
3153 return 0;
3156 set_devices_and_printerports(pi);
3158 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3159 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3160 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3161 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3162 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3163 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3164 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3165 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3166 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3167 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3168 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3169 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3170 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3171 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3172 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3173 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3174 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3175 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3177 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3179 if (size < 0)
3181 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3182 size = sizeof(DEVMODEW);
3184 if(pi->pDevMode)
3185 dm = pi->pDevMode;
3186 else
3188 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3189 dm->dmSize = size;
3190 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3192 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3193 HeapFree( GetProcessHeap(), 0, dm );
3194 dm = NULL;
3196 else
3198 /* set devmode to printer name */
3199 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3203 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3204 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3206 RegCloseKey(hkeyPrinter);
3207 RegCloseKey(hkeyPrinters);
3208 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3209 ERR("OpenPrinter failing\n");
3210 return 0;
3212 return retval;
3215 /*****************************************************************************
3216 * AddPrinterA [WINSPOOL.@]
3218 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3220 UNICODE_STRING pNameW;
3221 PWSTR pwstrNameW;
3222 PRINTER_INFO_2W *piW;
3223 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3224 HANDLE ret;
3226 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3227 if(Level != 2) {
3228 ERR("Level = %d, unsupported!\n", Level);
3229 SetLastError(ERROR_INVALID_LEVEL);
3230 return 0;
3232 pwstrNameW = asciitounicode(&pNameW,pName);
3233 piW = printer_info_AtoW( piA, Level );
3235 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3237 free_printer_info( piW, Level );
3238 RtlFreeUnicodeString(&pNameW);
3239 return ret;
3243 /*****************************************************************************
3244 * ClosePrinter [WINSPOOL.@]
3246 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3248 UINT_PTR i = (UINT_PTR)hPrinter;
3249 opened_printer_t *printer = NULL;
3250 BOOL ret = FALSE;
3252 TRACE("(%p)\n", hPrinter);
3254 EnterCriticalSection(&printer_handles_cs);
3256 if ((i > 0) && (i <= nb_printer_handles))
3257 printer = printer_handles[i - 1];
3260 if(printer)
3262 struct list *cursor, *cursor2;
3264 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3266 if (printer->backend_printer) {
3267 backend->fpClosePrinter(printer->backend_printer);
3270 if(printer->doc)
3271 EndDocPrinter(hPrinter);
3273 if(InterlockedDecrement(&printer->queue->ref) == 0)
3275 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3277 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3278 ScheduleJob(hPrinter, job->job_id);
3280 HeapFree(GetProcessHeap(), 0, printer->queue);
3283 free_printer_entry( printer );
3284 printer_handles[i - 1] = NULL;
3285 ret = TRUE;
3287 LeaveCriticalSection(&printer_handles_cs);
3288 return ret;
3291 /*****************************************************************************
3292 * DeleteFormA [WINSPOOL.@]
3294 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3296 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3297 return 1;
3300 /*****************************************************************************
3301 * DeleteFormW [WINSPOOL.@]
3303 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3305 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3306 return 1;
3309 /*****************************************************************************
3310 * DeletePrinter [WINSPOOL.@]
3312 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3314 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3315 HKEY hkeyPrinters, hkey;
3316 WCHAR def[MAX_PATH];
3317 DWORD size = sizeof( def ) / sizeof( def[0] );
3319 if(!lpNameW) {
3320 SetLastError(ERROR_INVALID_HANDLE);
3321 return FALSE;
3323 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3324 RegDeleteTreeW(hkeyPrinters, lpNameW);
3325 RegCloseKey(hkeyPrinters);
3327 WriteProfileStringW(devicesW, lpNameW, NULL);
3328 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3330 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3331 RegDeleteValueW(hkey, lpNameW);
3332 RegCloseKey(hkey);
3335 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3336 RegDeleteValueW(hkey, lpNameW);
3337 RegCloseKey(hkey);
3340 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3342 WriteProfileStringW( windowsW, deviceW, NULL );
3343 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3345 RegDeleteValueW( hkey, deviceW );
3346 RegCloseKey( hkey );
3348 SetDefaultPrinterW( NULL );
3351 return TRUE;
3354 /*****************************************************************************
3355 * SetPrinterA [WINSPOOL.@]
3357 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3359 BYTE *dataW = data;
3360 BOOL ret;
3362 if (level != 0)
3364 dataW = printer_info_AtoW( data, level );
3365 if (!dataW) return FALSE;
3368 ret = SetPrinterW( printer, level, dataW, command );
3370 if (dataW != data) free_printer_info( dataW, level );
3372 return ret;
3375 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3377 set_reg_szW( key, NameW, pi->pPrinterName );
3378 set_reg_szW( key, Share_NameW, pi->pShareName );
3379 set_reg_szW( key, PortW, pi->pPortName );
3380 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3381 set_reg_szW( key, DescriptionW, pi->pComment );
3382 set_reg_szW( key, LocationW, pi->pLocation );
3384 if (pi->pDevMode)
3385 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3387 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3388 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3389 set_reg_szW( key, DatatypeW, pi->pDatatype );
3390 set_reg_szW( key, ParametersW, pi->pParameters );
3392 set_reg_DWORD( key, AttributesW, pi->Attributes );
3393 set_reg_DWORD( key, PriorityW, pi->Priority );
3394 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3395 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3396 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3399 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3401 if (!pi->pDevMode) return FALSE;
3403 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3404 return TRUE;
3407 /******************************************************************************
3408 * SetPrinterW [WINSPOOL.@]
3410 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3412 HKEY key;
3413 BOOL ret = FALSE;
3415 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3417 if (command != 0) FIXME( "Ignoring command %d\n", command );
3419 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3420 return FALSE;
3422 switch (level)
3424 case 2:
3426 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3427 set_printer_2( key, pi2 );
3428 ret = TRUE;
3429 break;
3432 case 9:
3434 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3435 ret = set_printer_9( key, pi );
3436 break;
3439 default:
3440 FIXME( "Unimplemented level %d\n", level );
3441 SetLastError( ERROR_INVALID_LEVEL );
3444 RegCloseKey( key );
3445 return ret;
3448 /*****************************************************************************
3449 * SetJobA [WINSPOOL.@]
3451 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3452 LPBYTE pJob, DWORD Command)
3454 BOOL ret;
3455 LPBYTE JobW;
3456 UNICODE_STRING usBuffer;
3458 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3460 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3461 are all ignored by SetJob, so we don't bother copying them */
3462 switch(Level)
3464 case 0:
3465 JobW = NULL;
3466 break;
3467 case 1:
3469 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3470 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3472 JobW = (LPBYTE)info1W;
3473 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3474 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3475 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3476 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3477 info1W->Status = info1A->Status;
3478 info1W->Priority = info1A->Priority;
3479 info1W->Position = info1A->Position;
3480 info1W->PagesPrinted = info1A->PagesPrinted;
3481 break;
3483 case 2:
3485 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3486 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3488 JobW = (LPBYTE)info2W;
3489 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3490 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3491 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3492 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3493 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3494 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3495 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3496 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3497 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3498 info2W->Status = info2A->Status;
3499 info2W->Priority = info2A->Priority;
3500 info2W->Position = info2A->Position;
3501 info2W->StartTime = info2A->StartTime;
3502 info2W->UntilTime = info2A->UntilTime;
3503 info2W->PagesPrinted = info2A->PagesPrinted;
3504 break;
3506 case 3:
3507 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3508 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3509 break;
3510 default:
3511 SetLastError(ERROR_INVALID_LEVEL);
3512 return FALSE;
3515 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3517 switch(Level)
3519 case 1:
3521 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3522 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3523 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3524 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3525 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3526 break;
3528 case 2:
3530 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3531 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3532 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3533 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3534 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3535 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3536 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3537 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3538 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3539 break;
3542 HeapFree(GetProcessHeap(), 0, JobW);
3544 return ret;
3547 /*****************************************************************************
3548 * SetJobW [WINSPOOL.@]
3550 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3551 LPBYTE pJob, DWORD Command)
3553 BOOL ret = FALSE;
3554 job_t *job;
3556 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3557 FIXME("Ignoring everything other than document title\n");
3559 EnterCriticalSection(&printer_handles_cs);
3560 job = get_job(hPrinter, JobId);
3561 if(!job)
3562 goto end;
3564 switch(Level)
3566 case 0:
3567 break;
3568 case 1:
3570 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3571 HeapFree(GetProcessHeap(), 0, job->document_title);
3572 job->document_title = strdupW(info1->pDocument);
3573 break;
3575 case 2:
3577 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3578 HeapFree(GetProcessHeap(), 0, job->document_title);
3579 job->document_title = strdupW(info2->pDocument);
3580 HeapFree(GetProcessHeap(), 0, job->devmode);
3581 job->devmode = dup_devmode( info2->pDevMode );
3582 break;
3584 case 3:
3585 break;
3586 default:
3587 SetLastError(ERROR_INVALID_LEVEL);
3588 goto end;
3590 ret = TRUE;
3591 end:
3592 LeaveCriticalSection(&printer_handles_cs);
3593 return ret;
3596 /*****************************************************************************
3597 * EndDocPrinter [WINSPOOL.@]
3599 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3601 opened_printer_t *printer;
3602 BOOL ret = FALSE;
3603 TRACE("(%p)\n", hPrinter);
3605 EnterCriticalSection(&printer_handles_cs);
3607 printer = get_opened_printer(hPrinter);
3608 if(!printer)
3610 SetLastError(ERROR_INVALID_HANDLE);
3611 goto end;
3614 if(!printer->doc)
3616 SetLastError(ERROR_SPL_NO_STARTDOC);
3617 goto end;
3620 CloseHandle(printer->doc->hf);
3621 ScheduleJob(hPrinter, printer->doc->job_id);
3622 HeapFree(GetProcessHeap(), 0, printer->doc);
3623 printer->doc = NULL;
3624 ret = TRUE;
3625 end:
3626 LeaveCriticalSection(&printer_handles_cs);
3627 return ret;
3630 /*****************************************************************************
3631 * EndPagePrinter [WINSPOOL.@]
3633 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3635 FIXME("(%p): stub\n", hPrinter);
3636 return TRUE;
3639 /*****************************************************************************
3640 * StartDocPrinterA [WINSPOOL.@]
3642 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3644 UNICODE_STRING usBuffer;
3645 DOC_INFO_2W doc2W;
3646 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3647 DWORD ret;
3649 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3650 or one (DOC_INFO_3) extra DWORDs */
3652 switch(Level) {
3653 case 2:
3654 doc2W.JobId = doc2->JobId;
3655 /* fall through */
3656 case 3:
3657 doc2W.dwMode = doc2->dwMode;
3658 /* fall through */
3659 case 1:
3660 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3661 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3662 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3663 break;
3665 default:
3666 SetLastError(ERROR_INVALID_LEVEL);
3667 return FALSE;
3670 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3672 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3673 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3674 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3676 return ret;
3679 /*****************************************************************************
3680 * StartDocPrinterW [WINSPOOL.@]
3682 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3684 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3685 opened_printer_t *printer;
3686 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3687 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3688 JOB_INFO_1W job_info;
3689 DWORD needed, ret = 0;
3690 HANDLE hf;
3691 WCHAR *filename;
3692 job_t *job;
3694 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3695 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3696 debugstr_w(doc->pDatatype));
3698 if(Level < 1 || Level > 3)
3700 SetLastError(ERROR_INVALID_LEVEL);
3701 return 0;
3704 EnterCriticalSection(&printer_handles_cs);
3705 printer = get_opened_printer(hPrinter);
3706 if(!printer)
3708 SetLastError(ERROR_INVALID_HANDLE);
3709 goto end;
3712 if(printer->doc)
3714 SetLastError(ERROR_INVALID_PRINTER_STATE);
3715 goto end;
3718 /* Even if we're printing to a file we still add a print job, we'll
3719 just ignore the spool file name */
3721 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3723 ERR("AddJob failed gle %u\n", GetLastError());
3724 goto end;
3727 /* use pOutputFile only, when it is a real filename */
3728 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3729 filename = doc->pOutputFile;
3730 else
3731 filename = addjob->Path;
3733 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3734 if(hf == INVALID_HANDLE_VALUE)
3735 goto end;
3737 memset(&job_info, 0, sizeof(job_info));
3738 job_info.pDocument = doc->pDocName;
3739 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3741 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3742 printer->doc->hf = hf;
3743 ret = printer->doc->job_id = addjob->JobId;
3744 job = get_job(hPrinter, ret);
3745 job->portname = strdupW(doc->pOutputFile);
3747 end:
3748 LeaveCriticalSection(&printer_handles_cs);
3750 return ret;
3753 /*****************************************************************************
3754 * StartPagePrinter [WINSPOOL.@]
3756 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3758 FIXME("(%p): stub\n", hPrinter);
3759 return TRUE;
3762 /*****************************************************************************
3763 * GetFormA [WINSPOOL.@]
3765 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3766 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3768 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3769 Level,pForm,cbBuf,pcbNeeded);
3770 return FALSE;
3773 /*****************************************************************************
3774 * GetFormW [WINSPOOL.@]
3776 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3777 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3779 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3780 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3781 return FALSE;
3784 /*****************************************************************************
3785 * SetFormA [WINSPOOL.@]
3787 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3788 LPBYTE pForm)
3790 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3791 return FALSE;
3794 /*****************************************************************************
3795 * SetFormW [WINSPOOL.@]
3797 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3798 LPBYTE pForm)
3800 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3801 return FALSE;
3804 /*****************************************************************************
3805 * ReadPrinter [WINSPOOL.@]
3807 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3808 LPDWORD pNoBytesRead)
3810 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3811 return FALSE;
3814 /*****************************************************************************
3815 * ResetPrinterA [WINSPOOL.@]
3817 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3819 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3820 return FALSE;
3823 /*****************************************************************************
3824 * ResetPrinterW [WINSPOOL.@]
3826 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3828 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3829 return FALSE;
3832 /*****************************************************************************
3833 * get_filename_from_reg [internal]
3835 * Get ValueName from hkey storing result in out
3836 * when the Value in the registry has only a filename, use driverdir as prefix
3837 * outlen is space left in out
3838 * String is stored either as unicode or ascii
3842 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3843 LPBYTE out, DWORD outlen, LPDWORD needed)
3845 WCHAR filename[MAX_PATH];
3846 DWORD size;
3847 DWORD type;
3848 LONG ret;
3849 LPWSTR buffer = filename;
3850 LPWSTR ptr;
3852 *needed = 0;
3853 size = sizeof(filename);
3854 buffer[0] = '\0';
3855 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3856 if (ret == ERROR_MORE_DATA) {
3857 TRACE("need dynamic buffer: %u\n", size);
3858 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3859 if (!buffer) {
3860 /* No Memory is bad */
3861 return FALSE;
3863 buffer[0] = '\0';
3864 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3867 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3868 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3869 return FALSE;
3872 ptr = buffer;
3873 while (ptr) {
3874 /* do we have a full path ? */
3875 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3876 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3878 if (!ret) {
3879 /* we must build the full Path */
3880 *needed += dirlen;
3881 if ((out) && (outlen > dirlen)) {
3882 lstrcpyW((LPWSTR)out, driverdir);
3883 out += dirlen;
3884 outlen -= dirlen;
3886 else
3887 out = NULL;
3890 /* write the filename */
3891 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3892 if ((out) && (outlen >= size)) {
3893 lstrcpyW((LPWSTR)out, ptr);
3894 out += size;
3895 outlen -= size;
3897 else
3898 out = NULL;
3899 *needed += size;
3900 ptr += lstrlenW(ptr)+1;
3901 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3904 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3906 /* write the multisz-termination */
3907 if (type == REG_MULTI_SZ) {
3908 size = sizeof(WCHAR);
3910 *needed += size;
3911 if (out && (outlen >= size)) {
3912 memset (out, 0, size);
3915 return TRUE;
3918 /*****************************************************************************
3919 * WINSPOOL_GetStringFromReg
3921 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3922 * String is stored as unicode.
3924 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3925 DWORD buflen, DWORD *needed)
3927 DWORD sz = buflen, type;
3928 LONG ret;
3930 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3931 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3932 WARN("Got ret = %d\n", ret);
3933 *needed = 0;
3934 return FALSE;
3936 /* add space for terminating '\0' */
3937 sz += sizeof(WCHAR);
3938 *needed = sz;
3940 if (ptr)
3941 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3943 return TRUE;
3946 /*****************************************************************************
3947 * WINSPOOL_GetDefaultDevMode
3949 * Get a default DevMode values for wineps.
3950 * FIXME - use ppd.
3953 static void WINSPOOL_GetDefaultDevMode(
3954 LPBYTE ptr,
3955 DWORD buflen, DWORD *needed)
3957 DEVMODEW dm;
3958 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3960 /* fill default DEVMODE - should be read from ppd... */
3961 ZeroMemory( &dm, sizeof(dm) );
3962 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3963 dm.dmSpecVersion = DM_SPECVERSION;
3964 dm.dmDriverVersion = 1;
3965 dm.dmSize = sizeof(DEVMODEW);
3966 dm.dmDriverExtra = 0;
3967 dm.dmFields =
3968 DM_ORIENTATION | DM_PAPERSIZE |
3969 DM_PAPERLENGTH | DM_PAPERWIDTH |
3970 DM_SCALE |
3971 DM_COPIES |
3972 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3973 DM_YRESOLUTION | DM_TTOPTION;
3975 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3976 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3977 dm.u1.s1.dmPaperLength = 2970;
3978 dm.u1.s1.dmPaperWidth = 2100;
3980 dm.u1.s1.dmScale = 100;
3981 dm.u1.s1.dmCopies = 1;
3982 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3983 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3984 /* dm.dmColor */
3985 /* dm.dmDuplex */
3986 dm.dmYResolution = 300; /* 300dpi */
3987 dm.dmTTOption = DMTT_BITMAP;
3988 /* dm.dmCollate */
3989 /* dm.dmFormName */
3990 /* dm.dmLogPixels */
3991 /* dm.dmBitsPerPel */
3992 /* dm.dmPelsWidth */
3993 /* dm.dmPelsHeight */
3994 /* dm.u2.dmDisplayFlags */
3995 /* dm.dmDisplayFrequency */
3996 /* dm.dmICMMethod */
3997 /* dm.dmICMIntent */
3998 /* dm.dmMediaType */
3999 /* dm.dmDitherType */
4000 /* dm.dmReserved1 */
4001 /* dm.dmReserved2 */
4002 /* dm.dmPanningWidth */
4003 /* dm.dmPanningHeight */
4005 if(buflen >= sizeof(DEVMODEW))
4006 memcpy(ptr, &dm, sizeof(DEVMODEW));
4007 *needed = sizeof(DEVMODEW);
4010 /*****************************************************************************
4011 * WINSPOOL_GetDevModeFromReg
4013 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4014 * DevMode is stored either as unicode or ascii.
4016 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4017 LPBYTE ptr,
4018 DWORD buflen, DWORD *needed)
4020 DWORD sz = buflen, type;
4021 LONG ret;
4023 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4024 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4025 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4026 if (sz < sizeof(DEVMODEA))
4028 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4029 return FALSE;
4031 /* ensures that dmSize is not erratically bogus if registry is invalid */
4032 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4033 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4034 sz += (CCHDEVICENAME + CCHFORMNAME);
4035 if (ptr && (buflen >= sz)) {
4036 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4037 memcpy(ptr, dmW, sz);
4038 HeapFree(GetProcessHeap(),0,dmW);
4040 *needed = sz;
4041 return TRUE;
4044 /*********************************************************************
4045 * WINSPOOL_GetPrinter_1
4047 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4049 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4050 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4052 DWORD size, left = cbBuf;
4053 BOOL space = (cbBuf > 0);
4054 LPBYTE ptr = buf;
4056 *pcbNeeded = 0;
4058 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4059 if(space && size <= left) {
4060 pi1->pName = (LPWSTR)ptr;
4061 ptr += size;
4062 left -= size;
4063 } else
4064 space = FALSE;
4065 *pcbNeeded += size;
4068 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4069 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4070 if(space && size <= left) {
4071 pi1->pDescription = (LPWSTR)ptr;
4072 ptr += size;
4073 left -= size;
4074 } else
4075 space = FALSE;
4076 *pcbNeeded += size;
4079 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4080 if(space && size <= left) {
4081 pi1->pComment = (LPWSTR)ptr;
4082 ptr += size;
4083 left -= size;
4084 } else
4085 space = FALSE;
4086 *pcbNeeded += size;
4089 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4091 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4092 memset(pi1, 0, sizeof(*pi1));
4094 return space;
4096 /*********************************************************************
4097 * WINSPOOL_GetPrinter_2
4099 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4101 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4102 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4104 DWORD size, left = cbBuf;
4105 BOOL space = (cbBuf > 0);
4106 LPBYTE ptr = buf;
4108 *pcbNeeded = 0;
4110 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4111 if(space && size <= left) {
4112 pi2->pPrinterName = (LPWSTR)ptr;
4113 ptr += size;
4114 left -= size;
4115 } else
4116 space = FALSE;
4117 *pcbNeeded += size;
4119 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4120 if(space && size <= left) {
4121 pi2->pShareName = (LPWSTR)ptr;
4122 ptr += size;
4123 left -= size;
4124 } else
4125 space = FALSE;
4126 *pcbNeeded += size;
4128 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4129 if(space && size <= left) {
4130 pi2->pPortName = (LPWSTR)ptr;
4131 ptr += size;
4132 left -= size;
4133 } else
4134 space = FALSE;
4135 *pcbNeeded += size;
4137 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4138 if(space && size <= left) {
4139 pi2->pDriverName = (LPWSTR)ptr;
4140 ptr += size;
4141 left -= size;
4142 } else
4143 space = FALSE;
4144 *pcbNeeded += size;
4146 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4147 if(space && size <= left) {
4148 pi2->pComment = (LPWSTR)ptr;
4149 ptr += size;
4150 left -= size;
4151 } else
4152 space = FALSE;
4153 *pcbNeeded += size;
4155 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4156 if(space && size <= left) {
4157 pi2->pLocation = (LPWSTR)ptr;
4158 ptr += size;
4159 left -= size;
4160 } else
4161 space = FALSE;
4162 *pcbNeeded += size;
4164 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4165 if(space && size <= left) {
4166 pi2->pDevMode = (LPDEVMODEW)ptr;
4167 ptr += size;
4168 left -= size;
4169 } else
4170 space = FALSE;
4171 *pcbNeeded += size;
4173 else
4175 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4176 if(space && size <= left) {
4177 pi2->pDevMode = (LPDEVMODEW)ptr;
4178 ptr += size;
4179 left -= size;
4180 } else
4181 space = FALSE;
4182 *pcbNeeded += size;
4184 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4185 if(space && size <= left) {
4186 pi2->pSepFile = (LPWSTR)ptr;
4187 ptr += size;
4188 left -= size;
4189 } else
4190 space = FALSE;
4191 *pcbNeeded += size;
4193 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4194 if(space && size <= left) {
4195 pi2->pPrintProcessor = (LPWSTR)ptr;
4196 ptr += size;
4197 left -= size;
4198 } else
4199 space = FALSE;
4200 *pcbNeeded += size;
4202 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4203 if(space && size <= left) {
4204 pi2->pDatatype = (LPWSTR)ptr;
4205 ptr += size;
4206 left -= size;
4207 } else
4208 space = FALSE;
4209 *pcbNeeded += size;
4211 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4212 if(space && size <= left) {
4213 pi2->pParameters = (LPWSTR)ptr;
4214 ptr += size;
4215 left -= size;
4216 } else
4217 space = FALSE;
4218 *pcbNeeded += size;
4220 if(pi2) {
4221 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4222 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4223 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4224 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4225 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4228 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4229 memset(pi2, 0, sizeof(*pi2));
4231 return space;
4234 /*********************************************************************
4235 * WINSPOOL_GetPrinter_4
4237 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4239 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4240 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4242 DWORD size, left = cbBuf;
4243 BOOL space = (cbBuf > 0);
4244 LPBYTE ptr = buf;
4246 *pcbNeeded = 0;
4248 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4249 if(space && size <= left) {
4250 pi4->pPrinterName = (LPWSTR)ptr;
4251 ptr += size;
4252 left -= size;
4253 } else
4254 space = FALSE;
4255 *pcbNeeded += size;
4257 if(pi4) {
4258 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4261 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4262 memset(pi4, 0, sizeof(*pi4));
4264 return space;
4267 /*********************************************************************
4268 * WINSPOOL_GetPrinter_5
4270 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4272 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4273 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4275 DWORD size, left = cbBuf;
4276 BOOL space = (cbBuf > 0);
4277 LPBYTE ptr = buf;
4279 *pcbNeeded = 0;
4281 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4282 if(space && size <= left) {
4283 pi5->pPrinterName = (LPWSTR)ptr;
4284 ptr += size;
4285 left -= size;
4286 } else
4287 space = FALSE;
4288 *pcbNeeded += size;
4290 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4291 if(space && size <= left) {
4292 pi5->pPortName = (LPWSTR)ptr;
4293 ptr += size;
4294 left -= size;
4295 } else
4296 space = FALSE;
4297 *pcbNeeded += size;
4299 if(pi5) {
4300 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4301 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4302 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4305 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4306 memset(pi5, 0, sizeof(*pi5));
4308 return space;
4311 /*********************************************************************
4312 * WINSPOOL_GetPrinter_7
4314 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4316 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4317 DWORD cbBuf, LPDWORD pcbNeeded)
4319 DWORD size, left = cbBuf;
4320 BOOL space = (cbBuf > 0);
4321 LPBYTE ptr = buf;
4323 *pcbNeeded = 0;
4325 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4327 ptr = NULL;
4328 size = sizeof(pi7->pszObjectGUID);
4330 if (space && size <= left) {
4331 pi7->pszObjectGUID = (LPWSTR)ptr;
4332 ptr += size;
4333 left -= size;
4334 } else
4335 space = FALSE;
4336 *pcbNeeded += size;
4337 if (pi7) {
4338 /* We do not have a Directory Service */
4339 pi7->dwAction = DSPRINT_UNPUBLISH;
4342 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4343 memset(pi7, 0, sizeof(*pi7));
4345 return space;
4348 /*********************************************************************
4349 * WINSPOOL_GetPrinter_9
4351 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4353 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4354 DWORD cbBuf, LPDWORD pcbNeeded)
4356 DWORD size;
4357 BOOL space = (cbBuf > 0);
4359 *pcbNeeded = 0;
4361 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4362 if(space && size <= cbBuf) {
4363 pi9->pDevMode = (LPDEVMODEW)buf;
4364 } else
4365 space = FALSE;
4366 *pcbNeeded += size;
4368 else
4370 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4371 if(space && size <= cbBuf) {
4372 pi9->pDevMode = (LPDEVMODEW)buf;
4373 } else
4374 space = FALSE;
4375 *pcbNeeded += size;
4378 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4379 memset(pi9, 0, sizeof(*pi9));
4381 return space;
4384 /*****************************************************************************
4385 * GetPrinterW [WINSPOOL.@]
4387 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4388 DWORD cbBuf, LPDWORD pcbNeeded)
4390 DWORD size, needed = 0, err;
4391 LPBYTE ptr = NULL;
4392 HKEY hkeyPrinter;
4393 BOOL ret;
4395 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4397 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4398 if (err)
4400 SetLastError( err );
4401 return FALSE;
4404 switch(Level) {
4405 case 2:
4407 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4409 size = sizeof(PRINTER_INFO_2W);
4410 if(size <= cbBuf) {
4411 ptr = pPrinter + size;
4412 cbBuf -= size;
4413 memset(pPrinter, 0, size);
4414 } else {
4415 pi2 = NULL;
4416 cbBuf = 0;
4418 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4419 needed += size;
4420 break;
4423 case 4:
4425 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4427 size = sizeof(PRINTER_INFO_4W);
4428 if(size <= cbBuf) {
4429 ptr = pPrinter + size;
4430 cbBuf -= size;
4431 memset(pPrinter, 0, size);
4432 } else {
4433 pi4 = NULL;
4434 cbBuf = 0;
4436 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4437 needed += size;
4438 break;
4442 case 5:
4444 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4446 size = sizeof(PRINTER_INFO_5W);
4447 if(size <= cbBuf) {
4448 ptr = pPrinter + size;
4449 cbBuf -= size;
4450 memset(pPrinter, 0, size);
4451 } else {
4452 pi5 = NULL;
4453 cbBuf = 0;
4456 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4457 needed += size;
4458 break;
4462 case 6:
4464 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4466 size = sizeof(PRINTER_INFO_6);
4467 if (size <= cbBuf) {
4468 /* FIXME: We do not update the status yet */
4469 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4470 ret = TRUE;
4471 } else {
4472 ret = FALSE;
4475 needed += size;
4476 break;
4479 case 7:
4481 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4483 size = sizeof(PRINTER_INFO_7W);
4484 if (size <= cbBuf) {
4485 ptr = pPrinter + size;
4486 cbBuf -= size;
4487 memset(pPrinter, 0, size);
4488 } else {
4489 pi7 = NULL;
4490 cbBuf = 0;
4493 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4494 needed += size;
4495 break;
4499 case 8:
4500 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4501 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4502 /* fall through */
4503 case 9:
4505 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4507 size = sizeof(PRINTER_INFO_9W);
4508 if(size <= cbBuf) {
4509 ptr = pPrinter + size;
4510 cbBuf -= size;
4511 memset(pPrinter, 0, size);
4512 } else {
4513 pi9 = NULL;
4514 cbBuf = 0;
4517 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4518 needed += size;
4519 break;
4523 default:
4524 FIXME("Unimplemented level %d\n", Level);
4525 SetLastError(ERROR_INVALID_LEVEL);
4526 RegCloseKey(hkeyPrinter);
4527 return FALSE;
4530 RegCloseKey(hkeyPrinter);
4532 TRACE("returning %d needed = %d\n", ret, needed);
4533 if(pcbNeeded) *pcbNeeded = needed;
4534 if(!ret)
4535 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4536 return ret;
4539 /*****************************************************************************
4540 * GetPrinterA [WINSPOOL.@]
4542 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4543 DWORD cbBuf, LPDWORD pcbNeeded)
4545 BOOL ret;
4546 LPBYTE buf = NULL;
4548 if (cbBuf)
4549 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4551 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4552 if (ret)
4553 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4554 HeapFree(GetProcessHeap(), 0, buf);
4556 return ret;
4559 /*****************************************************************************
4560 * WINSPOOL_EnumPrintersW
4562 * Implementation of EnumPrintersW
4564 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4565 DWORD dwLevel, LPBYTE lpbPrinters,
4566 DWORD cbBuf, LPDWORD lpdwNeeded,
4567 LPDWORD lpdwReturned)
4570 HKEY hkeyPrinters, hkeyPrinter;
4571 WCHAR PrinterName[255];
4572 DWORD needed = 0, number = 0;
4573 DWORD used, i, left;
4574 PBYTE pi, buf;
4576 if(lpbPrinters)
4577 memset(lpbPrinters, 0, cbBuf);
4578 if(lpdwReturned)
4579 *lpdwReturned = 0;
4580 if(lpdwNeeded)
4581 *lpdwNeeded = 0;
4583 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4584 if(dwType == PRINTER_ENUM_DEFAULT)
4585 return TRUE;
4587 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4588 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4589 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4590 if (!dwType) {
4591 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4592 return TRUE;
4597 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4598 FIXME("dwType = %08x\n", dwType);
4599 SetLastError(ERROR_INVALID_FLAGS);
4600 return FALSE;
4603 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4604 ERROR_SUCCESS) {
4605 ERR("Can't create Printers key\n");
4606 return FALSE;
4609 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4610 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4611 RegCloseKey(hkeyPrinters);
4612 ERR("Can't query Printers key\n");
4613 return FALSE;
4615 TRACE("Found %d printers\n", number);
4617 switch(dwLevel) {
4618 case 1:
4619 used = number * sizeof(PRINTER_INFO_1W);
4620 break;
4621 case 2:
4622 used = number * sizeof(PRINTER_INFO_2W);
4623 break;
4624 case 4:
4625 used = number * sizeof(PRINTER_INFO_4W);
4626 break;
4627 case 5:
4628 used = number * sizeof(PRINTER_INFO_5W);
4629 break;
4631 default:
4632 SetLastError(ERROR_INVALID_LEVEL);
4633 RegCloseKey(hkeyPrinters);
4634 return FALSE;
4636 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4638 for(i = 0; i < number; i++) {
4639 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4640 ERROR_SUCCESS) {
4641 ERR("Can't enum key number %d\n", i);
4642 RegCloseKey(hkeyPrinters);
4643 return FALSE;
4645 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4646 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4647 ERROR_SUCCESS) {
4648 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4649 RegCloseKey(hkeyPrinters);
4650 return FALSE;
4653 if(cbBuf > used) {
4654 buf = lpbPrinters + used;
4655 left = cbBuf - used;
4656 } else {
4657 buf = NULL;
4658 left = 0;
4661 switch(dwLevel) {
4662 case 1:
4663 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4664 left, &needed);
4665 used += needed;
4666 if(pi) pi += sizeof(PRINTER_INFO_1W);
4667 break;
4668 case 2:
4669 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4670 left, &needed);
4671 used += needed;
4672 if(pi) pi += sizeof(PRINTER_INFO_2W);
4673 break;
4674 case 4:
4675 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4676 left, &needed);
4677 used += needed;
4678 if(pi) pi += sizeof(PRINTER_INFO_4W);
4679 break;
4680 case 5:
4681 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4682 left, &needed);
4683 used += needed;
4684 if(pi) pi += sizeof(PRINTER_INFO_5W);
4685 break;
4686 default:
4687 ERR("Shouldn't be here!\n");
4688 RegCloseKey(hkeyPrinter);
4689 RegCloseKey(hkeyPrinters);
4690 return FALSE;
4692 RegCloseKey(hkeyPrinter);
4694 RegCloseKey(hkeyPrinters);
4696 if(lpdwNeeded)
4697 *lpdwNeeded = used;
4699 if(used > cbBuf) {
4700 if(lpbPrinters)
4701 memset(lpbPrinters, 0, cbBuf);
4702 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4703 return FALSE;
4705 if(lpdwReturned)
4706 *lpdwReturned = number;
4707 SetLastError(ERROR_SUCCESS);
4708 return TRUE;
4712 /******************************************************************
4713 * EnumPrintersW [WINSPOOL.@]
4715 * Enumerates the available printers, print servers and print
4716 * providers, depending on the specified flags, name and level.
4718 * RETURNS:
4720 * If level is set to 1:
4721 * Returns an array of PRINTER_INFO_1 data structures in the
4722 * lpbPrinters buffer.
4724 * If level is set to 2:
4725 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4726 * Returns an array of PRINTER_INFO_2 data structures in the
4727 * lpbPrinters buffer. Note that according to MSDN also an
4728 * OpenPrinter should be performed on every remote printer.
4730 * If level is set to 4 (officially WinNT only):
4731 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4732 * Fast: Only the registry is queried to retrieve printer names,
4733 * no connection to the driver is made.
4734 * Returns an array of PRINTER_INFO_4 data structures in the
4735 * lpbPrinters buffer.
4737 * If level is set to 5 (officially WinNT4/Win9x only):
4738 * Fast: Only the registry is queried to retrieve printer names,
4739 * no connection to the driver is made.
4740 * Returns an array of PRINTER_INFO_5 data structures in the
4741 * lpbPrinters buffer.
4743 * If level set to 3 or 6+:
4744 * returns zero (failure!)
4746 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4747 * for information.
4749 * BUGS:
4750 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4751 * - Only levels 2, 4 and 5 are implemented at the moment.
4752 * - 16-bit printer drivers are not enumerated.
4753 * - Returned amount of bytes used/needed does not match the real Windoze
4754 * implementation (as in this implementation, all strings are part
4755 * of the buffer, whereas Win32 keeps them somewhere else)
4756 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4758 * NOTE:
4759 * - In a regular Wine installation, no registry settings for printers
4760 * exist, which makes this function return an empty list.
4762 BOOL WINAPI EnumPrintersW(
4763 DWORD dwType, /* [in] Types of print objects to enumerate */
4764 LPWSTR lpszName, /* [in] name of objects to enumerate */
4765 DWORD dwLevel, /* [in] type of printer info structure */
4766 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4767 DWORD cbBuf, /* [in] max size of buffer in bytes */
4768 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4769 LPDWORD lpdwReturned /* [out] number of entries returned */
4772 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4773 lpdwNeeded, lpdwReturned);
4776 /******************************************************************
4777 * EnumPrintersA [WINSPOOL.@]
4779 * See EnumPrintersW
4782 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4783 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4785 BOOL ret;
4786 UNICODE_STRING pNameU;
4787 LPWSTR pNameW;
4788 LPBYTE pPrintersW;
4790 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4791 pPrinters, cbBuf, pcbNeeded, pcReturned);
4793 pNameW = asciitounicode(&pNameU, pName);
4795 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4796 MS Office need this */
4797 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4799 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4801 RtlFreeUnicodeString(&pNameU);
4802 if (ret) {
4803 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4805 HeapFree(GetProcessHeap(), 0, pPrintersW);
4806 return ret;
4809 /*****************************************************************************
4810 * WINSPOOL_GetDriverInfoFromReg [internal]
4812 * Enters the information from the registry into the DRIVER_INFO struct
4814 * RETURNS
4815 * zero if the printer driver does not exist in the registry
4816 * (only if Level > 1) otherwise nonzero
4818 static BOOL WINSPOOL_GetDriverInfoFromReg(
4819 HKEY hkeyDrivers,
4820 LPWSTR DriverName,
4821 const printenv_t * env,
4822 DWORD Level,
4823 LPBYTE ptr, /* DRIVER_INFO */
4824 LPBYTE pDriverStrings, /* strings buffer */
4825 DWORD cbBuf, /* size of string buffer */
4826 LPDWORD pcbNeeded) /* space needed for str. */
4828 DWORD size, tmp;
4829 HKEY hkeyDriver;
4830 WCHAR driverdir[MAX_PATH];
4831 DWORD dirlen;
4832 LPBYTE strPtr = pDriverStrings;
4833 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4835 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4836 debugstr_w(DriverName), env,
4837 Level, di, pDriverStrings, cbBuf);
4839 if (di) ZeroMemory(di, di_sizeof[Level]);
4841 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4842 if (*pcbNeeded <= cbBuf)
4843 strcpyW((LPWSTR)strPtr, DriverName);
4845 /* pName for level 1 has a different offset! */
4846 if (Level == 1) {
4847 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4848 return TRUE;
4851 /* .cVersion and .pName for level > 1 */
4852 if (di) {
4853 di->cVersion = env->driverversion;
4854 di->pName = (LPWSTR) strPtr;
4855 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4858 /* Reserve Space for the largest subdir and a Backslash*/
4859 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4860 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4861 /* Should never Fail */
4862 return FALSE;
4864 lstrcatW(driverdir, env->versionsubdir);
4865 lstrcatW(driverdir, backslashW);
4867 /* dirlen must not include the terminating zero */
4868 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4870 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4871 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4872 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4873 return FALSE;
4876 /* pEnvironment */
4877 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4879 *pcbNeeded += size;
4880 if (*pcbNeeded <= cbBuf) {
4881 lstrcpyW((LPWSTR)strPtr, env->envname);
4882 if (di) di->pEnvironment = (LPWSTR)strPtr;
4883 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4886 /* .pDriverPath is the Graphics rendering engine.
4887 The full Path is required to avoid a crash in some apps */
4888 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4889 *pcbNeeded += size;
4890 if (*pcbNeeded <= cbBuf)
4891 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4893 if (di) di->pDriverPath = (LPWSTR)strPtr;
4894 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4897 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4898 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4899 *pcbNeeded += size;
4900 if (*pcbNeeded <= cbBuf)
4901 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4903 if (di) di->pDataFile = (LPWSTR)strPtr;
4904 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4907 /* .pConfigFile is the Driver user Interface */
4908 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4909 *pcbNeeded += size;
4910 if (*pcbNeeded <= cbBuf)
4911 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4913 if (di) di->pConfigFile = (LPWSTR)strPtr;
4914 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4917 if (Level == 2 ) {
4918 RegCloseKey(hkeyDriver);
4919 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4920 return TRUE;
4923 if (Level == 5 ) {
4924 RegCloseKey(hkeyDriver);
4925 FIXME("level 5: incomplete\n");
4926 return TRUE;
4929 /* .pHelpFile */
4930 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4931 *pcbNeeded += size;
4932 if (*pcbNeeded <= cbBuf)
4933 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4935 if (di) di->pHelpFile = (LPWSTR)strPtr;
4936 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4939 /* .pDependentFiles */
4940 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4941 *pcbNeeded += size;
4942 if (*pcbNeeded <= cbBuf)
4943 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4945 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4946 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4948 else if (GetVersion() & 0x80000000) {
4949 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4950 size = 2 * sizeof(WCHAR);
4951 *pcbNeeded += size;
4952 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4954 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4955 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4958 /* .pMonitorName is the optional Language Monitor */
4959 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4960 *pcbNeeded += size;
4961 if (*pcbNeeded <= cbBuf)
4962 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4964 if (di) di->pMonitorName = (LPWSTR)strPtr;
4965 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4968 /* .pDefaultDataType */
4969 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4970 *pcbNeeded += size;
4971 if(*pcbNeeded <= cbBuf)
4972 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4974 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4975 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4978 if (Level == 3 ) {
4979 RegCloseKey(hkeyDriver);
4980 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4981 return TRUE;
4984 /* .pszzPreviousNames */
4985 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4986 *pcbNeeded += size;
4987 if(*pcbNeeded <= cbBuf)
4988 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4990 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4991 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4994 if (Level == 4 ) {
4995 RegCloseKey(hkeyDriver);
4996 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4997 return TRUE;
5000 /* support is missing, but not important enough for a FIXME */
5001 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5003 /* .pszMfgName */
5004 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5005 *pcbNeeded += size;
5006 if(*pcbNeeded <= cbBuf)
5007 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5009 if (di) di->pszMfgName = (LPWSTR)strPtr;
5010 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5013 /* .pszOEMUrl */
5014 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5015 *pcbNeeded += size;
5016 if(*pcbNeeded <= cbBuf)
5017 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5019 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5020 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5023 /* .pszHardwareID */
5024 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5025 *pcbNeeded += size;
5026 if(*pcbNeeded <= cbBuf)
5027 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5029 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5030 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5033 /* .pszProvider */
5034 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5035 *pcbNeeded += size;
5036 if(*pcbNeeded <= cbBuf)
5037 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5039 if (di) di->pszProvider = (LPWSTR)strPtr;
5040 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5043 if (Level == 6 ) {
5044 RegCloseKey(hkeyDriver);
5045 return TRUE;
5048 /* support is missing, but not important enough for a FIXME */
5049 TRACE("level 8: incomplete\n");
5051 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5052 RegCloseKey(hkeyDriver);
5053 return TRUE;
5056 /*****************************************************************************
5057 * GetPrinterDriverW [WINSPOOL.@]
5059 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5060 DWORD Level, LPBYTE pDriverInfo,
5061 DWORD cbBuf, LPDWORD pcbNeeded)
5063 LPCWSTR name;
5064 WCHAR DriverName[100];
5065 DWORD ret, type, size, needed = 0;
5066 LPBYTE ptr = NULL;
5067 HKEY hkeyPrinter, hkeyDrivers;
5068 const printenv_t * env;
5070 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5071 Level,pDriverInfo,cbBuf, pcbNeeded);
5073 if (cbBuf > 0)
5074 ZeroMemory(pDriverInfo, cbBuf);
5076 if (!(name = get_opened_printer_name(hPrinter))) {
5077 SetLastError(ERROR_INVALID_HANDLE);
5078 return FALSE;
5081 if (Level < 1 || Level == 7 || Level > 8) {
5082 SetLastError(ERROR_INVALID_LEVEL);
5083 return FALSE;
5086 env = validate_envW(pEnvironment);
5087 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5089 ret = open_printer_reg_key( name, &hkeyPrinter );
5090 if (ret)
5092 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5093 SetLastError( ret );
5094 return FALSE;
5097 size = sizeof(DriverName);
5098 DriverName[0] = 0;
5099 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5100 (LPBYTE)DriverName, &size);
5101 RegCloseKey(hkeyPrinter);
5102 if(ret != ERROR_SUCCESS) {
5103 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5104 return FALSE;
5107 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5108 if(!hkeyDrivers) {
5109 ERR("Can't create Drivers key\n");
5110 return FALSE;
5113 size = di_sizeof[Level];
5114 if ((size <= cbBuf) && pDriverInfo)
5115 ptr = pDriverInfo + size;
5117 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5118 env, Level, pDriverInfo, ptr,
5119 (cbBuf < size) ? 0 : cbBuf - size,
5120 &needed)) {
5121 RegCloseKey(hkeyDrivers);
5122 return FALSE;
5125 RegCloseKey(hkeyDrivers);
5127 if(pcbNeeded) *pcbNeeded = size + needed;
5128 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5129 if(cbBuf >= size + needed) return TRUE;
5130 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5131 return FALSE;
5134 /*****************************************************************************
5135 * GetPrinterDriverA [WINSPOOL.@]
5137 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5138 DWORD Level, LPBYTE pDriverInfo,
5139 DWORD cbBuf, LPDWORD pcbNeeded)
5141 BOOL ret;
5142 UNICODE_STRING pEnvW;
5143 PWSTR pwstrEnvW;
5144 LPBYTE buf = NULL;
5146 if (cbBuf)
5148 ZeroMemory(pDriverInfo, cbBuf);
5149 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5152 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5153 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5154 cbBuf, pcbNeeded);
5155 if (ret)
5156 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5158 HeapFree(GetProcessHeap(), 0, buf);
5160 RtlFreeUnicodeString(&pEnvW);
5161 return ret;
5164 /*****************************************************************************
5165 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5167 * Return the PATH for the Printer-Drivers (UNICODE)
5169 * PARAMS
5170 * pName [I] Servername (NT only) or NULL (local Computer)
5171 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5172 * Level [I] Structure-Level (must be 1)
5173 * pDriverDirectory [O] PTR to Buffer that receives the Result
5174 * cbBuf [I] Size of Buffer at pDriverDirectory
5175 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5176 * required for pDriverDirectory
5178 * RETURNS
5179 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5180 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5181 * if cbBuf is too small
5183 * Native Values returned in pDriverDirectory on Success:
5184 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5185 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5186 *| win9x(Windows 4.0): "%winsysdir%"
5188 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5190 * FIXME
5191 *- Only NULL or "" is supported for pName
5194 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5195 DWORD Level, LPBYTE pDriverDirectory,
5196 DWORD cbBuf, LPDWORD pcbNeeded)
5198 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5199 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5201 if ((backend == NULL) && !load_backend()) return FALSE;
5203 if (Level != 1) {
5204 /* (Level != 1) is ignored in win9x */
5205 SetLastError(ERROR_INVALID_LEVEL);
5206 return FALSE;
5208 if (pcbNeeded == NULL) {
5209 /* (pcbNeeded == NULL) is ignored in win9x */
5210 SetLastError(RPC_X_NULL_REF_POINTER);
5211 return FALSE;
5214 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5215 pDriverDirectory, cbBuf, pcbNeeded);
5220 /*****************************************************************************
5221 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5223 * Return the PATH for the Printer-Drivers (ANSI)
5225 * See GetPrinterDriverDirectoryW.
5227 * NOTES
5228 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5231 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5232 DWORD Level, LPBYTE pDriverDirectory,
5233 DWORD cbBuf, LPDWORD pcbNeeded)
5235 UNICODE_STRING nameW, environmentW;
5236 BOOL ret;
5237 DWORD pcbNeededW;
5238 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5239 WCHAR *driverDirectoryW = NULL;
5241 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5242 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5244 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5246 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5247 else nameW.Buffer = NULL;
5248 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5249 else environmentW.Buffer = NULL;
5251 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5252 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5253 if (ret) {
5254 DWORD needed;
5255 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5256 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5257 if(pcbNeeded)
5258 *pcbNeeded = needed;
5259 ret = (needed <= cbBuf) ? TRUE : FALSE;
5260 } else
5261 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5263 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5265 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5266 RtlFreeUnicodeString(&environmentW);
5267 RtlFreeUnicodeString(&nameW);
5269 return ret;
5272 /*****************************************************************************
5273 * AddPrinterDriverA [WINSPOOL.@]
5275 * See AddPrinterDriverW.
5278 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5280 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5281 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5284 /******************************************************************************
5285 * AddPrinterDriverW (WINSPOOL.@)
5287 * Install a Printer Driver
5289 * PARAMS
5290 * pName [I] Servername or NULL (local Computer)
5291 * level [I] Level for the supplied DRIVER_INFO_*W struct
5292 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5294 * RESULTS
5295 * Success: TRUE
5296 * Failure: FALSE
5299 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5301 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5302 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5305 /*****************************************************************************
5306 * AddPrintProcessorA [WINSPOOL.@]
5308 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5309 LPSTR pPrintProcessorName)
5311 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5312 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5313 return FALSE;
5316 /*****************************************************************************
5317 * AddPrintProcessorW [WINSPOOL.@]
5319 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5320 LPWSTR pPrintProcessorName)
5322 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5323 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5324 return TRUE;
5327 /*****************************************************************************
5328 * AddPrintProvidorA [WINSPOOL.@]
5330 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5332 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5333 return FALSE;
5336 /*****************************************************************************
5337 * AddPrintProvidorW [WINSPOOL.@]
5339 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5341 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5342 return FALSE;
5345 /*****************************************************************************
5346 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5348 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5349 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5351 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5352 pDevModeOutput, pDevModeInput);
5353 return 0;
5356 /*****************************************************************************
5357 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5359 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5360 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5362 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5363 pDevModeOutput, pDevModeInput);
5364 return 0;
5367 /*****************************************************************************
5368 * PrinterProperties [WINSPOOL.@]
5370 * Displays a dialog to set the properties of the printer.
5372 * RETURNS
5373 * nonzero on success or zero on failure
5375 * BUGS
5376 * implemented as stub only
5378 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5379 HANDLE hPrinter /* [in] handle to printer object */
5381 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5382 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5383 return FALSE;
5386 /*****************************************************************************
5387 * EnumJobsA [WINSPOOL.@]
5390 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5391 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5392 LPDWORD pcReturned)
5394 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5395 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5397 if(pcbNeeded) *pcbNeeded = 0;
5398 if(pcReturned) *pcReturned = 0;
5399 return FALSE;
5403 /*****************************************************************************
5404 * EnumJobsW [WINSPOOL.@]
5407 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5408 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5409 LPDWORD pcReturned)
5411 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5412 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5414 if(pcbNeeded) *pcbNeeded = 0;
5415 if(pcReturned) *pcReturned = 0;
5416 return FALSE;
5419 /*****************************************************************************
5420 * WINSPOOL_EnumPrinterDrivers [internal]
5422 * Delivers information about all printer drivers installed on the
5423 * localhost or a given server
5425 * RETURNS
5426 * nonzero on success or zero on failure. If the buffer for the returned
5427 * information is too small the function will return an error
5429 * BUGS
5430 * - only implemented for localhost, foreign hosts will return an error
5432 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5433 DWORD Level, LPBYTE pDriverInfo,
5434 DWORD driver_index,
5435 DWORD cbBuf, LPDWORD pcbNeeded,
5436 LPDWORD pcFound, DWORD data_offset)
5438 { HKEY hkeyDrivers;
5439 DWORD i, size = 0;
5440 const printenv_t * env;
5442 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5443 debugstr_w(pName), debugstr_w(pEnvironment),
5444 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5446 env = validate_envW(pEnvironment);
5447 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5449 *pcFound = 0;
5451 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5452 if(!hkeyDrivers) {
5453 ERR("Can't open Drivers key\n");
5454 return FALSE;
5457 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5458 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5459 RegCloseKey(hkeyDrivers);
5460 ERR("Can't query Drivers key\n");
5461 return FALSE;
5463 TRACE("Found %d Drivers\n", *pcFound);
5465 /* get size of single struct
5466 * unicode and ascii structure have the same size
5468 size = di_sizeof[Level];
5470 if (data_offset == 0)
5471 data_offset = size * (*pcFound);
5472 *pcbNeeded = data_offset;
5474 for( i = 0; i < *pcFound; i++) {
5475 WCHAR DriverNameW[255];
5476 PBYTE table_ptr = NULL;
5477 PBYTE data_ptr = NULL;
5478 DWORD needed = 0;
5480 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5481 != ERROR_SUCCESS) {
5482 ERR("Can't enum key number %d\n", i);
5483 RegCloseKey(hkeyDrivers);
5484 return FALSE;
5487 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5488 table_ptr = pDriverInfo + (driver_index + i) * size;
5489 if (pDriverInfo && *pcbNeeded <= cbBuf)
5490 data_ptr = pDriverInfo + *pcbNeeded;
5492 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5493 env, Level, table_ptr, data_ptr,
5494 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5495 &needed)) {
5496 RegCloseKey(hkeyDrivers);
5497 return FALSE;
5500 *pcbNeeded += needed;
5503 RegCloseKey(hkeyDrivers);
5505 if(cbBuf < *pcbNeeded){
5506 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5507 return FALSE;
5510 return TRUE;
5513 /*****************************************************************************
5514 * EnumPrinterDriversW [WINSPOOL.@]
5516 * see function EnumPrinterDrivers for RETURNS, BUGS
5518 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5519 LPBYTE pDriverInfo, DWORD cbBuf,
5520 LPDWORD pcbNeeded, LPDWORD pcReturned)
5522 static const WCHAR allW[] = {'a','l','l',0};
5523 BOOL ret;
5524 DWORD found;
5526 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5528 SetLastError(RPC_X_NULL_REF_POINTER);
5529 return FALSE;
5532 /* check for local drivers */
5533 if((pName) && (pName[0])) {
5534 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5535 SetLastError(ERROR_ACCESS_DENIED);
5536 return FALSE;
5539 /* check input parameter */
5540 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5541 SetLastError(ERROR_INVALID_LEVEL);
5542 return FALSE;
5545 if(pDriverInfo && cbBuf > 0)
5546 memset( pDriverInfo, 0, cbBuf);
5548 /* Exception: pull all printers */
5549 if (pEnvironment && !strcmpW(pEnvironment, allW))
5551 DWORD i, needed, bufsize = cbBuf;
5552 DWORD total_needed = 0;
5553 DWORD total_found = 0;
5554 DWORD data_offset;
5556 /* Precompute the overall total; we need this to know
5557 where pointers end and data begins (i.e. data_offset) */
5558 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5560 needed = found = 0;
5561 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5562 NULL, 0, 0, &needed, &found, 0);
5563 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5564 total_needed += needed;
5565 total_found += found;
5568 data_offset = di_sizeof[Level] * total_found;
5570 *pcReturned = 0;
5571 *pcbNeeded = 0;
5572 total_found = 0;
5573 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5575 needed = found = 0;
5576 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5577 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5578 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5579 else if (ret)
5580 *pcReturned += found;
5581 *pcbNeeded = needed;
5582 data_offset = needed;
5583 total_found += found;
5585 return ret;
5588 /* Normal behavior */
5589 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5590 0, cbBuf, pcbNeeded, &found, 0);
5591 if (ret)
5592 *pcReturned = found;
5594 return ret;
5597 /*****************************************************************************
5598 * EnumPrinterDriversA [WINSPOOL.@]
5600 * see function EnumPrinterDrivers for RETURNS, BUGS
5602 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5603 LPBYTE pDriverInfo, DWORD cbBuf,
5604 LPDWORD pcbNeeded, LPDWORD pcReturned)
5606 BOOL ret;
5607 UNICODE_STRING pNameW, pEnvironmentW;
5608 PWSTR pwstrNameW, pwstrEnvironmentW;
5609 LPBYTE buf = NULL;
5611 if (cbBuf)
5612 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5614 pwstrNameW = asciitounicode(&pNameW, pName);
5615 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5617 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5618 buf, cbBuf, pcbNeeded, pcReturned);
5619 if (ret)
5620 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5622 HeapFree(GetProcessHeap(), 0, buf);
5624 RtlFreeUnicodeString(&pNameW);
5625 RtlFreeUnicodeString(&pEnvironmentW);
5627 return ret;
5630 /******************************************************************************
5631 * EnumPortsA (WINSPOOL.@)
5633 * See EnumPortsW.
5636 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5637 LPDWORD pcbNeeded, LPDWORD pcReturned)
5639 BOOL res;
5640 LPBYTE bufferW = NULL;
5641 LPWSTR nameW = NULL;
5642 DWORD needed = 0;
5643 DWORD numentries = 0;
5644 INT len;
5646 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5647 cbBuf, pcbNeeded, pcReturned);
5649 /* convert servername to unicode */
5650 if (pName) {
5651 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5652 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5653 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5655 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5656 needed = cbBuf * sizeof(WCHAR);
5657 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5658 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5660 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5661 if (pcbNeeded) needed = *pcbNeeded;
5662 /* HeapReAlloc return NULL, when bufferW was NULL */
5663 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5664 HeapAlloc(GetProcessHeap(), 0, needed);
5666 /* Try again with the large Buffer */
5667 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5669 needed = pcbNeeded ? *pcbNeeded : 0;
5670 numentries = pcReturned ? *pcReturned : 0;
5673 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5674 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5676 if (res) {
5677 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5678 DWORD entrysize = 0;
5679 DWORD index;
5680 LPSTR ptr;
5681 LPPORT_INFO_2W pi2w;
5682 LPPORT_INFO_2A pi2a;
5684 needed = 0;
5685 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5687 /* First pass: calculate the size for all Entries */
5688 pi2w = (LPPORT_INFO_2W) bufferW;
5689 pi2a = (LPPORT_INFO_2A) pPorts;
5690 index = 0;
5691 while (index < numentries) {
5692 index++;
5693 needed += entrysize; /* PORT_INFO_?A */
5694 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5696 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5697 NULL, 0, NULL, NULL);
5698 if (Level > 1) {
5699 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5700 NULL, 0, NULL, NULL);
5701 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5702 NULL, 0, NULL, NULL);
5704 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5705 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5706 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5709 /* check for errors and quit on failure */
5710 if (cbBuf < needed) {
5711 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5712 res = FALSE;
5713 goto cleanup;
5715 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5716 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5717 cbBuf -= len ; /* free Bytes in the user-Buffer */
5718 pi2w = (LPPORT_INFO_2W) bufferW;
5719 pi2a = (LPPORT_INFO_2A) pPorts;
5720 index = 0;
5721 /* Second Pass: Fill the User Buffer (if we have one) */
5722 while ((index < numentries) && pPorts) {
5723 index++;
5724 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5725 pi2a->pPortName = ptr;
5726 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5727 ptr, cbBuf , NULL, NULL);
5728 ptr += len;
5729 cbBuf -= len;
5730 if (Level > 1) {
5731 pi2a->pMonitorName = ptr;
5732 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5733 ptr, cbBuf, NULL, NULL);
5734 ptr += len;
5735 cbBuf -= len;
5737 pi2a->pDescription = ptr;
5738 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5739 ptr, cbBuf, NULL, NULL);
5740 ptr += len;
5741 cbBuf -= len;
5743 pi2a->fPortType = pi2w->fPortType;
5744 pi2a->Reserved = 0; /* documented: "must be zero" */
5747 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5748 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5749 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5753 cleanup:
5754 if (pcbNeeded) *pcbNeeded = needed;
5755 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5757 HeapFree(GetProcessHeap(), 0, nameW);
5758 HeapFree(GetProcessHeap(), 0, bufferW);
5760 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5761 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5763 return (res);
5767 /******************************************************************************
5768 * EnumPortsW (WINSPOOL.@)
5770 * Enumerate available Ports
5772 * PARAMS
5773 * pName [I] Servername or NULL (local Computer)
5774 * Level [I] Structure-Level (1 or 2)
5775 * pPorts [O] PTR to Buffer that receives the Result
5776 * cbBuf [I] Size of Buffer at pPorts
5777 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5778 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5780 * RETURNS
5781 * Success: TRUE
5782 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5785 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5788 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5789 cbBuf, pcbNeeded, pcReturned);
5791 if ((backend == NULL) && !load_backend()) return FALSE;
5793 /* Level is not checked in win9x */
5794 if (!Level || (Level > 2)) {
5795 WARN("level (%d) is ignored in win9x\n", Level);
5796 SetLastError(ERROR_INVALID_LEVEL);
5797 return FALSE;
5799 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5800 SetLastError(RPC_X_NULL_REF_POINTER);
5801 return FALSE;
5804 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5807 /******************************************************************************
5808 * GetDefaultPrinterW (WINSPOOL.@)
5810 * FIXME
5811 * This function must read the value from data 'device' of key
5812 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5814 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5816 BOOL retval = TRUE;
5817 DWORD insize, len;
5818 WCHAR *buffer, *ptr;
5820 if (!namesize)
5822 SetLastError(ERROR_INVALID_PARAMETER);
5823 return FALSE;
5826 /* make the buffer big enough for the stuff from the profile/registry,
5827 * the content must fit into the local buffer to compute the correct
5828 * size even if the extern buffer is too small or not given.
5829 * (20 for ,driver,port) */
5830 insize = *namesize;
5831 len = max(100, (insize + 20));
5832 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5834 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5836 SetLastError (ERROR_FILE_NOT_FOUND);
5837 retval = FALSE;
5838 goto end;
5840 TRACE("%s\n", debugstr_w(buffer));
5842 if ((ptr = strchrW(buffer, ',')) == NULL)
5844 SetLastError(ERROR_INVALID_NAME);
5845 retval = FALSE;
5846 goto end;
5849 *ptr = 0;
5850 *namesize = strlenW(buffer) + 1;
5851 if(!name || (*namesize > insize))
5853 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5854 retval = FALSE;
5855 goto end;
5857 strcpyW(name, buffer);
5859 end:
5860 HeapFree( GetProcessHeap(), 0, buffer);
5861 return retval;
5865 /******************************************************************************
5866 * GetDefaultPrinterA (WINSPOOL.@)
5868 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5870 BOOL retval = TRUE;
5871 DWORD insize = 0;
5872 WCHAR *bufferW = NULL;
5874 if (!namesize)
5876 SetLastError(ERROR_INVALID_PARAMETER);
5877 return FALSE;
5880 if(name && *namesize) {
5881 insize = *namesize;
5882 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5885 if(!GetDefaultPrinterW( bufferW, namesize)) {
5886 retval = FALSE;
5887 goto end;
5890 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5891 NULL, NULL);
5892 if (!*namesize)
5894 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5895 retval = FALSE;
5897 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5899 end:
5900 HeapFree( GetProcessHeap(), 0, bufferW);
5901 return retval;
5905 /******************************************************************************
5906 * SetDefaultPrinterW (WINSPOOL.204)
5908 * Set the Name of the Default Printer
5910 * PARAMS
5911 * pszPrinter [I] Name of the Printer or NULL
5913 * RETURNS
5914 * Success: True
5915 * Failure: FALSE
5917 * NOTES
5918 * When the Parameter is NULL or points to an Empty String and
5919 * a Default Printer was already present, then this Function changes nothing.
5920 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5921 * the First enumerated local Printer is used.
5924 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5926 WCHAR default_printer[MAX_PATH];
5927 LPWSTR buffer = NULL;
5928 HKEY hreg;
5929 DWORD size;
5930 DWORD namelen;
5931 LONG lres;
5933 TRACE("(%s)\n", debugstr_w(pszPrinter));
5934 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5936 default_printer[0] = '\0';
5937 size = sizeof(default_printer)/sizeof(WCHAR);
5939 /* if we have a default Printer, do nothing. */
5940 if (GetDefaultPrinterW(default_printer, &size))
5941 return TRUE;
5943 pszPrinter = NULL;
5944 /* we have no default Printer: search local Printers and use the first */
5945 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5947 default_printer[0] = '\0';
5948 size = sizeof(default_printer)/sizeof(WCHAR);
5949 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5951 pszPrinter = default_printer;
5952 TRACE("using %s\n", debugstr_w(pszPrinter));
5954 RegCloseKey(hreg);
5957 if (pszPrinter == NULL) {
5958 TRACE("no local printer found\n");
5959 SetLastError(ERROR_FILE_NOT_FOUND);
5960 return FALSE;
5964 /* "pszPrinter" is never empty or NULL here. */
5965 namelen = lstrlenW(pszPrinter);
5966 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5967 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5968 if (!buffer ||
5969 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5970 HeapFree(GetProcessHeap(), 0, buffer);
5971 SetLastError(ERROR_FILE_NOT_FOUND);
5972 return FALSE;
5975 /* read the devices entry for the printer (driver,port) to build the string for the
5976 default device entry (printer,driver,port) */
5977 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5978 buffer[namelen] = ',';
5979 namelen++; /* move index to the start of the driver */
5981 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5982 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5983 if (!lres) {
5984 TRACE("set device to %s\n", debugstr_w(buffer));
5986 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5987 TRACE("failed to set the device entry: %d\n", GetLastError());
5988 lres = ERROR_INVALID_PRINTER_NAME;
5991 /* remove the next section, when INIFileMapping is implemented */
5993 HKEY hdev;
5994 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5995 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5996 RegCloseKey(hdev);
6000 else
6002 if (lres != ERROR_FILE_NOT_FOUND)
6003 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6005 SetLastError(ERROR_INVALID_PRINTER_NAME);
6008 RegCloseKey(hreg);
6009 HeapFree(GetProcessHeap(), 0, buffer);
6010 return (lres == ERROR_SUCCESS);
6013 /******************************************************************************
6014 * SetDefaultPrinterA (WINSPOOL.202)
6016 * See SetDefaultPrinterW.
6019 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6021 LPWSTR bufferW = NULL;
6022 BOOL res;
6024 TRACE("(%s)\n", debugstr_a(pszPrinter));
6025 if(pszPrinter) {
6026 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6027 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6028 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6030 res = SetDefaultPrinterW(bufferW);
6031 HeapFree(GetProcessHeap(), 0, bufferW);
6032 return res;
6035 /******************************************************************************
6036 * SetPrinterDataExA (WINSPOOL.@)
6038 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6039 LPCSTR pValueName, DWORD Type,
6040 LPBYTE pData, DWORD cbData)
6042 HKEY hkeyPrinter, hkeySubkey;
6043 DWORD ret;
6045 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6046 debugstr_a(pValueName), Type, pData, cbData);
6048 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6049 != ERROR_SUCCESS)
6050 return ret;
6052 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6053 != ERROR_SUCCESS) {
6054 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6055 RegCloseKey(hkeyPrinter);
6056 return ret;
6058 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6059 RegCloseKey(hkeySubkey);
6060 RegCloseKey(hkeyPrinter);
6061 return ret;
6064 /******************************************************************************
6065 * SetPrinterDataExW (WINSPOOL.@)
6067 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6068 LPCWSTR pValueName, DWORD Type,
6069 LPBYTE pData, DWORD cbData)
6071 HKEY hkeyPrinter, hkeySubkey;
6072 DWORD ret;
6074 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6075 debugstr_w(pValueName), Type, pData, cbData);
6077 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6078 != ERROR_SUCCESS)
6079 return ret;
6081 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6082 != ERROR_SUCCESS) {
6083 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6084 RegCloseKey(hkeyPrinter);
6085 return ret;
6087 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6088 RegCloseKey(hkeySubkey);
6089 RegCloseKey(hkeyPrinter);
6090 return ret;
6093 /******************************************************************************
6094 * SetPrinterDataA (WINSPOOL.@)
6096 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6097 LPBYTE pData, DWORD cbData)
6099 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6100 pData, cbData);
6103 /******************************************************************************
6104 * SetPrinterDataW (WINSPOOL.@)
6106 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6107 LPBYTE pData, DWORD cbData)
6109 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6110 pData, cbData);
6113 /******************************************************************************
6114 * GetPrinterDataExA (WINSPOOL.@)
6116 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6117 LPCSTR pValueName, LPDWORD pType,
6118 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6120 opened_printer_t *printer;
6121 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6122 DWORD ret;
6124 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6125 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6127 printer = get_opened_printer(hPrinter);
6128 if(!printer) return ERROR_INVALID_HANDLE;
6130 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6131 if (ret) return ret;
6133 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6135 if (printer->name) {
6137 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6138 if (ret) {
6139 RegCloseKey(hkeyPrinters);
6140 return ret;
6142 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6143 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6144 RegCloseKey(hkeyPrinter);
6145 RegCloseKey(hkeyPrinters);
6146 return ret;
6149 *pcbNeeded = nSize;
6150 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6151 0, pType, pData, pcbNeeded);
6153 if (!ret && !pData) ret = ERROR_MORE_DATA;
6155 RegCloseKey(hkeySubkey);
6156 RegCloseKey(hkeyPrinter);
6157 RegCloseKey(hkeyPrinters);
6159 TRACE("--> %d\n", ret);
6160 return ret;
6163 /******************************************************************************
6164 * GetPrinterDataExW (WINSPOOL.@)
6166 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6167 LPCWSTR pValueName, LPDWORD pType,
6168 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6170 opened_printer_t *printer;
6171 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6172 DWORD ret;
6174 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6175 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6177 printer = get_opened_printer(hPrinter);
6178 if(!printer) return ERROR_INVALID_HANDLE;
6180 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6181 if (ret) return ret;
6183 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6185 if (printer->name) {
6187 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6188 if (ret) {
6189 RegCloseKey(hkeyPrinters);
6190 return ret;
6192 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6193 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6194 RegCloseKey(hkeyPrinter);
6195 RegCloseKey(hkeyPrinters);
6196 return ret;
6199 *pcbNeeded = nSize;
6200 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6201 0, pType, pData, pcbNeeded);
6203 if (!ret && !pData) ret = ERROR_MORE_DATA;
6205 RegCloseKey(hkeySubkey);
6206 RegCloseKey(hkeyPrinter);
6207 RegCloseKey(hkeyPrinters);
6209 TRACE("--> %d\n", ret);
6210 return ret;
6213 /******************************************************************************
6214 * GetPrinterDataA (WINSPOOL.@)
6216 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6217 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6219 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6220 pData, nSize, pcbNeeded);
6223 /******************************************************************************
6224 * GetPrinterDataW (WINSPOOL.@)
6226 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6227 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6229 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6230 pData, nSize, pcbNeeded);
6233 /*******************************************************************************
6234 * EnumPrinterDataExW [WINSPOOL.@]
6236 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6237 LPBYTE pEnumValues, DWORD cbEnumValues,
6238 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6240 HKEY hkPrinter, hkSubKey;
6241 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6242 cbValueNameLen, cbMaxValueLen, cbValueLen,
6243 cbBufSize, dwType;
6244 LPWSTR lpValueName;
6245 HANDLE hHeap;
6246 PBYTE lpValue;
6247 PPRINTER_ENUM_VALUESW ppev;
6249 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6251 if (pKeyName == NULL || *pKeyName == 0)
6252 return ERROR_INVALID_PARAMETER;
6254 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6255 if (ret != ERROR_SUCCESS)
6257 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6258 hPrinter, ret);
6259 return ret;
6262 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6263 if (ret != ERROR_SUCCESS)
6265 r = RegCloseKey (hkPrinter);
6266 if (r != ERROR_SUCCESS)
6267 WARN ("RegCloseKey returned %i\n", r);
6268 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6269 debugstr_w (pKeyName), ret);
6270 return ret;
6273 ret = RegCloseKey (hkPrinter);
6274 if (ret != ERROR_SUCCESS)
6276 ERR ("RegCloseKey returned %i\n", ret);
6277 r = RegCloseKey (hkSubKey);
6278 if (r != ERROR_SUCCESS)
6279 WARN ("RegCloseKey returned %i\n", r);
6280 return ret;
6283 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6284 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6285 if (ret != ERROR_SUCCESS)
6287 r = RegCloseKey (hkSubKey);
6288 if (r != ERROR_SUCCESS)
6289 WARN ("RegCloseKey returned %i\n", r);
6290 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6291 return ret;
6294 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6295 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6297 if (cValues == 0) /* empty key */
6299 r = RegCloseKey (hkSubKey);
6300 if (r != ERROR_SUCCESS)
6301 WARN ("RegCloseKey returned %i\n", r);
6302 *pcbEnumValues = *pnEnumValues = 0;
6303 return ERROR_SUCCESS;
6306 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6308 hHeap = GetProcessHeap ();
6309 if (hHeap == NULL)
6311 ERR ("GetProcessHeap failed\n");
6312 r = RegCloseKey (hkSubKey);
6313 if (r != ERROR_SUCCESS)
6314 WARN ("RegCloseKey returned %i\n", r);
6315 return ERROR_OUTOFMEMORY;
6318 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6319 if (lpValueName == NULL)
6321 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6322 r = RegCloseKey (hkSubKey);
6323 if (r != ERROR_SUCCESS)
6324 WARN ("RegCloseKey returned %i\n", r);
6325 return ERROR_OUTOFMEMORY;
6328 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6329 if (lpValue == NULL)
6331 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6332 if (HeapFree (hHeap, 0, lpValueName) == 0)
6333 WARN ("HeapFree failed with code %i\n", GetLastError ());
6334 r = RegCloseKey (hkSubKey);
6335 if (r != ERROR_SUCCESS)
6336 WARN ("RegCloseKey returned %i\n", r);
6337 return ERROR_OUTOFMEMORY;
6340 TRACE ("pass 1: calculating buffer required for all names and values\n");
6342 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6344 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6346 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6348 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6349 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6350 NULL, NULL, lpValue, &cbValueLen);
6351 if (ret != ERROR_SUCCESS)
6353 if (HeapFree (hHeap, 0, lpValue) == 0)
6354 WARN ("HeapFree failed with code %i\n", GetLastError ());
6355 if (HeapFree (hHeap, 0, lpValueName) == 0)
6356 WARN ("HeapFree failed with code %i\n", GetLastError ());
6357 r = RegCloseKey (hkSubKey);
6358 if (r != ERROR_SUCCESS)
6359 WARN ("RegCloseKey returned %i\n", r);
6360 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6361 return ret;
6364 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6365 debugstr_w (lpValueName), dwIndex,
6366 cbValueNameLen + 1, cbValueLen);
6368 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6369 cbBufSize += cbValueLen;
6372 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6374 *pcbEnumValues = cbBufSize;
6375 *pnEnumValues = cValues;
6377 if (cbEnumValues < cbBufSize) /* buffer too small */
6379 if (HeapFree (hHeap, 0, lpValue) == 0)
6380 WARN ("HeapFree failed with code %i\n", GetLastError ());
6381 if (HeapFree (hHeap, 0, lpValueName) == 0)
6382 WARN ("HeapFree failed with code %i\n", GetLastError ());
6383 r = RegCloseKey (hkSubKey);
6384 if (r != ERROR_SUCCESS)
6385 WARN ("RegCloseKey returned %i\n", r);
6386 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6387 return ERROR_MORE_DATA;
6390 TRACE ("pass 2: copying all names and values to buffer\n");
6392 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6393 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6395 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6397 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6398 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6399 NULL, &dwType, lpValue, &cbValueLen);
6400 if (ret != ERROR_SUCCESS)
6402 if (HeapFree (hHeap, 0, lpValue) == 0)
6403 WARN ("HeapFree failed with code %i\n", GetLastError ());
6404 if (HeapFree (hHeap, 0, lpValueName) == 0)
6405 WARN ("HeapFree failed with code %i\n", GetLastError ());
6406 r = RegCloseKey (hkSubKey);
6407 if (r != ERROR_SUCCESS)
6408 WARN ("RegCloseKey returned %i\n", r);
6409 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6410 return ret;
6413 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6414 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6415 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6416 pEnumValues += cbValueNameLen;
6418 /* return # of *bytes* (including trailing \0), not # of chars */
6419 ppev[dwIndex].cbValueName = cbValueNameLen;
6421 ppev[dwIndex].dwType = dwType;
6423 memcpy (pEnumValues, lpValue, cbValueLen);
6424 ppev[dwIndex].pData = pEnumValues;
6425 pEnumValues += cbValueLen;
6427 ppev[dwIndex].cbData = cbValueLen;
6429 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6430 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6433 if (HeapFree (hHeap, 0, lpValue) == 0)
6435 ret = GetLastError ();
6436 ERR ("HeapFree failed with code %i\n", ret);
6437 if (HeapFree (hHeap, 0, lpValueName) == 0)
6438 WARN ("HeapFree failed with code %i\n", GetLastError ());
6439 r = RegCloseKey (hkSubKey);
6440 if (r != ERROR_SUCCESS)
6441 WARN ("RegCloseKey returned %i\n", r);
6442 return ret;
6445 if (HeapFree (hHeap, 0, lpValueName) == 0)
6447 ret = GetLastError ();
6448 ERR ("HeapFree failed with code %i\n", ret);
6449 r = RegCloseKey (hkSubKey);
6450 if (r != ERROR_SUCCESS)
6451 WARN ("RegCloseKey returned %i\n", r);
6452 return ret;
6455 ret = RegCloseKey (hkSubKey);
6456 if (ret != ERROR_SUCCESS)
6458 ERR ("RegCloseKey returned %i\n", ret);
6459 return ret;
6462 return ERROR_SUCCESS;
6465 /*******************************************************************************
6466 * EnumPrinterDataExA [WINSPOOL.@]
6468 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6469 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6470 * what Windows 2000 SP1 does.
6473 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6474 LPBYTE pEnumValues, DWORD cbEnumValues,
6475 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6477 INT len;
6478 LPWSTR pKeyNameW;
6479 DWORD ret, dwIndex, dwBufSize;
6480 HANDLE hHeap;
6481 LPSTR pBuffer;
6483 TRACE ("%p %s\n", hPrinter, pKeyName);
6485 if (pKeyName == NULL || *pKeyName == 0)
6486 return ERROR_INVALID_PARAMETER;
6488 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6489 if (len == 0)
6491 ret = GetLastError ();
6492 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6493 return ret;
6496 hHeap = GetProcessHeap ();
6497 if (hHeap == NULL)
6499 ERR ("GetProcessHeap failed\n");
6500 return ERROR_OUTOFMEMORY;
6503 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6504 if (pKeyNameW == NULL)
6506 ERR ("Failed to allocate %i bytes from process heap\n",
6507 (LONG)(len * sizeof (WCHAR)));
6508 return ERROR_OUTOFMEMORY;
6511 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6513 ret = GetLastError ();
6514 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6515 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6516 WARN ("HeapFree failed with code %i\n", GetLastError ());
6517 return ret;
6520 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6521 pcbEnumValues, pnEnumValues);
6522 if (ret != ERROR_SUCCESS)
6524 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6525 WARN ("HeapFree failed with code %i\n", GetLastError ());
6526 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6527 return ret;
6530 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6532 ret = GetLastError ();
6533 ERR ("HeapFree failed with code %i\n", ret);
6534 return ret;
6537 if (*pnEnumValues == 0) /* empty key */
6538 return ERROR_SUCCESS;
6540 dwBufSize = 0;
6541 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6543 PPRINTER_ENUM_VALUESW ppev =
6544 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6546 if (dwBufSize < ppev->cbValueName)
6547 dwBufSize = ppev->cbValueName;
6549 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6550 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6551 dwBufSize = ppev->cbData;
6554 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6556 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6557 if (pBuffer == NULL)
6559 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6560 return ERROR_OUTOFMEMORY;
6563 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6565 PPRINTER_ENUM_VALUESW ppev =
6566 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6568 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6569 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6570 NULL);
6571 if (len == 0)
6573 ret = GetLastError ();
6574 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6575 if (HeapFree (hHeap, 0, pBuffer) == 0)
6576 WARN ("HeapFree failed with code %i\n", GetLastError ());
6577 return ret;
6580 memcpy (ppev->pValueName, pBuffer, len);
6582 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6584 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6585 ppev->dwType != REG_MULTI_SZ)
6586 continue;
6588 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6589 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6590 if (len == 0)
6592 ret = GetLastError ();
6593 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6594 if (HeapFree (hHeap, 0, pBuffer) == 0)
6595 WARN ("HeapFree failed with code %i\n", GetLastError ());
6596 return ret;
6599 memcpy (ppev->pData, pBuffer, len);
6601 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6602 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6605 if (HeapFree (hHeap, 0, pBuffer) == 0)
6607 ret = GetLastError ();
6608 ERR ("HeapFree failed with code %i\n", ret);
6609 return ret;
6612 return ERROR_SUCCESS;
6615 /******************************************************************************
6616 * AbortPrinter (WINSPOOL.@)
6618 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6620 FIXME("(%p), stub!\n", hPrinter);
6621 return TRUE;
6624 /******************************************************************************
6625 * AddPortA (WINSPOOL.@)
6627 * See AddPortW.
6630 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6632 LPWSTR nameW = NULL;
6633 LPWSTR monitorW = NULL;
6634 DWORD len;
6635 BOOL res;
6637 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6639 if (pName) {
6640 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6641 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6642 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6645 if (pMonitorName) {
6646 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6647 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6648 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6650 res = AddPortW(nameW, hWnd, monitorW);
6651 HeapFree(GetProcessHeap(), 0, nameW);
6652 HeapFree(GetProcessHeap(), 0, monitorW);
6653 return res;
6656 /******************************************************************************
6657 * AddPortW (WINSPOOL.@)
6659 * Add a Port for a specific Monitor
6661 * PARAMS
6662 * pName [I] Servername or NULL (local Computer)
6663 * hWnd [I] Handle to parent Window for the Dialog-Box
6664 * pMonitorName [I] Name of the Monitor that manage the Port
6666 * RETURNS
6667 * Success: TRUE
6668 * Failure: FALSE
6671 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6673 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6675 if ((backend == NULL) && !load_backend()) return FALSE;
6677 if (!pMonitorName) {
6678 SetLastError(RPC_X_NULL_REF_POINTER);
6679 return FALSE;
6682 return backend->fpAddPort(pName, hWnd, pMonitorName);
6685 /******************************************************************************
6686 * AddPortExA (WINSPOOL.@)
6688 * See AddPortExW.
6691 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6693 PORT_INFO_2W pi2W;
6694 PORT_INFO_2A * pi2A;
6695 LPWSTR nameW = NULL;
6696 LPWSTR monitorW = NULL;
6697 DWORD len;
6698 BOOL res;
6700 pi2A = (PORT_INFO_2A *) pBuffer;
6702 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6703 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6705 if ((level < 1) || (level > 2)) {
6706 SetLastError(ERROR_INVALID_LEVEL);
6707 return FALSE;
6710 if (!pi2A) {
6711 SetLastError(ERROR_INVALID_PARAMETER);
6712 return FALSE;
6715 if (pName) {
6716 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6717 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6718 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6721 if (pMonitorName) {
6722 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6723 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6724 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6727 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6729 if (pi2A->pPortName) {
6730 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6731 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6732 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6735 if (level > 1) {
6736 if (pi2A->pMonitorName) {
6737 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6738 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6739 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6742 if (pi2A->pDescription) {
6743 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6744 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6745 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6747 pi2W.fPortType = pi2A->fPortType;
6748 pi2W.Reserved = pi2A->Reserved;
6751 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6753 HeapFree(GetProcessHeap(), 0, nameW);
6754 HeapFree(GetProcessHeap(), 0, monitorW);
6755 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6756 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6757 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6758 return res;
6762 /******************************************************************************
6763 * AddPortExW (WINSPOOL.@)
6765 * Add a Port for a specific Monitor, without presenting a user interface
6767 * PARAMS
6768 * pName [I] Servername or NULL (local Computer)
6769 * level [I] Structure-Level (1 or 2) for pBuffer
6770 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6771 * pMonitorName [I] Name of the Monitor that manage the Port
6773 * RETURNS
6774 * Success: TRUE
6775 * Failure: FALSE
6778 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6780 PORT_INFO_2W * pi2;
6782 pi2 = (PORT_INFO_2W *) pBuffer;
6784 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6785 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6786 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6787 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6789 if ((backend == NULL) && !load_backend()) return FALSE;
6791 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6792 SetLastError(ERROR_INVALID_PARAMETER);
6793 return FALSE;
6796 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6799 /******************************************************************************
6800 * AddPrinterConnectionA (WINSPOOL.@)
6802 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6804 FIXME("%s\n", debugstr_a(pName));
6805 return FALSE;
6808 /******************************************************************************
6809 * AddPrinterConnectionW (WINSPOOL.@)
6811 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6813 FIXME("%s\n", debugstr_w(pName));
6814 return FALSE;
6817 /******************************************************************************
6818 * AddPrinterDriverExW (WINSPOOL.@)
6820 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6822 * PARAMS
6823 * pName [I] Servername or NULL (local Computer)
6824 * level [I] Level for the supplied DRIVER_INFO_*W struct
6825 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6826 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6828 * RESULTS
6829 * Success: TRUE
6830 * Failure: FALSE
6833 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6835 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6837 if ((backend == NULL) && !load_backend()) return FALSE;
6839 if (level < 2 || level == 5 || level == 7 || level > 8) {
6840 SetLastError(ERROR_INVALID_LEVEL);
6841 return FALSE;
6844 if (!pDriverInfo) {
6845 SetLastError(ERROR_INVALID_PARAMETER);
6846 return FALSE;
6849 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6852 /******************************************************************************
6853 * AddPrinterDriverExA (WINSPOOL.@)
6855 * See AddPrinterDriverExW.
6858 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6860 DRIVER_INFO_8A *diA;
6861 DRIVER_INFO_8W diW;
6862 LPWSTR nameW = NULL;
6863 DWORD lenA;
6864 DWORD len;
6865 DWORD res = FALSE;
6867 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6869 diA = (DRIVER_INFO_8A *) pDriverInfo;
6870 ZeroMemory(&diW, sizeof(diW));
6872 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6873 SetLastError(ERROR_INVALID_LEVEL);
6874 return FALSE;
6877 if (diA == NULL) {
6878 SetLastError(ERROR_INVALID_PARAMETER);
6879 return FALSE;
6882 /* convert servername to unicode */
6883 if (pName) {
6884 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6885 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6886 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6889 /* common fields */
6890 diW.cVersion = diA->cVersion;
6892 if (diA->pName) {
6893 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6894 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6895 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6898 if (diA->pEnvironment) {
6899 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6900 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6901 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6904 if (diA->pDriverPath) {
6905 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6906 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6907 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6910 if (diA->pDataFile) {
6911 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6912 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6913 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6916 if (diA->pConfigFile) {
6917 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6918 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6919 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6922 if ((Level > 2) && diA->pDependentFiles) {
6923 lenA = multi_sz_lenA(diA->pDependentFiles);
6924 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6925 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6926 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6929 if ((Level > 2) && diA->pMonitorName) {
6930 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6931 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6932 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6935 if ((Level > 3) && diA->pDefaultDataType) {
6936 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6937 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6938 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6941 if ((Level > 3) && diA->pszzPreviousNames) {
6942 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6943 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6944 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6945 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6948 if ((Level > 5) && diA->pszMfgName) {
6949 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6950 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6951 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6954 if ((Level > 5) && diA->pszOEMUrl) {
6955 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6956 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6957 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6960 if ((Level > 5) && diA->pszHardwareID) {
6961 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6962 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6963 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6966 if ((Level > 5) && diA->pszProvider) {
6967 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6968 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6969 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6972 if (Level > 7) {
6973 FIXME("level %u is incomplete\n", Level);
6976 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6977 TRACE("got %u with %u\n", res, GetLastError());
6978 HeapFree(GetProcessHeap(), 0, nameW);
6979 HeapFree(GetProcessHeap(), 0, diW.pName);
6980 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6981 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6982 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6983 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6984 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6985 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6986 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6987 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6988 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6989 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6990 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6991 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6993 TRACE("=> %u with %u\n", res, GetLastError());
6994 return res;
6997 /******************************************************************************
6998 * ConfigurePortA (WINSPOOL.@)
7000 * See ConfigurePortW.
7003 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7005 LPWSTR nameW = NULL;
7006 LPWSTR portW = NULL;
7007 INT len;
7008 DWORD res;
7010 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7012 /* convert servername to unicode */
7013 if (pName) {
7014 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7015 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7016 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7019 /* convert portname to unicode */
7020 if (pPortName) {
7021 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7022 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7023 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7026 res = ConfigurePortW(nameW, hWnd, portW);
7027 HeapFree(GetProcessHeap(), 0, nameW);
7028 HeapFree(GetProcessHeap(), 0, portW);
7029 return res;
7032 /******************************************************************************
7033 * ConfigurePortW (WINSPOOL.@)
7035 * Display the Configuration-Dialog for a specific Port
7037 * PARAMS
7038 * pName [I] Servername or NULL (local Computer)
7039 * hWnd [I] Handle to parent Window for the Dialog-Box
7040 * pPortName [I] Name of the Port, that should be configured
7042 * RETURNS
7043 * Success: TRUE
7044 * Failure: FALSE
7047 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7050 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7052 if ((backend == NULL) && !load_backend()) return FALSE;
7054 if (!pPortName) {
7055 SetLastError(RPC_X_NULL_REF_POINTER);
7056 return FALSE;
7059 return backend->fpConfigurePort(pName, hWnd, pPortName);
7062 /******************************************************************************
7063 * ConnectToPrinterDlg (WINSPOOL.@)
7065 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7067 FIXME("%p %x\n", hWnd, Flags);
7068 return NULL;
7071 /******************************************************************************
7072 * DeletePrinterConnectionA (WINSPOOL.@)
7074 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7076 FIXME("%s\n", debugstr_a(pName));
7077 return TRUE;
7080 /******************************************************************************
7081 * DeletePrinterConnectionW (WINSPOOL.@)
7083 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7085 FIXME("%s\n", debugstr_w(pName));
7086 return TRUE;
7089 /******************************************************************************
7090 * DeletePrinterDriverExW (WINSPOOL.@)
7092 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7093 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7095 HKEY hkey_drivers;
7096 BOOL ret = FALSE;
7098 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7099 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7101 if(pName && pName[0])
7103 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7104 SetLastError(ERROR_INVALID_PARAMETER);
7105 return FALSE;
7108 if(dwDeleteFlag)
7110 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7111 SetLastError(ERROR_INVALID_PARAMETER);
7112 return FALSE;
7115 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7117 if(!hkey_drivers)
7119 ERR("Can't open drivers key\n");
7120 return FALSE;
7123 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7124 ret = TRUE;
7126 RegCloseKey(hkey_drivers);
7128 return ret;
7131 /******************************************************************************
7132 * DeletePrinterDriverExA (WINSPOOL.@)
7134 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7135 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7137 UNICODE_STRING NameW, EnvW, DriverW;
7138 BOOL ret;
7140 asciitounicode(&NameW, pName);
7141 asciitounicode(&EnvW, pEnvironment);
7142 asciitounicode(&DriverW, pDriverName);
7144 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7146 RtlFreeUnicodeString(&DriverW);
7147 RtlFreeUnicodeString(&EnvW);
7148 RtlFreeUnicodeString(&NameW);
7150 return ret;
7153 /******************************************************************************
7154 * DeletePrinterDataExW (WINSPOOL.@)
7156 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7157 LPCWSTR pValueName)
7159 FIXME("%p %s %s\n", hPrinter,
7160 debugstr_w(pKeyName), debugstr_w(pValueName));
7161 return ERROR_INVALID_PARAMETER;
7164 /******************************************************************************
7165 * DeletePrinterDataExA (WINSPOOL.@)
7167 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7168 LPCSTR pValueName)
7170 FIXME("%p %s %s\n", hPrinter,
7171 debugstr_a(pKeyName), debugstr_a(pValueName));
7172 return ERROR_INVALID_PARAMETER;
7175 /******************************************************************************
7176 * DeletePrintProcessorA (WINSPOOL.@)
7178 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7180 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7181 debugstr_a(pPrintProcessorName));
7182 return TRUE;
7185 /******************************************************************************
7186 * DeletePrintProcessorW (WINSPOOL.@)
7188 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7190 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7191 debugstr_w(pPrintProcessorName));
7192 return TRUE;
7195 /******************************************************************************
7196 * DeletePrintProvidorA (WINSPOOL.@)
7198 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7200 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7201 debugstr_a(pPrintProviderName));
7202 return TRUE;
7205 /******************************************************************************
7206 * DeletePrintProvidorW (WINSPOOL.@)
7208 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7210 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7211 debugstr_w(pPrintProviderName));
7212 return TRUE;
7215 /******************************************************************************
7216 * EnumFormsA (WINSPOOL.@)
7218 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7219 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7221 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7222 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7223 return FALSE;
7226 /******************************************************************************
7227 * EnumFormsW (WINSPOOL.@)
7229 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7230 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7232 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7233 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7234 return FALSE;
7237 /*****************************************************************************
7238 * EnumMonitorsA [WINSPOOL.@]
7240 * See EnumMonitorsW.
7243 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7244 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7246 BOOL res;
7247 LPBYTE bufferW = NULL;
7248 LPWSTR nameW = NULL;
7249 DWORD needed = 0;
7250 DWORD numentries = 0;
7251 INT len;
7253 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7254 cbBuf, pcbNeeded, pcReturned);
7256 /* convert servername to unicode */
7257 if (pName) {
7258 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7259 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7260 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7262 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7263 needed = cbBuf * sizeof(WCHAR);
7264 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7265 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7267 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7268 if (pcbNeeded) needed = *pcbNeeded;
7269 /* HeapReAlloc return NULL, when bufferW was NULL */
7270 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7271 HeapAlloc(GetProcessHeap(), 0, needed);
7273 /* Try again with the large Buffer */
7274 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7276 numentries = pcReturned ? *pcReturned : 0;
7277 needed = 0;
7279 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7280 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7282 if (res) {
7283 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7284 DWORD entrysize = 0;
7285 DWORD index;
7286 LPSTR ptr;
7287 LPMONITOR_INFO_2W mi2w;
7288 LPMONITOR_INFO_2A mi2a;
7290 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7291 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7293 /* First pass: calculate the size for all Entries */
7294 mi2w = (LPMONITOR_INFO_2W) bufferW;
7295 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7296 index = 0;
7297 while (index < numentries) {
7298 index++;
7299 needed += entrysize; /* MONITOR_INFO_?A */
7300 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7302 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7303 NULL, 0, NULL, NULL);
7304 if (Level > 1) {
7305 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7306 NULL, 0, NULL, NULL);
7307 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7308 NULL, 0, NULL, NULL);
7310 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7311 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7312 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7315 /* check for errors and quit on failure */
7316 if (cbBuf < needed) {
7317 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7318 res = FALSE;
7319 goto emA_cleanup;
7321 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7322 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7323 cbBuf -= len ; /* free Bytes in the user-Buffer */
7324 mi2w = (LPMONITOR_INFO_2W) bufferW;
7325 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7326 index = 0;
7327 /* Second Pass: Fill the User Buffer (if we have one) */
7328 while ((index < numentries) && pMonitors) {
7329 index++;
7330 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7331 mi2a->pName = ptr;
7332 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7333 ptr, cbBuf , NULL, NULL);
7334 ptr += len;
7335 cbBuf -= len;
7336 if (Level > 1) {
7337 mi2a->pEnvironment = ptr;
7338 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7339 ptr, cbBuf, NULL, NULL);
7340 ptr += len;
7341 cbBuf -= len;
7343 mi2a->pDLLName = ptr;
7344 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7345 ptr, cbBuf, NULL, NULL);
7346 ptr += len;
7347 cbBuf -= len;
7349 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7350 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7351 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7354 emA_cleanup:
7355 if (pcbNeeded) *pcbNeeded = needed;
7356 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7358 HeapFree(GetProcessHeap(), 0, nameW);
7359 HeapFree(GetProcessHeap(), 0, bufferW);
7361 TRACE("returning %d with %d (%d byte for %d entries)\n",
7362 (res), GetLastError(), needed, numentries);
7364 return (res);
7368 /*****************************************************************************
7369 * EnumMonitorsW [WINSPOOL.@]
7371 * Enumerate available Port-Monitors
7373 * PARAMS
7374 * pName [I] Servername or NULL (local Computer)
7375 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7376 * pMonitors [O] PTR to Buffer that receives the Result
7377 * cbBuf [I] Size of Buffer at pMonitors
7378 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7379 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7381 * RETURNS
7382 * Success: TRUE
7383 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7386 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7387 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7390 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7391 cbBuf, pcbNeeded, pcReturned);
7393 if ((backend == NULL) && !load_backend()) return FALSE;
7395 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7396 SetLastError(RPC_X_NULL_REF_POINTER);
7397 return FALSE;
7400 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7403 /******************************************************************************
7404 * SpoolerInit (WINSPOOL.@)
7406 * Initialize the Spooler
7408 * RETURNS
7409 * Success: TRUE
7410 * Failure: FALSE
7412 * NOTES
7413 * The function fails on windows, when the spooler service is not running
7416 BOOL WINAPI SpoolerInit(void)
7419 if ((backend == NULL) && !load_backend()) return FALSE;
7420 return TRUE;
7423 /******************************************************************************
7424 * XcvDataW (WINSPOOL.@)
7426 * Execute commands in the Printmonitor DLL
7428 * PARAMS
7429 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7430 * pszDataName [i] Name of the command to execute
7431 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7432 * cbInputData [i] Size in Bytes of Buffer at pInputData
7433 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7434 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7435 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7436 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7438 * RETURNS
7439 * Success: TRUE
7440 * Failure: FALSE
7442 * NOTES
7443 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7444 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7446 * Minimal List of commands, that a Printmonitor DLL should support:
7448 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7449 *| "AddPort" : Add a Port
7450 *| "DeletePort": Delete a Port
7452 * Many Printmonitors support additional commands. Examples for localspl.dll:
7453 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7454 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7457 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7458 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7459 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7461 opened_printer_t *printer;
7463 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7464 pInputData, cbInputData, pOutputData,
7465 cbOutputData, pcbOutputNeeded, pdwStatus);
7467 if ((backend == NULL) && !load_backend()) return FALSE;
7469 printer = get_opened_printer(hXcv);
7470 if (!printer || (!printer->backend_printer)) {
7471 SetLastError(ERROR_INVALID_HANDLE);
7472 return FALSE;
7475 if (!pcbOutputNeeded) {
7476 SetLastError(ERROR_INVALID_PARAMETER);
7477 return FALSE;
7480 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7481 SetLastError(RPC_X_NULL_REF_POINTER);
7482 return FALSE;
7485 *pcbOutputNeeded = 0;
7487 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7488 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7492 /*****************************************************************************
7493 * EnumPrinterDataA [WINSPOOL.@]
7496 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7497 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7498 DWORD cbData, LPDWORD pcbData )
7500 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7501 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7502 return ERROR_NO_MORE_ITEMS;
7505 /*****************************************************************************
7506 * EnumPrinterDataW [WINSPOOL.@]
7509 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7510 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7511 DWORD cbData, LPDWORD pcbData )
7513 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7514 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7515 return ERROR_NO_MORE_ITEMS;
7518 /*****************************************************************************
7519 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7522 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7523 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7524 LPDWORD pcbNeeded, LPDWORD pcReturned)
7526 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7527 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7528 pcbNeeded, pcReturned);
7529 return FALSE;
7532 /*****************************************************************************
7533 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7536 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7537 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7538 LPDWORD pcbNeeded, LPDWORD pcReturned)
7540 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7541 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7542 pcbNeeded, pcReturned);
7543 return FALSE;
7546 /*****************************************************************************
7547 * EnumPrintProcessorsA [WINSPOOL.@]
7549 * See EnumPrintProcessorsW.
7552 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7553 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7555 BOOL res;
7556 LPBYTE bufferW = NULL;
7557 LPWSTR nameW = NULL;
7558 LPWSTR envW = NULL;
7559 DWORD needed = 0;
7560 DWORD numentries = 0;
7561 INT len;
7563 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7564 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7566 /* convert names to unicode */
7567 if (pName) {
7568 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7569 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7570 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7572 if (pEnvironment) {
7573 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7574 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7575 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7578 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7579 needed = cbBuf * sizeof(WCHAR);
7580 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7581 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7583 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7584 if (pcbNeeded) needed = *pcbNeeded;
7585 /* HeapReAlloc return NULL, when bufferW was NULL */
7586 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7587 HeapAlloc(GetProcessHeap(), 0, needed);
7589 /* Try again with the large Buffer */
7590 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7592 numentries = pcReturned ? *pcReturned : 0;
7593 needed = 0;
7595 if (res) {
7596 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7597 DWORD index;
7598 LPSTR ptr;
7599 PPRINTPROCESSOR_INFO_1W ppiw;
7600 PPRINTPROCESSOR_INFO_1A ppia;
7602 /* First pass: calculate the size for all Entries */
7603 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7604 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7605 index = 0;
7606 while (index < numentries) {
7607 index++;
7608 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7609 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7611 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7612 NULL, 0, NULL, NULL);
7614 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7615 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7618 /* check for errors and quit on failure */
7619 if (cbBuf < needed) {
7620 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7621 res = FALSE;
7622 goto epp_cleanup;
7625 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7626 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7627 cbBuf -= len ; /* free Bytes in the user-Buffer */
7628 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7629 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7630 index = 0;
7631 /* Second Pass: Fill the User Buffer (if we have one) */
7632 while ((index < numentries) && pPPInfo) {
7633 index++;
7634 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7635 ppia->pName = ptr;
7636 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7637 ptr, cbBuf , NULL, NULL);
7638 ptr += len;
7639 cbBuf -= len;
7641 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7642 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7646 epp_cleanup:
7647 if (pcbNeeded) *pcbNeeded = needed;
7648 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7650 HeapFree(GetProcessHeap(), 0, nameW);
7651 HeapFree(GetProcessHeap(), 0, envW);
7652 HeapFree(GetProcessHeap(), 0, bufferW);
7654 TRACE("returning %d with %d (%d byte for %d entries)\n",
7655 (res), GetLastError(), needed, numentries);
7657 return (res);
7660 /*****************************************************************************
7661 * EnumPrintProcessorsW [WINSPOOL.@]
7663 * Enumerate available Print Processors
7665 * PARAMS
7666 * pName [I] Servername or NULL (local Computer)
7667 * pEnvironment [I] Printing-Environment or NULL (Default)
7668 * Level [I] Structure-Level (Only 1 is allowed)
7669 * pPPInfo [O] PTR to Buffer that receives the Result
7670 * cbBuf [I] Size of Buffer at pPPInfo
7671 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7672 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7674 * RETURNS
7675 * Success: TRUE
7676 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7679 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7680 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7683 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7684 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7686 if ((backend == NULL) && !load_backend()) return FALSE;
7688 if (!pcbNeeded || !pcReturned) {
7689 SetLastError(RPC_X_NULL_REF_POINTER);
7690 return FALSE;
7693 if (!pPPInfo && (cbBuf > 0)) {
7694 SetLastError(ERROR_INVALID_USER_BUFFER);
7695 return FALSE;
7698 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7699 cbBuf, pcbNeeded, pcReturned);
7702 /*****************************************************************************
7703 * ExtDeviceMode [WINSPOOL.@]
7706 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7707 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7708 DWORD fMode)
7710 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7711 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7712 debugstr_a(pProfile), fMode);
7713 return -1;
7716 /*****************************************************************************
7717 * FindClosePrinterChangeNotification [WINSPOOL.@]
7720 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7722 FIXME("Stub: %p\n", hChange);
7723 return TRUE;
7726 /*****************************************************************************
7727 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7730 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7731 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7733 FIXME("Stub: %p %x %x %p\n",
7734 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7735 return INVALID_HANDLE_VALUE;
7738 /*****************************************************************************
7739 * FindNextPrinterChangeNotification [WINSPOOL.@]
7742 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7743 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7745 FIXME("Stub: %p %p %p %p\n",
7746 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7747 return FALSE;
7750 /*****************************************************************************
7751 * FreePrinterNotifyInfo [WINSPOOL.@]
7754 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7756 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7757 return TRUE;
7760 /*****************************************************************************
7761 * string_to_buf
7763 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7764 * ansi depending on the unicode parameter.
7766 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7768 if(!str)
7770 *size = 0;
7771 return TRUE;
7774 if(unicode)
7776 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7777 if(*size <= cb)
7779 memcpy(ptr, str, *size);
7780 return TRUE;
7782 return FALSE;
7784 else
7786 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7787 if(*size <= cb)
7789 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7790 return TRUE;
7792 return FALSE;
7796 /*****************************************************************************
7797 * get_job_info_1
7799 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7800 LPDWORD pcbNeeded, BOOL unicode)
7802 DWORD size, left = cbBuf;
7803 BOOL space = (cbBuf > 0);
7804 LPBYTE ptr = buf;
7806 *pcbNeeded = 0;
7808 if(space)
7810 ji1->JobId = job->job_id;
7813 string_to_buf(job->document_title, ptr, left, &size, unicode);
7814 if(space && size <= left)
7816 ji1->pDocument = (LPWSTR)ptr;
7817 ptr += size;
7818 left -= size;
7820 else
7821 space = FALSE;
7822 *pcbNeeded += size;
7824 if (job->printer_name)
7826 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7827 if(space && size <= left)
7829 ji1->pPrinterName = (LPWSTR)ptr;
7830 ptr += size;
7831 left -= size;
7833 else
7834 space = FALSE;
7835 *pcbNeeded += size;
7838 return space;
7841 /*****************************************************************************
7842 * get_job_info_2
7844 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7845 LPDWORD pcbNeeded, BOOL unicode)
7847 DWORD size, left = cbBuf;
7848 DWORD shift;
7849 BOOL space = (cbBuf > 0);
7850 LPBYTE ptr = buf;
7851 LPDEVMODEA dmA = NULL;
7852 LPDEVMODEW devmode;
7854 *pcbNeeded = 0;
7856 if(space)
7858 ji2->JobId = job->job_id;
7861 string_to_buf(job->document_title, ptr, left, &size, unicode);
7862 if(space && size <= left)
7864 ji2->pDocument = (LPWSTR)ptr;
7865 ptr += size;
7866 left -= size;
7868 else
7869 space = FALSE;
7870 *pcbNeeded += size;
7872 if (job->printer_name)
7874 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7875 if(space && size <= left)
7877 ji2->pPrinterName = (LPWSTR)ptr;
7878 ptr += size;
7879 left -= size;
7881 else
7882 space = FALSE;
7883 *pcbNeeded += size;
7886 if (job->devmode)
7888 if (!unicode)
7890 dmA = DEVMODEdupWtoA(job->devmode);
7891 devmode = (LPDEVMODEW) dmA;
7892 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7894 else
7896 devmode = job->devmode;
7897 size = devmode->dmSize + devmode->dmDriverExtra;
7900 if (!devmode)
7901 FIXME("Can't convert DEVMODE W to A\n");
7902 else
7904 /* align DEVMODE to a DWORD boundary */
7905 shift = (4 - (*pcbNeeded & 3)) & 3;
7906 size += shift;
7908 if (size <= left)
7910 ptr += shift;
7911 memcpy(ptr, devmode, size-shift);
7912 ji2->pDevMode = (LPDEVMODEW)ptr;
7913 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7914 ptr += size-shift;
7915 left -= size;
7917 else
7918 space = FALSE;
7919 *pcbNeeded +=size;
7923 return space;
7926 /*****************************************************************************
7927 * get_job_info
7929 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7930 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7932 BOOL ret = FALSE;
7933 DWORD needed = 0, size;
7934 job_t *job;
7935 LPBYTE ptr = pJob;
7937 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7939 EnterCriticalSection(&printer_handles_cs);
7940 job = get_job(hPrinter, JobId);
7941 if(!job)
7942 goto end;
7944 switch(Level)
7946 case 1:
7947 size = sizeof(JOB_INFO_1W);
7948 if(cbBuf >= size)
7950 cbBuf -= size;
7951 ptr += size;
7952 memset(pJob, 0, size);
7954 else
7955 cbBuf = 0;
7956 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7957 needed += size;
7958 break;
7960 case 2:
7961 size = sizeof(JOB_INFO_2W);
7962 if(cbBuf >= size)
7964 cbBuf -= size;
7965 ptr += size;
7966 memset(pJob, 0, size);
7968 else
7969 cbBuf = 0;
7970 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7971 needed += size;
7972 break;
7974 case 3:
7975 size = sizeof(JOB_INFO_3);
7976 if(cbBuf >= size)
7978 cbBuf -= size;
7979 memset(pJob, 0, size);
7980 ret = TRUE;
7982 else
7983 cbBuf = 0;
7984 needed = size;
7985 break;
7987 default:
7988 SetLastError(ERROR_INVALID_LEVEL);
7989 goto end;
7991 if(pcbNeeded)
7992 *pcbNeeded = needed;
7993 end:
7994 LeaveCriticalSection(&printer_handles_cs);
7995 return ret;
7998 /*****************************************************************************
7999 * GetJobA [WINSPOOL.@]
8002 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8003 DWORD cbBuf, LPDWORD pcbNeeded)
8005 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8008 /*****************************************************************************
8009 * GetJobW [WINSPOOL.@]
8012 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8013 DWORD cbBuf, LPDWORD pcbNeeded)
8015 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8018 /*****************************************************************************
8019 * schedule_pipe
8021 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8023 #ifdef HAVE_FORK
8024 char *unixname, *cmdA;
8025 DWORD len;
8026 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8027 BOOL ret = FALSE;
8028 char buf[1024];
8029 pid_t pid, wret;
8030 int status;
8032 if(!(unixname = wine_get_unix_file_name(filename)))
8033 return FALSE;
8035 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8036 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8037 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8039 TRACE("printing with: %s\n", cmdA);
8041 if((file_fd = open(unixname, O_RDONLY)) == -1)
8042 goto end;
8044 if (pipe(fds))
8046 ERR("pipe() failed!\n");
8047 goto end;
8050 if ((pid = fork()) == 0)
8052 close(0);
8053 dup2(fds[0], 0);
8054 close(fds[1]);
8056 /* reset signals that we previously set to SIG_IGN */
8057 signal(SIGPIPE, SIG_DFL);
8059 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8060 _exit(1);
8062 else if (pid == -1)
8064 ERR("fork() failed!\n");
8065 goto end;
8068 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8069 write(fds[1], buf, no_read);
8071 close(fds[1]);
8072 fds[1] = -1;
8074 /* reap child */
8075 do {
8076 wret = waitpid(pid, &status, 0);
8077 } while (wret < 0 && errno == EINTR);
8078 if (wret < 0)
8080 ERR("waitpid() failed!\n");
8081 goto end;
8083 if (!WIFEXITED(status) || WEXITSTATUS(status))
8085 ERR("child process failed! %d\n", status);
8086 goto end;
8089 ret = TRUE;
8091 end:
8092 if(file_fd != -1) close(file_fd);
8093 if(fds[0] != -1) close(fds[0]);
8094 if(fds[1] != -1) close(fds[1]);
8096 HeapFree(GetProcessHeap(), 0, cmdA);
8097 HeapFree(GetProcessHeap(), 0, unixname);
8098 return ret;
8099 #else
8100 return FALSE;
8101 #endif
8104 /*****************************************************************************
8105 * schedule_lpr
8107 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8109 WCHAR *cmd;
8110 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8111 BOOL r;
8113 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8114 sprintfW(cmd, fmtW, printer_name);
8116 r = schedule_pipe(cmd, filename);
8118 HeapFree(GetProcessHeap(), 0, cmd);
8119 return r;
8122 #ifdef SONAME_LIBCUPS
8123 /*****************************************************************************
8124 * get_cups_jobs_ticket_options
8126 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8127 * The CUPS scheduler only looks for these in Print-File requests, and since
8128 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8129 * parsed.
8131 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8133 FILE *fp = fopen( file, "r" );
8134 char buf[257]; /* DSC max of 256 + '\0' */
8135 const char *ps_adobe = "%!PS-Adobe-";
8136 const char *cups_job = "%cupsJobTicket:";
8138 if (!fp) return num_options;
8139 if (!fgets( buf, sizeof(buf), fp )) goto end;
8140 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8141 while (fgets( buf, sizeof(buf), fp ))
8143 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8144 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8147 end:
8148 fclose( fp );
8149 return num_options;
8151 #endif
8153 /*****************************************************************************
8154 * schedule_cups
8156 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8158 #ifdef SONAME_LIBCUPS
8159 if(pcupsPrintFile)
8161 char *unixname, *queue, *unix_doc_title;
8162 DWORD len;
8163 BOOL ret;
8164 int num_options = 0, i;
8165 cups_option_t *options = NULL;
8167 if(!(unixname = wine_get_unix_file_name(filename)))
8168 return FALSE;
8170 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8171 queue = HeapAlloc(GetProcessHeap(), 0, len);
8172 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8174 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8175 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8176 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8178 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8180 TRACE( "printing via cups with options:\n" );
8181 for (i = 0; i < num_options; i++)
8182 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8184 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8186 pcupsFreeOptions( num_options, options );
8188 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8189 HeapFree(GetProcessHeap(), 0, queue);
8190 HeapFree(GetProcessHeap(), 0, unixname);
8191 return ret;
8193 else
8194 #endif
8196 return schedule_lpr(printer_name, filename);
8200 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8202 LPWSTR filename;
8204 switch(msg)
8206 case WM_INITDIALOG:
8207 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8208 return TRUE;
8210 case WM_COMMAND:
8211 if(HIWORD(wparam) == BN_CLICKED)
8213 if(LOWORD(wparam) == IDOK)
8215 HANDLE hf;
8216 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8217 LPWSTR *output;
8219 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8220 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8222 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8224 WCHAR caption[200], message[200];
8225 int mb_ret;
8227 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8228 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8229 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8230 if(mb_ret == IDCANCEL)
8232 HeapFree(GetProcessHeap(), 0, filename);
8233 return TRUE;
8236 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8237 if(hf == INVALID_HANDLE_VALUE)
8239 WCHAR caption[200], message[200];
8241 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8242 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8243 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8244 HeapFree(GetProcessHeap(), 0, filename);
8245 return TRUE;
8247 CloseHandle(hf);
8248 DeleteFileW(filename);
8249 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8250 *output = filename;
8251 EndDialog(hwnd, IDOK);
8252 return TRUE;
8254 if(LOWORD(wparam) == IDCANCEL)
8256 EndDialog(hwnd, IDCANCEL);
8257 return TRUE;
8260 return FALSE;
8262 return FALSE;
8265 /*****************************************************************************
8266 * get_filename
8268 static BOOL get_filename(LPWSTR *filename)
8270 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8271 file_dlg_proc, (LPARAM)filename) == IDOK;
8274 /*****************************************************************************
8275 * schedule_file
8277 static BOOL schedule_file(LPCWSTR filename)
8279 LPWSTR output = NULL;
8281 if(get_filename(&output))
8283 BOOL r;
8284 TRACE("copy to %s\n", debugstr_w(output));
8285 r = CopyFileW(filename, output, FALSE);
8286 HeapFree(GetProcessHeap(), 0, output);
8287 return r;
8289 return FALSE;
8292 /*****************************************************************************
8293 * schedule_unixfile
8295 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8297 int in_fd, out_fd, no_read;
8298 char buf[1024];
8299 BOOL ret = FALSE;
8300 char *unixname, *outputA;
8301 DWORD len;
8303 if(!(unixname = wine_get_unix_file_name(filename)))
8304 return FALSE;
8306 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8307 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8308 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8310 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8311 in_fd = open(unixname, O_RDONLY);
8312 if(out_fd == -1 || in_fd == -1)
8313 goto end;
8315 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8316 write(out_fd, buf, no_read);
8318 ret = TRUE;
8319 end:
8320 if(in_fd != -1) close(in_fd);
8321 if(out_fd != -1) close(out_fd);
8322 HeapFree(GetProcessHeap(), 0, outputA);
8323 HeapFree(GetProcessHeap(), 0, unixname);
8324 return ret;
8327 /*****************************************************************************
8328 * ScheduleJob [WINSPOOL.@]
8331 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8333 opened_printer_t *printer;
8334 BOOL ret = FALSE;
8335 struct list *cursor, *cursor2;
8337 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8338 EnterCriticalSection(&printer_handles_cs);
8339 printer = get_opened_printer(hPrinter);
8340 if(!printer)
8341 goto end;
8343 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8345 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8346 HANDLE hf;
8348 if(job->job_id != dwJobID) continue;
8350 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8351 if(hf != INVALID_HANDLE_VALUE)
8353 PRINTER_INFO_5W *pi5 = NULL;
8354 LPWSTR portname = job->portname;
8355 DWORD needed;
8356 HKEY hkey;
8357 WCHAR output[1024];
8358 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8359 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8361 if (!portname)
8363 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8364 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8365 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8366 portname = pi5->pPortName;
8368 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8369 debugstr_w(portname));
8371 output[0] = 0;
8373 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8374 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8376 DWORD type, count = sizeof(output);
8377 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8378 RegCloseKey(hkey);
8380 if(output[0] == '|')
8382 ret = schedule_pipe(output + 1, job->filename);
8384 else if(output[0])
8386 ret = schedule_unixfile(output, job->filename);
8388 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8390 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8392 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8394 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8396 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8398 ret = schedule_file(job->filename);
8400 else
8402 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8404 HeapFree(GetProcessHeap(), 0, pi5);
8405 CloseHandle(hf);
8406 DeleteFileW(job->filename);
8408 list_remove(cursor);
8409 HeapFree(GetProcessHeap(), 0, job->document_title);
8410 HeapFree(GetProcessHeap(), 0, job->printer_name);
8411 HeapFree(GetProcessHeap(), 0, job->portname);
8412 HeapFree(GetProcessHeap(), 0, job->filename);
8413 HeapFree(GetProcessHeap(), 0, job->devmode);
8414 HeapFree(GetProcessHeap(), 0, job);
8415 break;
8417 end:
8418 LeaveCriticalSection(&printer_handles_cs);
8419 return ret;
8422 /*****************************************************************************
8423 * StartDocDlgA [WINSPOOL.@]
8425 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8427 UNICODE_STRING usBuffer;
8428 DOCINFOW docW;
8429 LPWSTR retW;
8430 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8431 LPSTR ret = NULL;
8433 docW.cbSize = sizeof(docW);
8434 if (doc->lpszDocName)
8436 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8437 if (!(docW.lpszDocName = docnameW)) return NULL;
8439 if (doc->lpszOutput)
8441 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8442 if (!(docW.lpszOutput = outputW)) return NULL;
8444 if (doc->lpszDatatype)
8446 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8447 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8449 docW.fwType = doc->fwType;
8451 retW = StartDocDlgW(hPrinter, &docW);
8453 if(retW)
8455 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8456 ret = HeapAlloc(GetProcessHeap(), 0, len);
8457 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8458 HeapFree(GetProcessHeap(), 0, retW);
8461 HeapFree(GetProcessHeap(), 0, datatypeW);
8462 HeapFree(GetProcessHeap(), 0, outputW);
8463 HeapFree(GetProcessHeap(), 0, docnameW);
8465 return ret;
8468 /*****************************************************************************
8469 * StartDocDlgW [WINSPOOL.@]
8471 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8472 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8473 * port is "FILE:". Also returns the full path if passed a relative path.
8475 * The caller should free the returned string from the process heap.
8477 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8479 LPWSTR ret = NULL;
8480 DWORD len, attr;
8482 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8484 PRINTER_INFO_5W *pi5;
8485 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8486 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8487 return NULL;
8488 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8489 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8490 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8492 HeapFree(GetProcessHeap(), 0, pi5);
8493 return NULL;
8495 HeapFree(GetProcessHeap(), 0, pi5);
8498 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8500 LPWSTR name;
8502 if (get_filename(&name))
8504 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8506 HeapFree(GetProcessHeap(), 0, name);
8507 return NULL;
8509 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8510 GetFullPathNameW(name, len, ret, NULL);
8511 HeapFree(GetProcessHeap(), 0, name);
8513 return ret;
8516 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8517 return NULL;
8519 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8520 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8522 attr = GetFileAttributesW(ret);
8523 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8525 HeapFree(GetProcessHeap(), 0, ret);
8526 ret = NULL;
8528 return ret;