winevulkan: Update to VK spec version 1.2.195.
[wine.git] / dlls / winspool.drv / info.c
blobedfdab218c444d77f89a594b20cfdc344d1ca5ce
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
47 #ifdef HAVE_CUPS_PPD_H
48 # include <cups/ppd.h>
49 #endif
51 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
52 #define GetCurrentProcess GetCurrentProcess_Mac
53 #define GetCurrentThread GetCurrentThread_Mac
54 #define LoadResource LoadResource_Mac
55 #define AnimatePalette AnimatePalette_Mac
56 #define EqualRgn EqualRgn_Mac
57 #define FillRgn FillRgn_Mac
58 #define FrameRgn FrameRgn_Mac
59 #define GetPixel GetPixel_Mac
60 #define InvertRgn InvertRgn_Mac
61 #define LineTo LineTo_Mac
62 #define OffsetRgn OffsetRgn_Mac
63 #define PaintRgn PaintRgn_Mac
64 #define Polygon Polygon_Mac
65 #define ResizePalette ResizePalette_Mac
66 #define SetRectRgn SetRectRgn_Mac
67 #define EqualRect EqualRect_Mac
68 #define FillRect FillRect_Mac
69 #define FrameRect FrameRect_Mac
70 #define GetCursor GetCursor_Mac
71 #define InvertRect InvertRect_Mac
72 #define OffsetRect OffsetRect_Mac
73 #define PtInRect PtInRect_Mac
74 #define SetCursor SetCursor_Mac
75 #define SetRect SetRect_Mac
76 #define ShowCursor ShowCursor_Mac
77 #define UnionRect UnionRect_Mac
78 #include <ApplicationServices/ApplicationServices.h>
79 #undef GetCurrentProcess
80 #undef GetCurrentThread
81 #undef LoadResource
82 #undef AnimatePalette
83 #undef EqualRgn
84 #undef FillRgn
85 #undef FrameRgn
86 #undef GetPixel
87 #undef InvertRgn
88 #undef LineTo
89 #undef OffsetRgn
90 #undef PaintRgn
91 #undef Polygon
92 #undef ResizePalette
93 #undef SetRectRgn
94 #undef EqualRect
95 #undef FillRect
96 #undef FrameRect
97 #undef GetCursor
98 #undef InvertRect
99 #undef OffsetRect
100 #undef PtInRect
101 #undef SetCursor
102 #undef SetRect
103 #undef ShowCursor
104 #undef UnionRect
105 #endif
107 #define NONAMELESSSTRUCT
108 #define NONAMELESSUNION
110 #include "windef.h"
111 #include "winbase.h"
112 #include "winuser.h"
113 #include "winerror.h"
114 #include "winreg.h"
115 #include "wingdi.h"
116 #include "winspool.h"
117 #include "winternl.h"
118 #include "wine/windef16.h"
119 #include "wine/unicode.h"
120 #include "wine/debug.h"
121 #include "wine/list.h"
122 #include "wine/rbtree.h"
123 #include "wine/heap.h"
124 #include "winnls.h"
126 #include "ddk/winsplp.h"
127 #include "wspool.h"
129 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
131 /* ############################### */
133 static CRITICAL_SECTION printer_handles_cs;
134 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
136 0, 0, &printer_handles_cs,
137 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
138 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
140 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
142 /* ############################### */
144 typedef struct {
145 DWORD job_id;
146 HANDLE hf;
147 } started_doc_t;
149 typedef struct {
150 struct list jobs;
151 LONG ref;
152 } jobqueue_t;
154 typedef struct {
155 LPWSTR name;
156 LPWSTR printername;
157 HANDLE backend_printer;
158 jobqueue_t *queue;
159 started_doc_t *doc;
160 DEVMODEW *devmode;
161 } opened_printer_t;
163 typedef struct {
164 struct list entry;
165 DWORD job_id;
166 WCHAR *filename;
167 WCHAR *portname;
168 WCHAR *document_title;
169 WCHAR *printer_name;
170 LPDEVMODEW devmode;
171 } job_t;
174 typedef struct {
175 LPCWSTR envname;
176 LPCWSTR subdir;
177 DWORD driverversion;
178 LPCWSTR versionregpath;
179 LPCWSTR versionsubdir;
180 } printenv_t;
182 typedef struct
184 struct wine_rb_entry entry;
185 HMODULE module;
186 LONG ref;
188 /* entry points */
189 DWORD (WINAPI *pDrvDeviceCapabilities)(HANDLE, const WCHAR *, WORD, void *, const DEVMODEW *);
190 INT (WINAPI *pDrvDocumentProperties)(HWND, const WCHAR *, DEVMODEW *, DEVMODEW *, DWORD);
192 WCHAR name[1];
193 } config_module_t;
195 /* ############################### */
197 static opened_printer_t **printer_handles;
198 static UINT nb_printer_handles;
199 static LONG next_job_id = 1;
201 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
202 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
203 'c','o','n','t','r','o','l','\\',
204 'P','r','i','n','t','\\',
205 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
206 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
208 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
209 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
210 'C','o','n','t','r','o','l','\\',
211 'P','r','i','n','t','\\',
212 'P','r','i','n','t','e','r','s',0};
214 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
215 'M','i','c','r','o','s','o','f','t','\\',
216 'W','i','n','d','o','w','s',' ','N','T','\\',
217 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
218 'W','i','n','d','o','w','s',0};
220 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
221 'M','i','c','r','o','s','o','f','t','\\',
222 'W','i','n','d','o','w','s',' ','N','T','\\',
223 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
224 'D','e','v','i','c','e','s',0};
226 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
227 'M','i','c','r','o','s','o','f','t','\\',
228 'W','i','n','d','o','w','s',' ','N','T','\\',
229 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
230 'P','r','i','n','t','e','r','P','o','r','t','s',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 AttributesW[] = {'A','t','t','r','i','b','u','t','e','s',0};
244 static const WCHAR backslashW[] = {'\\',0};
245 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
246 'i','o','n',' ','F','i','l','e',0};
247 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
248 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
249 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
250 static const WCHAR Default_PriorityW[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
251 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
252 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
253 static const WCHAR dnsTimeoutW[] = {'d','n','s','T','i','m','e','o','u','t',0};
254 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
255 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
256 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
257 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
258 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
259 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
260 static const WCHAR NameW[] = {'N','a','m','e',0};
261 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
262 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
263 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
264 static const WCHAR PortW[] = {'P','o','r','t',0};
265 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
266 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
267 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
268 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
269 static const WCHAR PriorityW[] = {'P','r','i','o','r','i','t','y',0};
270 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
271 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
272 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
273 static const WCHAR StartTimeW[] = {'S','t','a','r','t','T','i','m','e',0};
274 static const WCHAR StatusW[] = {'S','t','a','t','u','s',0};
275 static const WCHAR txTimeoutW[] = {'t','x','T','i','m','e','o','u','t',0};
276 static const WCHAR UntilTimeW[] = {'U','n','t','i','l','T','i','m','e',0};
277 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
278 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
279 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
280 static WCHAR rawW[] = {'R','A','W',0};
281 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
282 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
283 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
284 static const WCHAR commaW[] = {',',0};
285 static WCHAR emptyStringW[] = {0};
287 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
289 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
290 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
291 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
293 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
294 'D','o','c','u','m','e','n','t',0};
296 static const WCHAR PPD_Overrides[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
297 static const WCHAR DefaultPageSize[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
299 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
300 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
301 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
302 0, sizeof(DRIVER_INFO_8W)};
305 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
306 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
307 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
308 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
309 sizeof(PRINTER_INFO_9W)};
311 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
312 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
313 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
315 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
317 /******************************************************************
318 * validate the user-supplied printing-environment [internal]
320 * PARAMS
321 * env [I] PTR to Environment-String or NULL
323 * RETURNS
324 * Failure: NULL
325 * Success: PTR to printenv_t
327 * NOTES
328 * An empty string is handled the same way as NULL.
329 * SetLastError(ERROR_INVALID_ENVIRONMENT) is called on Failure
333 static const printenv_t * validate_envW(LPCWSTR env)
335 const printenv_t *result = NULL;
336 unsigned int i;
338 TRACE("testing %s\n", debugstr_w(env));
339 if (env && env[0])
341 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
343 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
345 result = all_printenv[i];
346 break;
350 if (result == NULL) {
351 FIXME("unsupported Environment: %s\n", debugstr_w(env));
352 SetLastError(ERROR_INVALID_ENVIRONMENT);
354 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
356 else
358 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
360 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
362 return result;
366 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
367 if passed a NULL string. This returns NULLs to the result.
369 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
371 if ( (src) )
373 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
374 return usBufferPtr->Buffer;
376 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
377 return NULL;
380 static LPWSTR strdupW(LPCWSTR p)
382 LPWSTR ret;
383 DWORD len;
385 if(!p) return NULL;
386 len = (strlenW(p) + 1) * sizeof(WCHAR);
387 ret = HeapAlloc(GetProcessHeap(), 0, len);
388 memcpy(ret, p, len);
389 return ret;
392 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
394 DEVMODEW *ret;
396 if (!dm) return NULL;
397 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
398 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
399 return ret;
402 /***********************************************************
403 * DEVMODEdupWtoA
404 * Creates an ansi copy of supplied devmode
406 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
408 LPDEVMODEA dmA;
409 DWORD size;
411 if (!dmW) return NULL;
412 size = dmW->dmSize - CCHDEVICENAME -
413 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
415 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
416 if (!dmA) return NULL;
418 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
419 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
421 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
423 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
424 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
426 else
428 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
429 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
430 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
431 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
433 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
436 dmA->dmSize = size;
437 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
438 return dmA;
441 static void packed_string_WtoA( WCHAR *strW )
443 DWORD len = strlenW( strW ), size = (len + 1) * sizeof(WCHAR), ret;
444 char *str;
446 if (!len) return;
447 str = heap_alloc( size );
448 ret = WideCharToMultiByte( CP_ACP, 0, strW, len, str, size - 1, NULL, NULL );
449 memcpy( strW, str, ret );
450 memset( (BYTE *)strW + ret, 0, size - ret );
451 heap_free( str );
454 /*********************************************************************
455 * packed_struct_WtoA
457 * Convert a packed struct from W to A overwriting the unicode strings
458 * with their ansi equivalents.
460 static void packed_struct_WtoA( BYTE *data, const DWORD *string_info )
462 WCHAR *strW;
464 string_info++; /* sizeof */
465 while (*string_info != ~0u)
467 strW = *(WCHAR **)(data + *string_info);
468 if (strW) packed_string_WtoA( strW );
469 string_info++;
473 static inline const DWORD *form_string_info( DWORD level )
475 static const DWORD info_1[] =
477 sizeof( FORM_INFO_1W ),
478 FIELD_OFFSET( FORM_INFO_1W, pName ),
481 static const DWORD info_2[] =
483 sizeof( FORM_INFO_2W ),
484 FIELD_OFFSET( FORM_INFO_2W, pName ),
485 FIELD_OFFSET( FORM_INFO_2W, pMuiDll ),
486 FIELD_OFFSET( FORM_INFO_2W, pDisplayName ),
490 if (level == 1) return info_1;
491 if (level == 2) return info_2;
493 SetLastError( ERROR_INVALID_LEVEL );
494 return NULL;
497 /*****************************************************************************
498 * WINSPOOL_OpenDriverReg [internal]
500 * opens the registry for the printer drivers depending on the given input
501 * variable pEnvironment
503 * RETURNS:
504 * the opened hkey on success
505 * NULL on error
507 static HKEY WINSPOOL_OpenDriverReg(const void *pEnvironment)
509 HKEY retval = NULL;
510 LPWSTR buffer;
511 const printenv_t *env;
513 TRACE("(%s)\n", debugstr_w(pEnvironment));
515 env = validate_envW(pEnvironment);
516 if (!env) return NULL;
518 buffer = HeapAlloc( GetProcessHeap(), 0,
519 (strlenW(DriversW) + strlenW(env->envname) +
520 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
521 if(buffer) {
522 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
523 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
524 HeapFree(GetProcessHeap(), 0, buffer);
526 return retval;
529 static CRITICAL_SECTION config_modules_cs;
530 static CRITICAL_SECTION_DEBUG config_modules_cs_debug =
532 0, 0, &config_modules_cs,
533 { &config_modules_cs_debug.ProcessLocksList, &config_modules_cs_debug.ProcessLocksList },
534 0, 0, { (DWORD_PTR)(__FILE__ ": config_modules_cs") }
536 static CRITICAL_SECTION config_modules_cs = { &config_modules_cs_debug, -1, 0, 0, 0, 0 };
538 static int compare_config_modules(const void *key, const struct wine_rb_entry *entry)
540 config_module_t *module = WINE_RB_ENTRY_VALUE(entry, config_module_t, entry);
541 return lstrcmpiW(key, module->name);
544 static struct wine_rb_tree config_modules = { compare_config_modules };
546 static void release_config_module(config_module_t *config_module)
548 if (InterlockedDecrement(&config_module->ref)) return;
549 FreeLibrary(config_module->module);
550 HeapFree(GetProcessHeap(), 0, config_module);
553 static config_module_t *get_config_module(const WCHAR *device, BOOL grab)
555 WCHAR driver[MAX_PATH];
556 DWORD size, len;
557 HKEY driver_key, device_key;
558 HMODULE driver_module;
559 config_module_t *ret = NULL;
560 struct wine_rb_entry *entry;
561 DWORD type;
562 LSTATUS res;
564 EnterCriticalSection(&config_modules_cs);
565 entry = wine_rb_get(&config_modules, device);
566 if (entry) {
567 ret = WINE_RB_ENTRY_VALUE(entry, config_module_t, entry);
568 if (grab) InterlockedIncrement(&ret->ref);
569 goto ret;
571 if (!grab) goto ret;
573 if (!(driver_key = WINSPOOL_OpenDriverReg(NULL))) goto ret;
575 res = RegOpenKeyW(driver_key, device, &device_key);
576 RegCloseKey(driver_key);
577 if (res) {
578 WARN("Device %s key not found\n", debugstr_w(device));
579 goto ret;
582 size = sizeof(driver);
583 if (!GetPrinterDriverDirectoryW(NULL, NULL, 1, (LPBYTE)driver, size, &size)) goto ret;
585 len = size / sizeof(WCHAR) - 1;
586 driver[len++] = '\\';
587 driver[len++] = '3';
588 driver[len++] = '\\';
589 size = sizeof(driver) - len * sizeof(WCHAR);
590 res = RegQueryValueExW(device_key, Configuration_FileW, NULL, &type,
591 (BYTE *)(driver + len), &size);
592 RegCloseKey(device_key);
593 if (res || type != REG_SZ) {
594 WARN("no configuration file: %u\n", res);
595 goto ret;
598 if (!(driver_module = LoadLibraryW(driver))) {
599 WARN("Could not load %s\n", debugstr_w(driver));
600 goto ret;
603 len = lstrlenW(device);
604 if (!(ret = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(config_module_t, name[len + 1]))))
605 goto ret;
607 ret->ref = 2; /* one for config_module and one for the caller */
608 ret->module = driver_module;
609 ret->pDrvDeviceCapabilities = (void *)GetProcAddress(driver_module, "DrvDeviceCapabilities");
610 ret->pDrvDocumentProperties = (void *)GetProcAddress(driver_module, "DrvDocumentProperties");
611 lstrcpyW(ret->name, device);
613 wine_rb_put(&config_modules, ret->name, &ret->entry);
614 ret:
615 LeaveCriticalSection(&config_modules_cs);
616 return ret;
619 /******************************************************************
620 * verify, that the filename is a local file
623 static inline BOOL is_local_file(LPWSTR name)
625 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
628 /* ################################ */
630 static int multi_sz_lenA(const char *str)
632 const char *ptr = str;
633 if(!str) return 0;
636 ptr += lstrlenA(ptr) + 1;
637 } while(*ptr);
639 return ptr - str + 1;
642 /*****************************************************************************
643 * get_dword_from_reg
645 * Return DWORD associated with name from hkey.
647 static DWORD get_dword_from_reg( HKEY hkey, const WCHAR *name )
649 DWORD sz = sizeof(DWORD), type, value = 0;
650 LONG ret;
652 ret = RegQueryValueExW( hkey, name, 0, &type, (LPBYTE)&value, &sz );
654 if (ret != ERROR_SUCCESS)
656 WARN( "Got ret = %d on name %s\n", ret, debugstr_w(name) );
657 return 0;
659 if (type != REG_DWORD)
661 ERR( "Got type %d\n", type );
662 return 0;
664 return value;
667 static inline DWORD set_reg_DWORD( HKEY hkey, const WCHAR *keyname, const DWORD value )
669 return RegSetValueExW( hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value) );
672 /******************************************************************
673 * get_opened_printer
674 * Get the pointer to the opened printer referred by the handle
676 static opened_printer_t *get_opened_printer(HANDLE hprn)
678 UINT_PTR idx = (UINT_PTR)hprn;
679 opened_printer_t *ret = NULL;
681 EnterCriticalSection(&printer_handles_cs);
683 if ((idx > 0) && (idx <= nb_printer_handles)) {
684 ret = printer_handles[idx - 1];
686 LeaveCriticalSection(&printer_handles_cs);
687 return ret;
690 /******************************************************************
691 * get_opened_printer_name
692 * Get the pointer to the opened printer name referred by the handle
694 static LPCWSTR get_opened_printer_name(HANDLE hprn)
696 opened_printer_t *printer = get_opened_printer(hprn);
697 if(!printer) return NULL;
698 return printer->name;
701 static HANDLE get_backend_handle( HANDLE hprn )
703 opened_printer_t *printer = get_opened_printer( hprn );
704 if (!printer) return NULL;
705 return printer->backend_printer;
708 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
710 HKEY printers;
711 DWORD err;
713 *key = NULL;
714 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
715 if (err) return err;
717 err = RegOpenKeyW( printers, name, key );
718 if (err) err = ERROR_INVALID_PRINTER_NAME;
719 RegCloseKey( printers );
720 return err;
723 /******************************************************************
724 * WINSPOOL_GetOpenedPrinterRegKey
727 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
729 LPCWSTR name = get_opened_printer_name(hPrinter);
731 if(!name) return ERROR_INVALID_HANDLE;
732 return open_printer_reg_key( name, phkey );
735 static void set_default_printer(const char *devname, const char *name)
737 char *buf = HeapAlloc(GetProcessHeap(), 0, strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
738 HKEY hkey;
740 sprintf(buf, "%s,WINEPS.DRV,LPR:%s", devname, name);
741 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey))
743 RegSetValueExA(hkey, "Device", 0, REG_SZ, (BYTE *)buf, strlen(buf) + 1);
744 RegCloseKey(hkey);
746 HeapFree(GetProcessHeap(), 0, buf);
749 static BOOL add_printer_driver(const WCHAR *name, WCHAR *ppd)
751 DRIVER_INFO_3W di3;
752 unsigned int i;
753 BOOL res;
755 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
756 di3.cVersion = 3;
757 di3.pName = (WCHAR*)name;
758 di3.pDriverPath = driver_nt;
759 di3.pDataFile = ppd;
760 di3.pConfigFile = driver_nt;
761 di3.pDefaultDataType = rawW;
763 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
765 di3.pEnvironment = (WCHAR *) all_printenv[i]->envname;
766 if (all_printenv[i]->envname == envname_win40W)
768 /* We use wineps16.drv as driver for 16 bit */
769 di3.pDriverPath = driver_9x;
770 di3.pConfigFile = driver_9x;
772 res = AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY );
773 TRACE("got %d and %d for %s (%s)\n", res, GetLastError(), debugstr_w(name), debugstr_w(di3.pEnvironment));
775 if (!res && (GetLastError() != ERROR_PRINTER_DRIVER_ALREADY_INSTALLED))
777 ERR("failed with %u for %s (%s) %s\n", GetLastError(), debugstr_w(name),
778 debugstr_w(di3.pEnvironment), debugstr_w(di3.pDriverPath));
779 return FALSE;
783 return TRUE;
786 static inline char *expand_env_string( char *str, DWORD type )
788 if (type == REG_EXPAND_SZ)
790 char *tmp;
791 DWORD needed = ExpandEnvironmentStringsA( str, NULL, 0 );
792 tmp = HeapAlloc( GetProcessHeap(), 0, needed );
793 if (tmp)
795 ExpandEnvironmentStringsA( str, tmp, needed );
796 HeapFree( GetProcessHeap(), 0, str );
797 return tmp;
800 return str;
803 static char *get_fallback_ppd_name( const char *printer_name )
805 static const WCHAR ppds_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
806 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
807 HKEY hkey;
808 DWORD needed, type;
809 char *ret = NULL;
811 if (RegOpenKeyW( HKEY_CURRENT_USER, ppds_key, &hkey ) == ERROR_SUCCESS )
813 const char *value_name = NULL;
815 if (RegQueryValueExA( hkey, printer_name, 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
816 value_name = printer_name;
817 else if (RegQueryValueExA( hkey, "generic", 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
818 value_name = "generic";
820 if (value_name)
822 ret = HeapAlloc( GetProcessHeap(), 0, needed );
823 if (!ret) return NULL;
824 RegQueryValueExA( hkey, value_name, 0, &type, (BYTE *)ret, &needed );
826 RegCloseKey( hkey );
827 if (ret) return expand_env_string( ret, type );
829 return NULL;
832 static BOOL copy_file( const char *src, const char *dst )
834 int fds[2] = {-1, -1}, num;
835 char buf[1024];
836 BOOL ret = FALSE;
838 fds[0] = open( src, O_RDONLY );
839 fds[1] = open( dst, O_CREAT | O_TRUNC | O_WRONLY, 0666 );
840 if (fds[0] == -1 || fds[1] == -1) goto fail;
842 while ((num = read( fds[0], buf, sizeof(buf) )) != 0)
844 if (num == -1) goto fail;
845 if (write( fds[1], buf, num ) != num) goto fail;
847 ret = TRUE;
849 fail:
850 if (fds[1] != -1) close( fds[1] );
851 if (fds[0] != -1) close( fds[0] );
852 return ret;
855 static BOOL get_internal_fallback_ppd( const WCHAR *ppd )
857 static const WCHAR typeW[] = {'P','P','D','F','I','L','E',0};
859 char *ptr, *end;
860 DWORD size, written;
861 HANDLE file;
862 BOOL ret;
863 HRSRC res = FindResourceW( WINSPOOL_hInstance, MAKEINTRESOURCEW(1), typeW );
865 if (!res || !(ptr = LoadResource( WINSPOOL_hInstance, res ))) return FALSE;
866 size = SizeofResource( WINSPOOL_hInstance, res );
867 end = memchr( ptr, 0, size ); /* resource file may contain additional nulls */
868 if (end) size = end - ptr;
869 file = CreateFileW( ppd, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0 );
870 if (file == INVALID_HANDLE_VALUE) return FALSE;
871 ret = WriteFile( file, ptr, size, &written, NULL ) && written == size;
872 CloseHandle( file );
873 if (ret) TRACE( "using internal fallback for %s\n", debugstr_w( ppd ));
874 else DeleteFileW( ppd );
875 return ret;
878 static BOOL get_fallback_ppd( const char *printer_name, const WCHAR *ppd )
880 char *dst, *src = get_fallback_ppd_name( printer_name );
881 BOOL ret = FALSE;
883 if (!src) return get_internal_fallback_ppd( ppd );
885 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name), debugstr_w(ppd), debugstr_a(src) );
887 if (!(dst = wine_get_unix_file_name( ppd ))) goto fail;
889 if (symlink( src, dst ) == -1)
890 if (errno != ENOSYS || !copy_file( src, dst ))
891 goto fail;
893 ret = TRUE;
894 fail:
895 HeapFree( GetProcessHeap(), 0, dst );
896 HeapFree( GetProcessHeap(), 0, src );
897 return ret;
900 static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
902 static const WCHAR dot_ppd[] = {'.','p','p','d',0};
903 static const WCHAR invalid_chars[] = {'*','?','<','>','|','"','/','\\',0};
904 int dir_len = strlenW( dir ), file_len = strlenW( file_name );
905 int len = (dir_len + file_len + ARRAY_SIZE( dot_ppd )) * sizeof(WCHAR);
906 WCHAR *ppd = HeapAlloc( GetProcessHeap(), 0, len ), *p;
908 if (!ppd) return NULL;
909 memcpy( ppd, dir, dir_len * sizeof(WCHAR) );
910 memcpy( ppd + dir_len, file_name, file_len * sizeof(WCHAR) );
911 memcpy( ppd + dir_len + file_len, dot_ppd, sizeof(dot_ppd) );
913 p = ppd + dir_len;
914 while ((p = strpbrkW( p, invalid_chars ))) *p++ = '_';
916 return ppd;
919 static WCHAR *get_ppd_dir( void )
921 static const WCHAR wine_ppds[] = {'w','i','n','e','_','p','p','d','s','\\',0};
922 DWORD len;
923 WCHAR *dir, tmp_path[MAX_PATH];
924 BOOL res;
926 len = GetTempPathW( ARRAY_SIZE( tmp_path ), tmp_path );
927 if (!len) return NULL;
928 dir = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
929 if (!dir) return NULL;
931 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
932 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
933 res = CreateDirectoryW( dir, NULL );
934 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
936 HeapFree( GetProcessHeap(), 0, dir );
937 dir = NULL;
939 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
940 return dir;
943 static void unlink_ppd( const WCHAR *ppd )
945 char *unix_name = wine_get_unix_file_name( ppd );
946 unlink( unix_name );
947 HeapFree( GetProcessHeap(), 0, unix_name );
950 #ifdef SONAME_LIBCUPS
952 static void *cupshandle;
954 #define CUPS_FUNCS \
955 DO_FUNC(cupsAddOption); \
956 DO_FUNC(cupsFreeDests); \
957 DO_FUNC(cupsFreeOptions); \
958 DO_FUNC(cupsGetDests); \
959 DO_FUNC(cupsGetOption); \
960 DO_FUNC(cupsParseOptions); \
961 DO_FUNC(cupsPrintFile)
962 #define CUPS_OPT_FUNCS \
963 DO_FUNC(cupsGetNamedDest); \
964 DO_FUNC(cupsGetPPD); \
965 DO_FUNC(cupsGetPPD3); \
966 DO_FUNC(cupsLastErrorString)
968 #define DO_FUNC(f) static typeof(f) *p##f
969 CUPS_FUNCS;
970 #undef DO_FUNC
971 static cups_dest_t * (*pcupsGetNamedDest)(http_t *, const char *, const char *);
972 static const char * (*pcupsGetPPD)(const char *);
973 static http_status_t (*pcupsGetPPD3)(http_t *, const char *, time_t *, char *, size_t);
974 static const char * (*pcupsLastErrorString)(void);
976 static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name,
977 time_t *modtime, char *buffer,
978 size_t bufsize )
980 const char *ppd;
982 if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
984 if (!pcupsGetPPD) return HTTP_NOT_FOUND;
986 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
988 *modtime = 0;
989 ppd = pcupsGetPPD( name );
991 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
993 if (!ppd) return HTTP_NOT_FOUND;
995 if (rename( ppd, buffer ) == -1)
997 BOOL res = copy_file( ppd, buffer );
998 unlink( ppd );
999 if (!res) return HTTP_NOT_FOUND;
1001 return HTTP_OK;
1004 static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
1006 time_t modtime = 0;
1007 http_status_t http_status;
1008 char *unix_name = wine_get_unix_file_name( ppd );
1010 TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
1012 if (!unix_name) return FALSE;
1014 http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
1015 unix_name, strlen( unix_name ) + 1 );
1017 if (http_status != HTTP_OK) unlink( unix_name );
1018 HeapFree( GetProcessHeap(), 0, unix_name );
1020 if (http_status == HTTP_OK) return TRUE;
1022 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
1023 debugstr_a(printer_name), http_status );
1024 return get_fallback_ppd( printer_name, ppd );
1027 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
1029 const char *value;
1030 WCHAR *ret;
1031 int len;
1033 value = pcupsGetOption( name, num_options, options );
1034 if (!value) return NULL;
1036 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
1037 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1038 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
1040 return ret;
1043 static cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
1045 WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
1046 cups_ptype_t ret = 0;
1048 if (type && *type)
1050 ret = (cups_ptype_t)strtoulW( type, &end, 10 );
1051 if (*end) ret = 0;
1053 HeapFree( GetProcessHeap(), 0, type );
1054 return ret;
1057 static void load_cups(void)
1059 cupshandle = dlopen( SONAME_LIBCUPS, RTLD_NOW );
1060 if (!cupshandle) return;
1062 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
1064 #define DO_FUNC(x) \
1065 p##x = dlsym( cupshandle, #x ); \
1066 if (!p##x) \
1068 ERR("failed to load symbol %s\n", #x); \
1069 cupshandle = NULL; \
1070 return; \
1072 CUPS_FUNCS;
1073 #undef DO_FUNC
1074 #define DO_FUNC(x) p##x = dlsym( cupshandle, #x )
1075 CUPS_OPT_FUNCS;
1076 #undef DO_FUNC
1079 static BOOL CUPS_LoadPrinters(void)
1081 int i, nrofdests;
1082 BOOL hadprinter = FALSE, haddefault = FALSE;
1083 cups_dest_t *dests;
1084 PRINTER_INFO_2W pi2;
1085 WCHAR *port, *ppd_dir = NULL, *ppd;
1086 HKEY hkeyPrinter, hkeyPrinters;
1087 WCHAR nameW[MAX_PATH];
1088 HANDLE added_printer;
1089 cups_ptype_t printer_type;
1091 if (!cupshandle) return FALSE;
1093 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1094 ERROR_SUCCESS) {
1095 ERR("Can't create Printers key\n");
1096 return FALSE;
1099 nrofdests = pcupsGetDests(&dests);
1100 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
1101 for (i=0;i<nrofdests;i++) {
1102 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, ARRAY_SIZE(nameW));
1103 printer_type = get_cups_printer_type( dests + i );
1105 TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
1107 if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
1109 TRACE( "skipping scanner-only device\n" );
1110 continue;
1113 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
1114 lstrcpyW(port, CUPS_Port);
1115 lstrcatW(port, nameW);
1117 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
1118 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1119 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1120 and continue */
1121 TRACE("Printer already exists\n");
1122 /* overwrite old LPR:* port */
1123 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
1124 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1125 /* flag that the PPD file should be checked for an update */
1126 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1127 RegCloseKey(hkeyPrinter);
1128 } else {
1129 BOOL added_driver = FALSE;
1131 if (!ppd_dir && !(ppd_dir = get_ppd_dir()))
1133 HeapFree( GetProcessHeap(), 0, port );
1134 break;
1136 ppd = get_ppd_filename( ppd_dir, nameW );
1137 if (get_cups_ppd( dests[i].name, ppd ))
1139 added_driver = add_printer_driver( nameW, ppd );
1140 unlink_ppd( ppd );
1142 HeapFree( GetProcessHeap(), 0, ppd );
1143 if (!added_driver)
1145 HeapFree( GetProcessHeap(), 0, port );
1146 continue;
1149 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
1150 pi2.pPrinterName = nameW;
1151 pi2.pDatatype = rawW;
1152 pi2.pPrintProcessor = WinPrintW;
1153 pi2.pDriverName = nameW;
1154 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
1155 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
1156 pi2.pPortName = port;
1157 pi2.pParameters = emptyStringW;
1158 pi2.pShareName = emptyStringW;
1159 pi2.pSepFile = emptyStringW;
1161 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
1162 if (added_printer) ClosePrinter( added_printer );
1163 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1164 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
1166 HeapFree( GetProcessHeap(), 0, pi2.pComment );
1167 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
1169 HeapFree( GetProcessHeap(), 0, port );
1171 hadprinter = TRUE;
1172 if (dests[i].is_default) {
1173 SetDefaultPrinterW(nameW);
1174 haddefault = TRUE;
1178 if (ppd_dir)
1180 RemoveDirectoryW( ppd_dir );
1181 HeapFree( GetProcessHeap(), 0, ppd_dir );
1184 if (hadprinter && !haddefault) {
1185 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, ARRAY_SIZE(nameW));
1186 SetDefaultPrinterW(nameW);
1188 pcupsFreeDests(nrofdests, dests);
1189 RegCloseKey(hkeyPrinters);
1190 return TRUE;
1193 #endif
1195 static char *get_queue_name( HANDLE printer, BOOL *cups )
1197 WCHAR *port, *name = NULL;
1198 DWORD err, needed, type;
1199 char *ret = NULL;
1200 HKEY key;
1202 *cups = FALSE;
1204 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1205 if (err) return NULL;
1206 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1207 if (err) goto end;
1208 port = HeapAlloc( GetProcessHeap(), 0, needed );
1209 if (!port) goto end;
1210 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1212 if (!strncmpW( port, CUPS_Port, ARRAY_SIZE( CUPS_Port ) -1 ))
1214 name = port + ARRAY_SIZE( CUPS_Port ) - 1;
1215 *cups = TRUE;
1217 else if (!strncmpW( port, LPR_Port, ARRAY_SIZE( LPR_Port ) -1 ))
1218 name = port + ARRAY_SIZE( LPR_Port ) - 1;
1219 if (name)
1221 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1222 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1223 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1225 HeapFree( GetProcessHeap(), 0, port );
1226 end:
1227 RegCloseKey( key );
1228 return ret;
1232 static void set_ppd_overrides( HANDLE printer )
1234 WCHAR *wstr = NULL;
1235 int size = 0;
1236 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1237 OSStatus status;
1238 PMPrintSession session = NULL;
1239 PMPageFormat format = NULL;
1240 PMPaper paper;
1241 CFStringRef paper_name;
1242 CFRange range;
1244 status = PMCreateSession( &session );
1245 if (status) goto end;
1247 status = PMCreatePageFormat( &format );
1248 if (status) goto end;
1250 status = PMSessionDefaultPageFormat( session, format );
1251 if (status) goto end;
1253 status = PMGetPageFormatPaper( format, &paper );
1254 if (status) goto end;
1256 status = PMPaperGetPPDPaperName( paper, &paper_name );
1257 if (status) goto end;
1259 range.location = 0;
1260 range.length = CFStringGetLength( paper_name );
1261 size = (range.length + 1) * sizeof(WCHAR);
1263 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1264 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1265 wstr[range.length] = 0;
1267 end:
1268 if (format) PMRelease( format );
1269 if (session) PMRelease( session );
1270 #endif
1272 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1273 HeapFree( GetProcessHeap(), 0, wstr );
1276 static BOOL update_driver( HANDLE printer )
1278 BOOL ret, is_cups;
1279 const WCHAR *name = get_opened_printer_name( printer );
1280 WCHAR *ppd_dir, *ppd;
1281 char *queue_name;
1283 if (!name) return FALSE;
1284 queue_name = get_queue_name( printer, &is_cups );
1285 if (!queue_name) return FALSE;
1287 if (!(ppd_dir = get_ppd_dir()))
1289 HeapFree( GetProcessHeap(), 0, queue_name );
1290 return FALSE;
1292 ppd = get_ppd_filename( ppd_dir, name );
1294 #ifdef SONAME_LIBCUPS
1295 if (is_cups)
1296 ret = get_cups_ppd( queue_name, ppd );
1297 else
1298 #endif
1299 ret = get_fallback_ppd( queue_name, ppd );
1301 if (ret)
1303 TRACE( "updating driver %s\n", debugstr_w( name ) );
1304 ret = add_printer_driver( name, ppd );
1305 unlink_ppd( ppd );
1307 HeapFree( GetProcessHeap(), 0, ppd_dir );
1308 HeapFree( GetProcessHeap(), 0, ppd );
1309 HeapFree( GetProcessHeap(), 0, queue_name );
1311 set_ppd_overrides( printer );
1313 /* call into the driver to update the devmode */
1314 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1316 return ret;
1319 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1321 PRINTER_INFO_2A pinfo2a;
1322 const char *r;
1323 size_t name_len;
1324 char *e,*s,*name,*prettyname,*devname;
1325 BOOL ret = FALSE, set_default = FALSE;
1326 char *port = NULL, *env_default;
1327 HKEY hkeyPrinter, hkeyPrinters = NULL;
1328 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1329 HANDLE added_printer;
1331 while (isspace(*pent)) pent++;
1332 r = strchr(pent,':');
1333 if (r)
1334 name_len = r - pent;
1335 else
1336 name_len = strlen(pent);
1337 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1338 memcpy(name, pent, name_len);
1339 name[name_len] = '\0';
1340 if (r)
1341 pent = r;
1342 else
1343 pent = "";
1345 TRACE("name=%s entry=%s\n",name, pent);
1347 if(ispunct(*name)) { /* a tc entry, not a real printer */
1348 TRACE("skipping tc entry\n");
1349 goto end;
1352 if(strstr(pent,":server")) { /* server only version so skip */
1353 TRACE("skipping server entry\n");
1354 goto end;
1357 /* Determine whether this is a postscript printer. */
1359 ret = TRUE;
1360 env_default = getenv("PRINTER");
1361 prettyname = name;
1362 /* Get longest name, usually the one at the right for later display. */
1363 while((s=strchr(prettyname,'|'))) {
1364 *s = '\0';
1365 e = s;
1366 while(isspace(*--e)) *e = '\0';
1367 TRACE("\t%s\n", debugstr_a(prettyname));
1368 if(env_default && !_strnicmp(prettyname, env_default, -1)) set_default = TRUE;
1369 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1372 e = prettyname + strlen(prettyname);
1373 while(isspace(*--e)) *e = '\0';
1374 TRACE("\t%s\n", debugstr_a(prettyname));
1375 if(env_default && !_strnicmp(prettyname, env_default, -1)) set_default = TRUE;
1377 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1378 * if it is too long, we use it as comment below. */
1379 devname = prettyname;
1380 if (strlen(devname)>=CCHDEVICENAME-1)
1381 devname = name;
1382 if (strlen(devname)>=CCHDEVICENAME-1) {
1383 ret = FALSE;
1384 goto end;
1387 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1388 sprintf(port,"LPR:%s",name);
1390 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1391 ERROR_SUCCESS) {
1392 ERR("Can't create Printers key\n");
1393 ret = FALSE;
1394 goto end;
1397 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, ARRAY_SIZE(devnameW));
1399 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1400 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1401 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1402 and continue */
1403 TRACE("Printer already exists\n");
1404 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1405 /* flag that the PPD file should be checked for an update */
1406 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1407 RegCloseKey(hkeyPrinter);
1408 } else {
1409 static CHAR data_type[] = "RAW",
1410 print_proc[] = "WinPrint",
1411 comment[] = "WINEPS Printer using LPR",
1412 params[] = "<parameters?>",
1413 share_name[] = "<share name?>",
1414 sep_file[] = "<sep file?>";
1415 BOOL added_driver = FALSE;
1417 if (!ppd_dir && !(ppd_dir = get_ppd_dir())) goto end;
1418 ppd = get_ppd_filename( ppd_dir, devnameW );
1419 if (get_fallback_ppd( devname, ppd ))
1421 added_driver = add_printer_driver( devnameW, ppd );
1422 unlink_ppd( ppd );
1424 HeapFree( GetProcessHeap(), 0, ppd );
1425 if (!added_driver) goto end;
1427 memset(&pinfo2a,0,sizeof(pinfo2a));
1428 pinfo2a.pPrinterName = devname;
1429 pinfo2a.pDatatype = data_type;
1430 pinfo2a.pPrintProcessor = print_proc;
1431 pinfo2a.pDriverName = devname;
1432 pinfo2a.pComment = comment;
1433 pinfo2a.pLocation = prettyname;
1434 pinfo2a.pPortName = port;
1435 pinfo2a.pParameters = params;
1436 pinfo2a.pShareName = share_name;
1437 pinfo2a.pSepFile = sep_file;
1439 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1440 if (added_printer) ClosePrinter( added_printer );
1441 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1442 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1445 if (isfirst || set_default)
1446 set_default_printer(devname, name);
1448 end:
1449 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1450 if (ppd_dir)
1452 RemoveDirectoryW( ppd_dir );
1453 HeapFree( GetProcessHeap(), 0, ppd_dir );
1455 HeapFree(GetProcessHeap(), 0, port);
1456 HeapFree(GetProcessHeap(), 0, name);
1457 return ret;
1460 static BOOL
1461 PRINTCAP_LoadPrinters(void) {
1462 BOOL hadprinter = FALSE;
1463 char buf[200];
1464 FILE *f;
1465 char *pent = NULL;
1466 BOOL had_bash = FALSE;
1468 f = fopen("/etc/printcap","r");
1469 if (!f)
1470 return FALSE;
1472 while(fgets(buf,sizeof(buf),f)) {
1473 char *start, *end;
1475 end=strchr(buf,'\n');
1476 if (end) *end='\0';
1478 start = buf;
1479 while(isspace(*start)) start++;
1480 if(*start == '#' || *start == '\0')
1481 continue;
1483 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1484 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1485 HeapFree(GetProcessHeap(),0,pent);
1486 pent = NULL;
1489 if (end && *--end == '\\') {
1490 *end = '\0';
1491 had_bash = TRUE;
1492 } else
1493 had_bash = FALSE;
1495 if (pent) {
1496 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1497 strcat(pent,start);
1498 } else {
1499 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1500 strcpy(pent,start);
1504 if(pent) {
1505 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1506 HeapFree(GetProcessHeap(),0,pent);
1508 fclose(f);
1509 return hadprinter;
1512 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1514 if (value)
1515 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1516 (lstrlenW(value) + 1) * sizeof(WCHAR));
1517 else
1518 return ERROR_FILE_NOT_FOUND;
1521 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1523 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1524 DWORD ret = ERROR_FILE_NOT_FOUND;
1526 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1527 and we support these drivers. NT writes DEVMODEW so somehow
1528 we'll need to distinguish between these when we support NT
1529 drivers */
1531 if (dmA)
1533 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1534 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1535 HeapFree( GetProcessHeap(), 0, dmA );
1538 return ret;
1541 /******************************************************************
1542 * get_servername_from_name (internal)
1544 * for an external server, a copy of the serverpart from the full name is returned
1547 static LPWSTR get_servername_from_name(LPCWSTR name)
1549 LPWSTR server;
1550 LPWSTR ptr;
1551 WCHAR buffer[MAX_PATH];
1552 DWORD len;
1554 if (name == NULL) return NULL;
1555 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1557 server = strdupW(&name[2]); /* skip over both backslash */
1558 if (server == NULL) return NULL;
1560 /* strip '\' and the printername */
1561 ptr = strchrW(server, '\\');
1562 if (ptr) ptr[0] = '\0';
1564 TRACE("found %s\n", debugstr_w(server));
1566 len = ARRAY_SIZE(buffer);
1567 if (GetComputerNameW(buffer, &len)) {
1568 if (lstrcmpW(buffer, server) == 0) {
1569 /* The requested Servername is our computername */
1570 HeapFree(GetProcessHeap(), 0, server);
1571 return NULL;
1574 return server;
1577 /******************************************************************
1578 * get_basename_from_name (internal)
1580 * skip over the serverpart from the full name
1583 static LPCWSTR get_basename_from_name(LPCWSTR name)
1585 if (name == NULL) return NULL;
1586 if ((name[0] == '\\') && (name[1] == '\\')) {
1587 /* skip over the servername and search for the following '\' */
1588 name = strchrW(&name[2], '\\');
1589 if ((name) && (name[1])) {
1590 /* found a separator ('\') followed by a name:
1591 skip over the separator and return the rest */
1592 name++;
1594 else
1596 /* no basename present (we found only a servername) */
1597 return NULL;
1600 return name;
1603 static void free_printer_entry( opened_printer_t *printer )
1605 /* the queue is shared, so don't free that here */
1606 HeapFree( GetProcessHeap(), 0, printer->printername );
1607 HeapFree( GetProcessHeap(), 0, printer->name );
1608 HeapFree( GetProcessHeap(), 0, printer->devmode );
1609 HeapFree( GetProcessHeap(), 0, printer );
1612 /******************************************************************
1613 * get_opened_printer_entry
1614 * Get the first place empty in the opened printer table
1616 * ToDo:
1617 * - pDefault is ignored
1619 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1621 UINT_PTR handle = nb_printer_handles, i;
1622 jobqueue_t *queue = NULL;
1623 opened_printer_t *printer = NULL;
1624 LPWSTR servername;
1625 LPCWSTR printername;
1627 if ((backend == NULL) && !load_backend()) return NULL;
1629 servername = get_servername_from_name(name);
1630 if (servername) {
1631 FIXME("server %s not supported\n", debugstr_w(servername));
1632 HeapFree(GetProcessHeap(), 0, servername);
1633 SetLastError(ERROR_INVALID_PRINTER_NAME);
1634 return NULL;
1637 printername = get_basename_from_name(name);
1638 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1640 /* an empty printername is invalid */
1641 if (printername && (!printername[0])) {
1642 SetLastError(ERROR_INVALID_PARAMETER);
1643 return NULL;
1646 EnterCriticalSection(&printer_handles_cs);
1648 for (i = 0; i < nb_printer_handles; i++)
1650 if (!printer_handles[i])
1652 if(handle == nb_printer_handles)
1653 handle = i;
1655 else
1657 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1658 queue = printer_handles[i]->queue;
1662 if (handle >= nb_printer_handles)
1664 opened_printer_t **new_array;
1665 if (printer_handles)
1666 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1667 (nb_printer_handles + 16) * sizeof(*new_array) );
1668 else
1669 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1670 (nb_printer_handles + 16) * sizeof(*new_array) );
1672 if (!new_array)
1674 handle = 0;
1675 goto end;
1677 printer_handles = new_array;
1678 nb_printer_handles += 16;
1681 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1683 handle = 0;
1684 goto end;
1687 /* get a printer handle from the backend */
1688 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1689 handle = 0;
1690 goto end;
1693 /* clone the base name. This is NULL for the printserver */
1694 printer->printername = strdupW(printername);
1696 /* clone the full name */
1697 printer->name = strdupW(name);
1698 if (name && (!printer->name)) {
1699 handle = 0;
1700 goto end;
1703 if (pDefault && pDefault->pDevMode)
1704 printer->devmode = dup_devmode( pDefault->pDevMode );
1706 if(queue)
1707 printer->queue = queue;
1708 else
1710 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1711 if (!printer->queue) {
1712 handle = 0;
1713 goto end;
1715 list_init(&printer->queue->jobs);
1716 printer->queue->ref = 0;
1718 InterlockedIncrement(&printer->queue->ref);
1720 printer_handles[handle] = printer;
1721 handle++;
1722 end:
1723 LeaveCriticalSection(&printer_handles_cs);
1724 if (!handle && printer) {
1725 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1726 free_printer_entry( printer );
1729 return (HANDLE)handle;
1732 static void old_printer_check( BOOL delete_phase )
1734 PRINTER_INFO_5W* pi;
1735 DWORD needed, type, num, delete, i, size;
1736 const DWORD one = 1;
1737 HKEY key;
1738 HANDLE hprn;
1740 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1741 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1743 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1744 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1745 for (i = 0; i < num; i++)
1747 if (!pi[i].pPortName) continue;
1749 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1750 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1751 continue;
1753 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1755 if (!delete_phase)
1757 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1758 RegCloseKey( key );
1760 else
1762 delete = 0;
1763 size = sizeof( delete );
1764 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1765 RegCloseKey( key );
1766 if (delete)
1768 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1769 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1771 DeletePrinter( hprn );
1772 ClosePrinter( hprn );
1774 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1778 HeapFree(GetProcessHeap(), 0, pi);
1781 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1782 'M','U','T','E','X','_','_','\0'};
1783 static HANDLE init_mutex;
1785 void WINSPOOL_LoadSystemPrinters(void)
1787 HKEY hkey, hkeyPrinters;
1788 DWORD needed, num, i;
1789 WCHAR PrinterName[256];
1790 BOOL done = FALSE;
1792 #ifdef SONAME_LIBCUPS
1793 load_cups();
1794 #endif
1796 /* FIXME: The init code should be moved to spoolsv.exe */
1797 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1798 if (!init_mutex)
1800 ERR( "Failed to create mutex\n" );
1801 return;
1803 if (GetLastError() == ERROR_ALREADY_EXISTS)
1805 WaitForSingleObject( init_mutex, INFINITE );
1806 ReleaseMutex( init_mutex );
1807 TRACE( "Init already done\n" );
1808 return;
1811 /* This ensures that all printer entries have a valid Name value. If causes
1812 problems later if they don't. If one is found to be missed we create one
1813 and set it equal to the name of the key */
1814 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1815 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1816 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1817 for(i = 0; i < num; i++) {
1818 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, ARRAY_SIZE(PrinterName)) == ERROR_SUCCESS) {
1819 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1820 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1821 set_reg_szW(hkey, NameW, PrinterName);
1823 RegCloseKey(hkey);
1828 RegCloseKey(hkeyPrinters);
1831 old_printer_check( FALSE );
1833 #ifdef SONAME_LIBCUPS
1834 done = CUPS_LoadPrinters();
1835 #endif
1837 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1838 PRINTCAP_LoadPrinters();
1840 old_printer_check( TRUE );
1842 ReleaseMutex( init_mutex );
1843 return;
1846 /******************************************************************
1847 * get_job
1849 * Get the pointer to the specified job.
1850 * Should hold the printer_handles_cs before calling.
1852 static job_t *get_job(HANDLE hprn, DWORD JobId)
1854 opened_printer_t *printer = get_opened_printer(hprn);
1855 job_t *job;
1857 if(!printer) return NULL;
1858 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1860 if(job->job_id == JobId)
1861 return job;
1863 return NULL;
1866 /******************************************************************
1867 * convert_printerinfo_W_to_A [internal]
1870 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1871 DWORD level, DWORD outlen, DWORD numentries)
1873 DWORD id = 0;
1874 LPSTR ptr;
1875 INT len;
1877 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1879 len = pi_sizeof[level] * numentries;
1880 ptr = (LPSTR) out + len;
1881 outlen -= len;
1883 /* copy the numbers of all PRINTER_INFO_* first */
1884 memcpy(out, pPrintersW, len);
1886 while (id < numentries) {
1887 switch (level) {
1888 case 1:
1890 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1891 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1893 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1894 if (piW->pDescription) {
1895 piA->pDescription = ptr;
1896 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1897 ptr, outlen, NULL, NULL);
1898 ptr += len;
1899 outlen -= len;
1901 if (piW->pName) {
1902 piA->pName = ptr;
1903 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1904 ptr, outlen, NULL, NULL);
1905 ptr += len;
1906 outlen -= len;
1908 if (piW->pComment) {
1909 piA->pComment = ptr;
1910 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1911 ptr, outlen, NULL, NULL);
1912 ptr += len;
1913 outlen -= len;
1915 break;
1918 case 2:
1920 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1921 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1922 LPDEVMODEA dmA;
1924 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1925 if (piW->pServerName) {
1926 piA->pServerName = ptr;
1927 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1928 ptr, outlen, NULL, NULL);
1929 ptr += len;
1930 outlen -= len;
1932 if (piW->pPrinterName) {
1933 piA->pPrinterName = ptr;
1934 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1935 ptr, outlen, NULL, NULL);
1936 ptr += len;
1937 outlen -= len;
1939 if (piW->pShareName) {
1940 piA->pShareName = ptr;
1941 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1942 ptr, outlen, NULL, NULL);
1943 ptr += len;
1944 outlen -= len;
1946 if (piW->pPortName) {
1947 piA->pPortName = ptr;
1948 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1949 ptr, outlen, NULL, NULL);
1950 ptr += len;
1951 outlen -= len;
1953 if (piW->pDriverName) {
1954 piA->pDriverName = ptr;
1955 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1956 ptr, outlen, NULL, NULL);
1957 ptr += len;
1958 outlen -= len;
1960 if (piW->pComment) {
1961 piA->pComment = ptr;
1962 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1963 ptr, outlen, NULL, NULL);
1964 ptr += len;
1965 outlen -= len;
1967 if (piW->pLocation) {
1968 piA->pLocation = ptr;
1969 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1970 ptr, outlen, NULL, NULL);
1971 ptr += len;
1972 outlen -= len;
1975 dmA = DEVMODEdupWtoA(piW->pDevMode);
1976 if (dmA) {
1977 /* align DEVMODEA to a DWORD boundary */
1978 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1979 ptr += len;
1980 outlen -= len;
1982 piA->pDevMode = (LPDEVMODEA) ptr;
1983 len = dmA->dmSize + dmA->dmDriverExtra;
1984 memcpy(ptr, dmA, len);
1985 HeapFree(GetProcessHeap(), 0, dmA);
1987 ptr += len;
1988 outlen -= len;
1991 if (piW->pSepFile) {
1992 piA->pSepFile = ptr;
1993 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1994 ptr, outlen, NULL, NULL);
1995 ptr += len;
1996 outlen -= len;
1998 if (piW->pPrintProcessor) {
1999 piA->pPrintProcessor = ptr;
2000 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
2001 ptr, outlen, NULL, NULL);
2002 ptr += len;
2003 outlen -= len;
2005 if (piW->pDatatype) {
2006 piA->pDatatype = ptr;
2007 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
2008 ptr, outlen, NULL, NULL);
2009 ptr += len;
2010 outlen -= len;
2012 if (piW->pParameters) {
2013 piA->pParameters = ptr;
2014 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
2015 ptr, outlen, NULL, NULL);
2016 ptr += len;
2017 outlen -= len;
2019 if (piW->pSecurityDescriptor) {
2020 piA->pSecurityDescriptor = NULL;
2021 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
2023 break;
2026 case 4:
2028 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
2029 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
2031 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
2033 if (piW->pPrinterName) {
2034 piA->pPrinterName = ptr;
2035 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
2036 ptr, outlen, NULL, NULL);
2037 ptr += len;
2038 outlen -= len;
2040 if (piW->pServerName) {
2041 piA->pServerName = ptr;
2042 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
2043 ptr, outlen, NULL, NULL);
2044 ptr += len;
2045 outlen -= len;
2047 break;
2050 case 5:
2052 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
2053 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
2055 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
2057 if (piW->pPrinterName) {
2058 piA->pPrinterName = ptr;
2059 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
2060 ptr, outlen, NULL, NULL);
2061 ptr += len;
2062 outlen -= len;
2064 if (piW->pPortName) {
2065 piA->pPortName = ptr;
2066 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
2067 ptr, outlen, NULL, NULL);
2068 ptr += len;
2069 outlen -= len;
2071 break;
2074 case 6: /* 6A and 6W are the same structure */
2075 break;
2077 case 7:
2079 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
2080 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
2082 TRACE("(%u) #%u\n", level, id);
2083 if (piW->pszObjectGUID) {
2084 piA->pszObjectGUID = ptr;
2085 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
2086 ptr, outlen, NULL, NULL);
2087 ptr += len;
2088 outlen -= len;
2090 break;
2093 case 8:
2094 case 9:
2096 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
2097 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
2098 LPDEVMODEA dmA;
2100 TRACE("(%u) #%u\n", level, id);
2101 dmA = DEVMODEdupWtoA(piW->pDevMode);
2102 if (dmA) {
2103 /* align DEVMODEA to a DWORD boundary */
2104 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
2105 ptr += len;
2106 outlen -= len;
2108 piA->pDevMode = (LPDEVMODEA) ptr;
2109 len = dmA->dmSize + dmA->dmDriverExtra;
2110 memcpy(ptr, dmA, len);
2111 HeapFree(GetProcessHeap(), 0, dmA);
2113 ptr += len;
2114 outlen -= len;
2117 break;
2120 default:
2121 FIXME("for level %u\n", level);
2123 pPrintersW += pi_sizeof[level];
2124 out += pi_sizeof[level];
2125 id++;
2129 /******************************************************************
2130 * convert_driverinfo_W_to_A [internal]
2133 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
2134 DWORD level, DWORD outlen, DWORD numentries)
2136 DWORD id = 0;
2137 LPSTR ptr;
2138 INT len;
2140 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
2142 len = di_sizeof[level] * numentries;
2143 ptr = (LPSTR) out + len;
2144 outlen -= len;
2146 /* copy the numbers of all PRINTER_INFO_* first */
2147 memcpy(out, pDriversW, len);
2149 #define COPY_STRING(fld) \
2150 { if (diW->fld){ \
2151 diA->fld = ptr; \
2152 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
2153 ptr += len; outlen -= len;\
2155 #define COPY_MULTIZ_STRING(fld) \
2156 { LPWSTR p = diW->fld; if (p){ \
2157 diA->fld = ptr; \
2158 do {\
2159 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2160 ptr += len; outlen -= len; p += len;\
2162 while(len > 1 && outlen > 0); \
2165 while (id < numentries)
2167 switch (level)
2169 case 1:
2171 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
2172 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
2174 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2176 COPY_STRING(pName);
2177 break;
2179 case 2:
2181 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2182 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2184 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2186 COPY_STRING(pName);
2187 COPY_STRING(pEnvironment);
2188 COPY_STRING(pDriverPath);
2189 COPY_STRING(pDataFile);
2190 COPY_STRING(pConfigFile);
2191 break;
2193 case 3:
2195 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2196 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2198 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2200 COPY_STRING(pName);
2201 COPY_STRING(pEnvironment);
2202 COPY_STRING(pDriverPath);
2203 COPY_STRING(pDataFile);
2204 COPY_STRING(pConfigFile);
2205 COPY_STRING(pHelpFile);
2206 COPY_MULTIZ_STRING(pDependentFiles);
2207 COPY_STRING(pMonitorName);
2208 COPY_STRING(pDefaultDataType);
2209 break;
2211 case 4:
2213 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2214 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2216 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2218 COPY_STRING(pName);
2219 COPY_STRING(pEnvironment);
2220 COPY_STRING(pDriverPath);
2221 COPY_STRING(pDataFile);
2222 COPY_STRING(pConfigFile);
2223 COPY_STRING(pHelpFile);
2224 COPY_MULTIZ_STRING(pDependentFiles);
2225 COPY_STRING(pMonitorName);
2226 COPY_STRING(pDefaultDataType);
2227 COPY_MULTIZ_STRING(pszzPreviousNames);
2228 break;
2230 case 5:
2232 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2233 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2235 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2237 COPY_STRING(pName);
2238 COPY_STRING(pEnvironment);
2239 COPY_STRING(pDriverPath);
2240 COPY_STRING(pDataFile);
2241 COPY_STRING(pConfigFile);
2242 break;
2244 case 6:
2246 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2247 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2249 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2251 COPY_STRING(pName);
2252 COPY_STRING(pEnvironment);
2253 COPY_STRING(pDriverPath);
2254 COPY_STRING(pDataFile);
2255 COPY_STRING(pConfigFile);
2256 COPY_STRING(pHelpFile);
2257 COPY_MULTIZ_STRING(pDependentFiles);
2258 COPY_STRING(pMonitorName);
2259 COPY_STRING(pDefaultDataType);
2260 COPY_MULTIZ_STRING(pszzPreviousNames);
2261 COPY_STRING(pszMfgName);
2262 COPY_STRING(pszOEMUrl);
2263 COPY_STRING(pszHardwareID);
2264 COPY_STRING(pszProvider);
2265 break;
2267 case 8:
2269 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2270 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2272 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2274 COPY_STRING(pName);
2275 COPY_STRING(pEnvironment);
2276 COPY_STRING(pDriverPath);
2277 COPY_STRING(pDataFile);
2278 COPY_STRING(pConfigFile);
2279 COPY_STRING(pHelpFile);
2280 COPY_MULTIZ_STRING(pDependentFiles);
2281 COPY_STRING(pMonitorName);
2282 COPY_STRING(pDefaultDataType);
2283 COPY_MULTIZ_STRING(pszzPreviousNames);
2284 COPY_STRING(pszMfgName);
2285 COPY_STRING(pszOEMUrl);
2286 COPY_STRING(pszHardwareID);
2287 COPY_STRING(pszProvider);
2288 COPY_STRING(pszPrintProcessor);
2289 COPY_STRING(pszVendorSetup);
2290 COPY_MULTIZ_STRING(pszzColorProfiles);
2291 COPY_STRING(pszInfPath);
2292 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2293 break;
2297 default:
2298 FIXME("for level %u\n", level);
2301 pDriversW += di_sizeof[level];
2302 out += di_sizeof[level];
2303 id++;
2306 #undef COPY_STRING
2307 #undef COPY_MULTIZ_STRING
2311 /***********************************************************
2312 * printer_info_AtoW
2314 static void *printer_info_AtoW( const void *data, DWORD level )
2316 void *ret;
2317 UNICODE_STRING usBuffer;
2319 if (!data) return NULL;
2321 if (level < 1 || level > 9) return NULL;
2323 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2324 if (!ret) return NULL;
2326 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2328 switch (level)
2330 case 2:
2332 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2333 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2335 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2336 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2337 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2338 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2339 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2340 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2341 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2342 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2343 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2344 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2345 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2346 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2347 break;
2350 case 8:
2351 case 9:
2353 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2354 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2356 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2357 break;
2360 default:
2361 FIXME( "Unhandled level %d\n", level );
2362 HeapFree( GetProcessHeap(), 0, ret );
2363 return NULL;
2366 return ret;
2369 /***********************************************************
2370 * free_printer_info
2372 static void free_printer_info( void *data, DWORD level )
2374 if (!data) return;
2376 switch (level)
2378 case 2:
2380 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2382 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2383 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2384 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2385 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2386 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2387 HeapFree( GetProcessHeap(), 0, piW->pComment );
2388 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2389 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2390 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2391 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2392 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2393 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2394 break;
2397 case 8:
2398 case 9:
2400 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2402 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2403 break;
2406 default:
2407 FIXME( "Unhandled level %d\n", level );
2410 HeapFree( GetProcessHeap(), 0, data );
2411 return;
2414 /******************************************************************
2415 * DeviceCapabilities [WINSPOOL.@]
2416 * DeviceCapabilitiesA [WINSPOOL.@]
2419 INT WINAPI DeviceCapabilitiesA(const char *device, const char *portA, WORD cap,
2420 char *output, DEVMODEA *devmodeA)
2422 WCHAR *device_name = NULL, *port = NULL;
2423 DEVMODEW *devmode = NULL;
2424 DWORD ret, len;
2426 len = MultiByteToWideChar(CP_ACP, 0, device, -1, NULL, 0);
2427 if (len) {
2428 device_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2429 MultiByteToWideChar(CP_ACP, 0, device, -1, device_name, len);
2432 len = MultiByteToWideChar(CP_ACP, 0, portA, -1, NULL, 0);
2433 if (len) {
2434 port = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2435 MultiByteToWideChar(CP_ACP, 0, portA, -1, port, len);
2438 if (devmodeA) devmode = GdiConvertToDevmodeW( devmodeA );
2440 if (output && (cap == DC_BINNAMES || cap == DC_FILEDEPENDENCIES || cap == DC_PAPERNAMES)) {
2441 /* These need A -> W translation */
2442 unsigned int size = 0, i;
2443 WCHAR *outputW;
2445 ret = DeviceCapabilitiesW(device_name, port, cap, NULL, devmode);
2446 if (ret == -1) return ret;
2448 switch (cap) {
2449 case DC_BINNAMES:
2450 size = 24;
2451 break;
2452 case DC_PAPERNAMES:
2453 case DC_FILEDEPENDENCIES:
2454 size = 64;
2455 break;
2457 outputW = HeapAlloc(GetProcessHeap(), 0, size * ret * sizeof(WCHAR));
2458 ret = DeviceCapabilitiesW(device_name, port, cap, outputW, devmode);
2459 for (i = 0; i < ret; i++)
2460 WideCharToMultiByte(CP_ACP, 0, outputW + (i * size), -1,
2461 output + (i * size), size, NULL, NULL);
2462 HeapFree(GetProcessHeap(), 0, outputW);
2463 } else {
2464 ret = DeviceCapabilitiesW(device_name, port, cap, (WCHAR *)output, devmode);
2466 HeapFree(GetProcessHeap(), 0, device_name);
2467 HeapFree(GetProcessHeap(), 0, devmode);
2468 HeapFree(GetProcessHeap(), 0, port);
2469 return ret;
2472 /*****************************************************************************
2473 * DeviceCapabilitiesW [WINSPOOL.@]
2476 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2477 WORD fwCapability, LPWSTR pOutput,
2478 const DEVMODEW *pDevMode)
2480 config_module_t *config;
2481 int ret;
2483 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability,
2484 pOutput, pDevMode);
2486 if (!(config = get_config_module(pDevice, TRUE))) {
2487 WARN("Could not load config module for %s\n", debugstr_w(pDevice));
2488 return 0;
2491 ret = config->pDrvDeviceCapabilities(NULL /* FIXME */, pDevice, fwCapability,
2492 pOutput, pDevMode);
2493 release_config_module(config);
2494 return ret;
2497 /******************************************************************
2498 * DocumentPropertiesA [WINSPOOL.@]
2500 LONG WINAPI DocumentPropertiesA(HWND hwnd, HANDLE printer, char *device_name, DEVMODEA *output,
2501 DEVMODEA *input, DWORD mode)
2503 DEVMODEW *outputW = NULL, *inputW = NULL;
2504 WCHAR *device = NULL;
2505 unsigned int len;
2506 int ret;
2508 TRACE("(%p,%p,%s,%p,%p,%d)\n", hwnd, printer, debugstr_a(device_name), output, input, mode);
2510 len = MultiByteToWideChar(CP_ACP, 0, device_name, -1, NULL, 0);
2511 if (len) {
2512 device = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2513 MultiByteToWideChar(CP_ACP, 0, device_name, -1, device, len);
2516 if (output && (mode & (DM_COPY | DM_UPDATE))) {
2517 ret = DocumentPropertiesW(hwnd, printer, device, NULL, NULL, 0);
2518 if (ret <= 0) {
2519 HeapFree(GetProcessHeap(), 0, device);
2520 return -1;
2522 outputW = HeapAlloc(GetProcessHeap(), 0, ret);
2525 if (input) inputW = GdiConvertToDevmodeW(input);
2527 ret = DocumentPropertiesW(hwnd, printer, device, outputW, inputW, mode);
2529 if (ret >= 0 && outputW && (mode & (DM_COPY | DM_UPDATE))) {
2530 DEVMODEA *dmA = DEVMODEdupWtoA( outputW );
2531 if (dmA) memcpy(output, dmA, dmA->dmSize + dmA->dmDriverExtra);
2532 HeapFree(GetProcessHeap(), 0, dmA);
2535 HeapFree(GetProcessHeap(), 0, device);
2536 HeapFree(GetProcessHeap(), 0, inputW);
2537 HeapFree(GetProcessHeap(), 0, outputW);
2539 if (!mode && ret > 0) ret -= CCHDEVICENAME + CCHFORMNAME;
2540 return ret;
2544 /*****************************************************************************
2545 * DocumentPropertiesW (WINSPOOL.@)
2547 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2548 LPWSTR pDeviceName,
2549 LPDEVMODEW pDevModeOutput,
2550 LPDEVMODEW pDevModeInput, DWORD fMode)
2552 config_module_t *config = NULL;
2553 const WCHAR *device = NULL;
2554 LONG ret;
2556 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2557 hWnd, hPrinter, debugstr_w(pDeviceName), pDevModeOutput, pDevModeInput, fMode);
2559 device = pDeviceName && pDeviceName[0] ? pDeviceName : get_opened_printer_name(hPrinter);
2560 if (!device) {
2561 ERR("no device name\n");
2562 return -1;
2565 config = get_config_module(device, TRUE);
2566 if (!config) {
2567 ERR("Could not load config module for %s\n", debugstr_w(device));
2568 return -1;
2571 /* FIXME: This uses Wine-specific config file entry point.
2572 * We should use DrvDevicePropertySheets instead (requires CPSUI support first).
2574 ret = config->pDrvDocumentProperties(hWnd, device, pDevModeOutput, pDevModeInput, fMode);
2575 release_config_module(config);
2576 return ret;
2579 /*****************************************************************************
2580 * IsValidDevmodeA [WINSPOOL.@]
2582 * Validate a DEVMODE structure and fix errors if possible.
2585 BOOL WINAPI IsValidDevmodeA(PDEVMODEA pDevMode, SIZE_T size)
2587 FIXME("(%p,%ld): stub\n", pDevMode, size);
2589 if(!pDevMode)
2590 return FALSE;
2592 return TRUE;
2595 /*****************************************************************************
2596 * IsValidDevmodeW [WINSPOOL.@]
2598 * Validate a DEVMODE structure and fix errors if possible.
2601 BOOL WINAPI IsValidDevmodeW(PDEVMODEW dm, SIZE_T size)
2603 static const struct
2605 DWORD flag;
2606 SIZE_T size;
2607 } map[] =
2609 #define F_SIZE(field) FIELD_OFFSET(DEVMODEW, field) + sizeof(dm->field)
2610 { DM_ORIENTATION, F_SIZE(u1.s1.dmOrientation) },
2611 { DM_PAPERSIZE, F_SIZE(u1.s1.dmPaperSize) },
2612 { DM_PAPERLENGTH, F_SIZE(u1.s1.dmPaperLength) },
2613 { DM_PAPERWIDTH, F_SIZE(u1.s1.dmPaperWidth) },
2614 { DM_SCALE, F_SIZE(u1.s1.dmScale) },
2615 { DM_COPIES, F_SIZE(u1.s1.dmCopies) },
2616 { DM_DEFAULTSOURCE, F_SIZE(u1.s1.dmDefaultSource) },
2617 { DM_PRINTQUALITY, F_SIZE(u1.s1.dmPrintQuality) },
2618 { DM_POSITION, F_SIZE(u1.s2.dmPosition) },
2619 { DM_DISPLAYORIENTATION, F_SIZE(u1.s2.dmDisplayOrientation) },
2620 { DM_DISPLAYFIXEDOUTPUT, F_SIZE(u1.s2.dmDisplayFixedOutput) },
2621 { DM_COLOR, F_SIZE(dmColor) },
2622 { DM_DUPLEX, F_SIZE(dmDuplex) },
2623 { DM_YRESOLUTION, F_SIZE(dmYResolution) },
2624 { DM_TTOPTION, F_SIZE(dmTTOption) },
2625 { DM_COLLATE, F_SIZE(dmCollate) },
2626 { DM_FORMNAME, F_SIZE(dmFormName) },
2627 { DM_LOGPIXELS, F_SIZE(dmLogPixels) },
2628 { DM_BITSPERPEL, F_SIZE(dmBitsPerPel) },
2629 { DM_PELSWIDTH, F_SIZE(dmPelsWidth) },
2630 { DM_PELSHEIGHT, F_SIZE(dmPelsHeight) },
2631 { DM_DISPLAYFLAGS, F_SIZE(u2.dmDisplayFlags) },
2632 { DM_NUP, F_SIZE(u2.dmNup) },
2633 { DM_DISPLAYFREQUENCY, F_SIZE(dmDisplayFrequency) },
2634 { DM_ICMMETHOD, F_SIZE(dmICMMethod) },
2635 { DM_ICMINTENT, F_SIZE(dmICMIntent) },
2636 { DM_MEDIATYPE, F_SIZE(dmMediaType) },
2637 { DM_DITHERTYPE, F_SIZE(dmDitherType) },
2638 { DM_PANNINGWIDTH, F_SIZE(dmPanningWidth) },
2639 { DM_PANNINGHEIGHT, F_SIZE(dmPanningHeight) }
2640 #undef F_SIZE
2642 int i;
2644 if (!dm) return FALSE;
2645 if (size < FIELD_OFFSET(DEVMODEW, dmFields) + sizeof(dm->dmFields)) return FALSE;
2647 for (i = 0; i < ARRAY_SIZE(map); i++)
2648 if ((dm->dmFields & map[i].flag) && size < map[i].size)
2649 return FALSE;
2651 return TRUE;
2654 /******************************************************************
2655 * OpenPrinterA [WINSPOOL.@]
2657 * See OpenPrinterW.
2660 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2661 LPPRINTER_DEFAULTSA pDefault)
2663 UNICODE_STRING lpPrinterNameW;
2664 UNICODE_STRING usBuffer;
2665 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2666 PWSTR pwstrPrinterNameW;
2667 BOOL ret;
2669 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName), phPrinter, pDefault);
2671 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2673 if(pDefault) {
2674 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2675 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2676 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2677 pDefaultW = &DefaultW;
2679 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2680 if(pDefault) {
2681 RtlFreeUnicodeString(&usBuffer);
2682 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2684 RtlFreeUnicodeString(&lpPrinterNameW);
2685 return ret;
2688 /******************************************************************
2689 * OpenPrinterW [WINSPOOL.@]
2691 * Open a Printer / Printserver or a Printer-Object
2693 * PARAMS
2694 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2695 * phPrinter [O] The resulting Handle is stored here
2696 * pDefault [I] PTR to Default Printer Settings or NULL
2698 * RETURNS
2699 * Success: TRUE
2700 * Failure: FALSE
2702 * NOTES
2703 * lpPrinterName is one of:
2704 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2705 *| Printer: "PrinterName"
2706 *| Printer-Object: "PrinterName,Job xxx"
2707 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2708 *| XcvPort: "Servername,XcvPort PortName"
2710 * BUGS
2711 *| Printer-Object not supported
2712 *| pDefaults is ignored
2715 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2717 HKEY key;
2719 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2721 if(!phPrinter) {
2722 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2723 SetLastError(ERROR_INVALID_PARAMETER);
2724 return FALSE;
2727 /* Get the unique handle of the printer or Printserver */
2728 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2730 if (*phPrinter && WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key ) == ERROR_SUCCESS)
2732 DWORD deleting = 0, size = sizeof( deleting ), type;
2733 DWORD status;
2734 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2735 WaitForSingleObject( init_mutex, INFINITE );
2736 status = get_dword_from_reg( key, StatusW );
2737 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2738 ReleaseMutex( init_mutex );
2739 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2740 update_driver( *phPrinter );
2741 RegCloseKey( key );
2744 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2745 return (*phPrinter != 0);
2748 /******************************************************************
2749 * AddMonitorA [WINSPOOL.@]
2751 * See AddMonitorW.
2754 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2756 LPWSTR nameW = NULL;
2757 INT len;
2758 BOOL res;
2759 LPMONITOR_INFO_2A mi2a;
2760 MONITOR_INFO_2W mi2w;
2762 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2763 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2764 debugstr_a(mi2a ? mi2a->pName : NULL),
2765 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2766 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2768 if (Level != 2) {
2769 SetLastError(ERROR_INVALID_LEVEL);
2770 return FALSE;
2773 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2774 if (mi2a == NULL) {
2775 return FALSE;
2778 if (pName) {
2779 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2780 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2781 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2784 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2785 if (mi2a->pName) {
2786 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2787 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2788 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2790 if (mi2a->pEnvironment) {
2791 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2792 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2793 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2795 if (mi2a->pDLLName) {
2796 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2797 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2798 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2801 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2803 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2804 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2805 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2807 HeapFree(GetProcessHeap(), 0, nameW);
2808 return (res);
2811 /******************************************************************************
2812 * AddMonitorW [WINSPOOL.@]
2814 * Install a Printmonitor
2816 * PARAMS
2817 * pName [I] Servername or NULL (local Computer)
2818 * Level [I] Structure-Level (Must be 2)
2819 * pMonitors [I] PTR to MONITOR_INFO_2
2821 * RETURNS
2822 * Success: TRUE
2823 * Failure: FALSE
2825 * NOTES
2826 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2829 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2831 LPMONITOR_INFO_2W mi2w;
2833 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2834 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2835 debugstr_w(mi2w ? mi2w->pName : NULL),
2836 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2837 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2839 if ((backend == NULL) && !load_backend()) return FALSE;
2841 if (Level != 2) {
2842 SetLastError(ERROR_INVALID_LEVEL);
2843 return FALSE;
2846 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2847 if (mi2w == NULL) {
2848 return FALSE;
2851 return backend->fpAddMonitor(pName, Level, pMonitors);
2854 /******************************************************************
2855 * DeletePrinterDriverA [WINSPOOL.@]
2858 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2860 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2863 /******************************************************************
2864 * DeletePrinterDriverW [WINSPOOL.@]
2867 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2869 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2872 /******************************************************************
2873 * DeleteMonitorA [WINSPOOL.@]
2875 * See DeleteMonitorW.
2878 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2880 LPWSTR nameW = NULL;
2881 LPWSTR EnvironmentW = NULL;
2882 LPWSTR MonitorNameW = NULL;
2883 BOOL res;
2884 INT len;
2886 if (pName) {
2887 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2888 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2889 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2892 if (pEnvironment) {
2893 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2894 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2895 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2897 if (pMonitorName) {
2898 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2899 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2900 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2903 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2905 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2906 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2907 HeapFree(GetProcessHeap(), 0, nameW);
2908 return (res);
2911 /******************************************************************
2912 * DeleteMonitorW [WINSPOOL.@]
2914 * Delete a specific Printmonitor from a Printing-Environment
2916 * PARAMS
2917 * pName [I] Servername or NULL (local Computer)
2918 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2919 * pMonitorName [I] Name of the Monitor, that should be deleted
2921 * RETURNS
2922 * Success: TRUE
2923 * Failure: FALSE
2925 * NOTES
2926 * pEnvironment is ignored in Windows for the local Computer.
2929 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2932 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2933 debugstr_w(pMonitorName));
2935 if ((backend == NULL) && !load_backend()) return FALSE;
2937 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2941 /******************************************************************
2942 * DeletePortA [WINSPOOL.@]
2944 * See DeletePortW.
2947 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2949 LPWSTR nameW = NULL;
2950 LPWSTR portW = NULL;
2951 INT len;
2952 DWORD res;
2954 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2956 /* convert servername to unicode */
2957 if (pName) {
2958 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2959 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2960 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2963 /* convert portname to unicode */
2964 if (pPortName) {
2965 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2966 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2967 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2970 res = DeletePortW(nameW, hWnd, portW);
2971 HeapFree(GetProcessHeap(), 0, nameW);
2972 HeapFree(GetProcessHeap(), 0, portW);
2973 return res;
2976 /******************************************************************
2977 * DeletePortW [WINSPOOL.@]
2979 * Delete a specific Port
2981 * PARAMS
2982 * pName [I] Servername or NULL (local Computer)
2983 * hWnd [I] Handle to parent Window for the Dialog-Box
2984 * pPortName [I] Name of the Port, that should be deleted
2986 * RETURNS
2987 * Success: TRUE
2988 * Failure: FALSE
2991 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2993 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2995 if ((backend == NULL) && !load_backend()) return FALSE;
2997 if (!pPortName) {
2998 SetLastError(RPC_X_NULL_REF_POINTER);
2999 return FALSE;
3002 return backend->fpDeletePort(pName, hWnd, pPortName);
3005 /******************************************************************************
3006 * WritePrinter [WINSPOOL.@]
3008 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
3010 opened_printer_t *printer;
3011 BOOL ret = FALSE;
3013 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
3015 EnterCriticalSection(&printer_handles_cs);
3016 printer = get_opened_printer(hPrinter);
3017 if(!printer)
3019 SetLastError(ERROR_INVALID_HANDLE);
3020 goto end;
3023 if(!printer->doc)
3025 SetLastError(ERROR_SPL_NO_STARTDOC);
3026 goto end;
3029 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
3030 end:
3031 LeaveCriticalSection(&printer_handles_cs);
3032 return ret;
3035 /*****************************************************************************
3036 * AddFormA [WINSPOOL.@]
3038 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
3040 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
3041 return TRUE;
3044 /*****************************************************************************
3045 * AddFormW [WINSPOOL.@]
3047 BOOL WINAPI AddFormW( HANDLE printer, DWORD level, BYTE *form )
3049 HANDLE handle = get_backend_handle( printer );
3051 TRACE( "(%p, %d, %p)\n", printer, level, form );
3053 if (!handle)
3055 SetLastError( ERROR_INVALID_HANDLE );
3056 return FALSE;
3059 return backend->fpAddForm( handle, level, form );
3062 /*****************************************************************************
3063 * AddJobA [WINSPOOL.@]
3065 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
3067 BOOL ret;
3068 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3069 DWORD needed;
3071 if(Level != 1) {
3072 SetLastError(ERROR_INVALID_LEVEL);
3073 return FALSE;
3076 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
3078 if(ret) {
3079 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
3080 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
3081 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
3082 if(*pcbNeeded > cbBuf) {
3083 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3084 ret = FALSE;
3085 } else {
3086 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
3087 addjobA->JobId = addjobW->JobId;
3088 addjobA->Path = (char *)(addjobA + 1);
3089 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
3092 return ret;
3095 /*****************************************************************************
3096 * AddJobW [WINSPOOL.@]
3098 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
3100 opened_printer_t *printer;
3101 job_t *job;
3102 BOOL ret = FALSE;
3103 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
3104 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
3105 WCHAR path[MAX_PATH], filename[MAX_PATH];
3106 DWORD len;
3107 ADDJOB_INFO_1W *addjob;
3109 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
3111 EnterCriticalSection(&printer_handles_cs);
3113 printer = get_opened_printer(hPrinter);
3115 if(!printer) {
3116 SetLastError(ERROR_INVALID_HANDLE);
3117 goto end;
3120 if(Level != 1) {
3121 SetLastError(ERROR_INVALID_LEVEL);
3122 goto end;
3125 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
3126 if(!job)
3127 goto end;
3129 job->job_id = InterlockedIncrement(&next_job_id);
3131 len = GetSystemDirectoryW(path, ARRAY_SIZE(path));
3132 if(path[len - 1] != '\\')
3133 path[len++] = '\\';
3134 memcpy(path + len, spool_path, sizeof(spool_path));
3135 sprintfW(filename, fmtW, path, job->job_id);
3137 len = strlenW(filename);
3138 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
3139 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
3140 job->portname = NULL;
3141 job->document_title = strdupW(default_doc_title);
3142 job->printer_name = strdupW(printer->name);
3143 job->devmode = dup_devmode( printer->devmode );
3144 list_add_tail(&printer->queue->jobs, &job->entry);
3146 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
3147 if(*pcbNeeded <= cbBuf) {
3148 addjob = (ADDJOB_INFO_1W*)pData;
3149 addjob->JobId = job->job_id;
3150 addjob->Path = (WCHAR *)(addjob + 1);
3151 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
3152 ret = TRUE;
3153 } else
3154 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3156 end:
3157 LeaveCriticalSection(&printer_handles_cs);
3158 return ret;
3161 /*****************************************************************************
3162 * GetPrintProcessorDirectoryA [WINSPOOL.@]
3164 * Return the PATH for the Print-Processors
3166 * See GetPrintProcessorDirectoryW.
3170 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
3171 DWORD level, LPBYTE Info,
3172 DWORD cbBuf, LPDWORD pcbNeeded)
3174 LPWSTR serverW = NULL;
3175 LPWSTR envW = NULL;
3176 BOOL ret;
3177 INT len;
3179 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
3180 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
3183 if (server) {
3184 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
3185 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3186 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
3189 if (env) {
3190 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
3191 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3192 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
3195 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
3196 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
3198 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
3199 cbBuf, pcbNeeded);
3201 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
3202 cbBuf, NULL, NULL) > 0;
3205 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3206 HeapFree(GetProcessHeap(), 0, envW);
3207 HeapFree(GetProcessHeap(), 0, serverW);
3208 return ret;
3211 /*****************************************************************************
3212 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3214 * Return the PATH for the Print-Processors
3216 * PARAMS
3217 * server [I] Servername (NT only) or NULL (local Computer)
3218 * env [I] Printing-Environment (see below) or NULL (Default)
3219 * level [I] Structure-Level (must be 1)
3220 * Info [O] PTR to Buffer that receives the Result
3221 * cbBuf [I] Size of Buffer at "Info"
3222 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3223 * required for the Buffer at "Info"
3225 * RETURNS
3226 * Success: TRUE and in pcbNeeded the Bytes used in Info
3227 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3228 * if cbBuf is too small
3230 * Native Values returned in Info on Success:
3231 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3232 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3233 *| win9x(Windows 4.0): "%winsysdir%"
3235 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3237 * BUGS
3238 * Only NULL or "" is supported for server
3241 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3242 DWORD level, LPBYTE Info,
3243 DWORD cbBuf, LPDWORD pcbNeeded)
3246 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3247 Info, cbBuf, pcbNeeded);
3249 if ((backend == NULL) && !load_backend()) return FALSE;
3251 if (level != 1) {
3252 /* (Level != 1) is ignored in win9x */
3253 SetLastError(ERROR_INVALID_LEVEL);
3254 return FALSE;
3257 if (pcbNeeded == NULL) {
3258 /* (pcbNeeded == NULL) is ignored in win9x */
3259 SetLastError(RPC_X_NULL_REF_POINTER);
3260 return FALSE;
3263 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3266 /*****************************************************************************
3267 * set_devices_and_printerports [internal]
3269 * set the [Devices] and [PrinterPorts] entries for a printer.
3272 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3274 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3275 WCHAR *devline;
3276 HKEY hkey;
3278 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3280 /* FIXME: the driver must change to "winspool" */
3281 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3282 if (devline) {
3283 lstrcpyW(devline, driver_nt);
3284 lstrcatW(devline, commaW);
3285 lstrcatW(devline, pi->pPortName);
3287 TRACE("using %s\n", debugstr_w(devline));
3288 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3289 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3290 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3291 RegCloseKey(hkey);
3294 lstrcatW(devline, timeout_15_45);
3295 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3296 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3297 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3298 RegCloseKey(hkey);
3300 HeapFree(GetProcessHeap(), 0, devline);
3304 /*****************************************************************************
3305 * AddPrinterW [WINSPOOL.@]
3307 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3309 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3310 LPDEVMODEW dm;
3311 HANDLE retval;
3312 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3313 LONG size;
3315 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3317 if(pName && *pName) {
3318 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3319 SetLastError(ERROR_INVALID_PARAMETER);
3320 return 0;
3322 if(Level != 2) {
3323 ERR("Level = %d, unsupported!\n", Level);
3324 SetLastError(ERROR_INVALID_LEVEL);
3325 return 0;
3327 if(!pPrinter) {
3328 SetLastError(ERROR_INVALID_PARAMETER);
3329 return 0;
3331 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3332 ERROR_SUCCESS) {
3333 ERR("Can't create Printers key\n");
3334 return 0;
3336 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3337 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3338 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3339 RegCloseKey(hkeyPrinter);
3340 RegCloseKey(hkeyPrinters);
3341 return 0;
3343 RegCloseKey(hkeyPrinter);
3345 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3346 if(!hkeyDrivers) {
3347 ERR("Can't create Drivers key\n");
3348 RegCloseKey(hkeyPrinters);
3349 return 0;
3351 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3352 ERROR_SUCCESS) {
3353 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3354 RegCloseKey(hkeyPrinters);
3355 RegCloseKey(hkeyDrivers);
3356 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3357 return 0;
3359 RegCloseKey(hkeyDriver);
3360 RegCloseKey(hkeyDrivers);
3362 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3363 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3364 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3365 RegCloseKey(hkeyPrinters);
3366 return 0;
3369 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3370 ERROR_SUCCESS) {
3371 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3372 SetLastError(ERROR_INVALID_PRINTER_NAME);
3373 RegCloseKey(hkeyPrinters);
3374 return 0;
3377 set_devices_and_printerports(pi);
3379 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3380 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3381 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3382 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3383 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3384 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3385 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3386 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3387 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3388 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3389 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3390 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3391 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3392 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3393 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3394 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3395 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3396 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3398 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3400 if (size < 0)
3402 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3403 size = sizeof(DEVMODEW);
3405 if(pi->pDevMode)
3406 dm = pi->pDevMode;
3407 else
3409 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3410 dm->dmSize = size;
3411 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3413 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3414 HeapFree( GetProcessHeap(), 0, dm );
3415 dm = NULL;
3417 else
3419 /* set devmode to printer name */
3420 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3424 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3425 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3427 RegCloseKey(hkeyPrinter);
3428 RegCloseKey(hkeyPrinters);
3429 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3430 ERR("OpenPrinter failing\n");
3431 return 0;
3433 return retval;
3436 /*****************************************************************************
3437 * AddPrinterA [WINSPOOL.@]
3439 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3441 UNICODE_STRING pNameW;
3442 PWSTR pwstrNameW;
3443 PRINTER_INFO_2W *piW;
3444 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3445 HANDLE ret;
3447 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3448 if(Level != 2) {
3449 ERR("Level = %d, unsupported!\n", Level);
3450 SetLastError(ERROR_INVALID_LEVEL);
3451 return 0;
3453 pwstrNameW = asciitounicode(&pNameW,pName);
3454 piW = printer_info_AtoW( piA, Level );
3456 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3458 free_printer_info( piW, Level );
3459 RtlFreeUnicodeString(&pNameW);
3460 return ret;
3464 /*****************************************************************************
3465 * ClosePrinter [WINSPOOL.@]
3467 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3469 UINT_PTR i = (UINT_PTR)hPrinter;
3470 opened_printer_t *printer = NULL;
3472 TRACE("(%p)\n", hPrinter);
3474 EnterCriticalSection(&printer_handles_cs);
3476 if ((i > 0) && (i <= nb_printer_handles))
3477 printer = printer_handles[i - 1];
3480 if(printer)
3482 struct list *cursor, *cursor2;
3484 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3486 if(printer->doc)
3487 EndDocPrinter(hPrinter);
3489 if(InterlockedDecrement(&printer->queue->ref) == 0)
3491 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3493 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3494 ScheduleJob(hPrinter, job->job_id);
3496 HeapFree(GetProcessHeap(), 0, printer->queue);
3499 if (printer->backend_printer) {
3500 backend->fpClosePrinter(printer->backend_printer);
3503 free_printer_entry( printer );
3504 printer_handles[i - 1] = NULL;
3505 LeaveCriticalSection(&printer_handles_cs);
3506 return TRUE;
3509 LeaveCriticalSection(&printer_handles_cs);
3510 SetLastError(ERROR_INVALID_HANDLE);
3511 return FALSE;
3514 /*****************************************************************************
3515 * DeleteFormA [WINSPOOL.@]
3517 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3519 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3520 return TRUE;
3523 /*****************************************************************************
3524 * DeleteFormW [WINSPOOL.@]
3526 BOOL WINAPI DeleteFormW( HANDLE printer, WCHAR *name )
3528 HANDLE handle = get_backend_handle( printer );
3530 TRACE( "(%p, %s)\n", printer, debugstr_w( name ) );
3532 if (!handle)
3534 SetLastError( ERROR_INVALID_HANDLE );
3535 return FALSE;
3538 return backend->fpDeleteForm( handle, name );
3541 /*****************************************************************************
3542 * DeletePrinter [WINSPOOL.@]
3544 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3546 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3547 config_module_t *config_module;
3548 HKEY hkeyPrinters, hkey;
3549 WCHAR def[MAX_PATH];
3550 DWORD size = ARRAY_SIZE(def);
3552 if(!lpNameW) {
3553 SetLastError(ERROR_INVALID_HANDLE);
3554 return FALSE;
3557 EnterCriticalSection(&config_modules_cs);
3558 if ((config_module = get_config_module(lpNameW, FALSE))) {
3559 wine_rb_remove(&config_modules, &config_module->entry);
3560 release_config_module(config_module);
3562 LeaveCriticalSection(&config_modules_cs);
3564 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3565 RegDeleteTreeW(hkeyPrinters, lpNameW);
3566 RegCloseKey(hkeyPrinters);
3569 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3570 RegDeleteValueW(hkey, lpNameW);
3571 RegCloseKey(hkey);
3574 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3575 RegDeleteValueW(hkey, lpNameW);
3576 RegCloseKey(hkey);
3579 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3581 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3583 RegDeleteValueW( hkey, deviceW );
3584 RegCloseKey( hkey );
3586 SetDefaultPrinterW( NULL );
3589 return TRUE;
3592 /*****************************************************************************
3593 * SetPrinterA [WINSPOOL.@]
3595 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3597 BYTE *dataW = data;
3598 BOOL ret;
3600 if (level != 0)
3602 dataW = printer_info_AtoW( data, level );
3603 if (!dataW) return FALSE;
3606 ret = SetPrinterW( printer, level, dataW, command );
3608 if (dataW != data) free_printer_info( dataW, level );
3610 return ret;
3613 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3615 set_reg_szW( key, NameW, pi->pPrinterName );
3616 set_reg_szW( key, Share_NameW, pi->pShareName );
3617 set_reg_szW( key, PortW, pi->pPortName );
3618 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3619 set_reg_szW( key, DescriptionW, pi->pComment );
3620 set_reg_szW( key, LocationW, pi->pLocation );
3622 if (pi->pDevMode)
3623 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3625 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3626 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3627 set_reg_szW( key, DatatypeW, pi->pDatatype );
3628 set_reg_szW( key, ParametersW, pi->pParameters );
3630 set_reg_DWORD( key, AttributesW, pi->Attributes );
3631 set_reg_DWORD( key, PriorityW, pi->Priority );
3632 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3633 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3634 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3637 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3639 if (!pi->pDevMode) return FALSE;
3641 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3642 return TRUE;
3645 /******************************************************************************
3646 * SetPrinterW [WINSPOOL.@]
3648 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3650 HKEY key;
3651 BOOL ret = FALSE;
3653 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3655 if (command != 0) FIXME( "Ignoring command %d\n", command );
3657 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3658 return FALSE;
3660 switch (level)
3662 case 2:
3664 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3665 set_printer_2( key, pi2 );
3666 ret = TRUE;
3667 break;
3670 case 8:
3671 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
3672 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3673 /* fall through */
3674 case 9:
3676 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3677 ret = set_printer_9( key, pi );
3678 break;
3681 default:
3682 FIXME( "Unimplemented level %d\n", level );
3683 SetLastError( ERROR_INVALID_LEVEL );
3686 RegCloseKey( key );
3687 return ret;
3690 /*****************************************************************************
3691 * SetJobA [WINSPOOL.@]
3693 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3694 LPBYTE pJob, DWORD Command)
3696 BOOL ret;
3697 LPBYTE JobW;
3698 UNICODE_STRING usBuffer;
3700 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3702 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3703 are all ignored by SetJob, so we don't bother copying them */
3704 switch(Level)
3706 case 0:
3707 JobW = NULL;
3708 break;
3709 case 1:
3711 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3712 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3714 JobW = (LPBYTE)info1W;
3715 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3716 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3717 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3718 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3719 info1W->Status = info1A->Status;
3720 info1W->Priority = info1A->Priority;
3721 info1W->Position = info1A->Position;
3722 info1W->PagesPrinted = info1A->PagesPrinted;
3723 break;
3725 case 2:
3727 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3728 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3730 JobW = (LPBYTE)info2W;
3731 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3732 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3733 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3734 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3735 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3736 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3737 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3738 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3739 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3740 info2W->Status = info2A->Status;
3741 info2W->Priority = info2A->Priority;
3742 info2W->Position = info2A->Position;
3743 info2W->StartTime = info2A->StartTime;
3744 info2W->UntilTime = info2A->UntilTime;
3745 info2W->PagesPrinted = info2A->PagesPrinted;
3746 break;
3748 case 3:
3749 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3750 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3751 break;
3752 default:
3753 SetLastError(ERROR_INVALID_LEVEL);
3754 return FALSE;
3757 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3759 switch(Level)
3761 case 1:
3763 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3764 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3765 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3766 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3767 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3768 break;
3770 case 2:
3772 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3773 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3774 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3775 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3776 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3777 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3778 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3779 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3780 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3781 break;
3784 HeapFree(GetProcessHeap(), 0, JobW);
3786 return ret;
3789 /*****************************************************************************
3790 * SetJobW [WINSPOOL.@]
3792 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3793 LPBYTE pJob, DWORD Command)
3795 BOOL ret = FALSE;
3796 job_t *job;
3798 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3799 FIXME("Ignoring everything other than document title\n");
3801 EnterCriticalSection(&printer_handles_cs);
3802 job = get_job(hPrinter, JobId);
3803 if(!job)
3804 goto end;
3806 switch(Level)
3808 case 0:
3809 break;
3810 case 1:
3812 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3813 HeapFree(GetProcessHeap(), 0, job->document_title);
3814 job->document_title = strdupW(info1->pDocument);
3815 break;
3817 case 2:
3819 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3820 HeapFree(GetProcessHeap(), 0, job->document_title);
3821 job->document_title = strdupW(info2->pDocument);
3822 HeapFree(GetProcessHeap(), 0, job->devmode);
3823 job->devmode = dup_devmode( info2->pDevMode );
3824 break;
3826 case 3:
3827 break;
3828 default:
3829 SetLastError(ERROR_INVALID_LEVEL);
3830 goto end;
3832 ret = TRUE;
3833 end:
3834 LeaveCriticalSection(&printer_handles_cs);
3835 return ret;
3838 /*****************************************************************************
3839 * EndDocPrinter [WINSPOOL.@]
3841 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3843 opened_printer_t *printer;
3844 BOOL ret = FALSE;
3845 TRACE("(%p)\n", hPrinter);
3847 EnterCriticalSection(&printer_handles_cs);
3849 printer = get_opened_printer(hPrinter);
3850 if(!printer)
3852 SetLastError(ERROR_INVALID_HANDLE);
3853 goto end;
3856 if(!printer->doc)
3858 SetLastError(ERROR_SPL_NO_STARTDOC);
3859 goto end;
3862 CloseHandle(printer->doc->hf);
3863 ScheduleJob(hPrinter, printer->doc->job_id);
3864 HeapFree(GetProcessHeap(), 0, printer->doc);
3865 printer->doc = NULL;
3866 ret = TRUE;
3867 end:
3868 LeaveCriticalSection(&printer_handles_cs);
3869 return ret;
3872 /*****************************************************************************
3873 * EndPagePrinter [WINSPOOL.@]
3875 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3877 FIXME("(%p): stub\n", hPrinter);
3878 return TRUE;
3881 /*****************************************************************************
3882 * StartDocPrinterA [WINSPOOL.@]
3884 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3886 UNICODE_STRING usBuffer;
3887 DOC_INFO_2W doc2W;
3888 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3889 DWORD ret;
3891 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3892 or one (DOC_INFO_3) extra DWORDs */
3894 switch(Level) {
3895 case 2:
3896 doc2W.JobId = doc2->JobId;
3897 /* fall through */
3898 case 3:
3899 doc2W.dwMode = doc2->dwMode;
3900 /* fall through */
3901 case 1:
3902 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3903 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3904 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3905 break;
3907 default:
3908 SetLastError(ERROR_INVALID_LEVEL);
3909 return FALSE;
3912 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3914 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3915 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3916 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3918 return ret;
3921 /*****************************************************************************
3922 * StartDocPrinterW [WINSPOOL.@]
3924 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3926 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3927 opened_printer_t *printer;
3928 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3929 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3930 JOB_INFO_1W job_info;
3931 DWORD needed, ret = 0;
3932 HANDLE hf;
3933 WCHAR *filename;
3934 job_t *job;
3936 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3937 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3938 debugstr_w(doc->pDatatype));
3940 if(Level < 1 || Level > 3)
3942 SetLastError(ERROR_INVALID_LEVEL);
3943 return 0;
3946 EnterCriticalSection(&printer_handles_cs);
3947 printer = get_opened_printer(hPrinter);
3948 if(!printer)
3950 SetLastError(ERROR_INVALID_HANDLE);
3951 goto end;
3954 if(printer->doc)
3956 SetLastError(ERROR_INVALID_PRINTER_STATE);
3957 goto end;
3960 /* Even if we're printing to a file we still add a print job, we'll
3961 just ignore the spool file name */
3963 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3965 ERR("AddJob failed gle %u\n", GetLastError());
3966 goto end;
3969 /* use pOutputFile only, when it is a real filename */
3970 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3971 filename = doc->pOutputFile;
3972 else
3973 filename = addjob->Path;
3975 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3976 if(hf == INVALID_HANDLE_VALUE)
3977 goto end;
3979 memset(&job_info, 0, sizeof(job_info));
3980 job_info.pDocument = doc->pDocName;
3981 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3983 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3984 printer->doc->hf = hf;
3985 ret = printer->doc->job_id = addjob->JobId;
3986 job = get_job(hPrinter, ret);
3987 job->portname = strdupW(doc->pOutputFile);
3989 end:
3990 LeaveCriticalSection(&printer_handles_cs);
3992 return ret;
3995 /*****************************************************************************
3996 * StartPagePrinter [WINSPOOL.@]
3998 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
4000 FIXME("(%p): stub\n", hPrinter);
4001 return TRUE;
4004 /*****************************************************************************
4005 * GetFormA [WINSPOOL.@]
4007 BOOL WINAPI GetFormA( HANDLE printer, char *name, DWORD level, BYTE *form, DWORD size, DWORD *needed )
4009 UNICODE_STRING nameW;
4010 const DWORD *string_info = form_string_info( level );
4011 BOOL ret;
4013 if (!string_info) return FALSE;
4015 asciitounicode( &nameW, name );
4017 ret = GetFormW( printer, nameW.Buffer, level, form, size, needed );
4018 if (ret) packed_struct_WtoA( form, string_info );
4020 RtlFreeUnicodeString( &nameW );
4021 return ret;
4024 /*****************************************************************************
4025 * GetFormW [WINSPOOL.@]
4027 BOOL WINAPI GetFormW( HANDLE printer, WCHAR *name, DWORD level, BYTE *form, DWORD size, DWORD *needed )
4029 HANDLE handle = get_backend_handle( printer );
4031 TRACE( "(%p, %s, %d, %p, %d, %p)\n", printer, debugstr_w( name ), level, form, size, needed );
4033 if (!handle)
4035 SetLastError( ERROR_INVALID_HANDLE );
4036 return FALSE;
4039 return backend->fpGetForm( handle, name, level, form, size, needed );
4042 /*****************************************************************************
4043 * SetFormA [WINSPOOL.@]
4045 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
4046 LPBYTE pForm)
4048 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
4049 return FALSE;
4052 /*****************************************************************************
4053 * SetFormW [WINSPOOL.@]
4055 BOOL WINAPI SetFormW( HANDLE printer, WCHAR *name, DWORD level, BYTE *form )
4057 HANDLE handle = get_backend_handle( printer );
4059 TRACE( "(%p, %s, %d, %p)\n", printer, debugstr_w( name ), level, form );
4061 if (!handle)
4063 SetLastError( ERROR_INVALID_HANDLE );
4064 return FALSE;
4067 return backend->fpSetForm( handle, name, level, form );
4070 /*****************************************************************************
4071 * ReadPrinter [WINSPOOL.@]
4073 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
4074 LPDWORD pNoBytesRead)
4076 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
4077 return FALSE;
4080 /*****************************************************************************
4081 * ResetPrinterA [WINSPOOL.@]
4083 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
4085 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
4086 return FALSE;
4089 /*****************************************************************************
4090 * ResetPrinterW [WINSPOOL.@]
4092 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
4094 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
4095 return FALSE;
4098 /*****************************************************************************
4099 * get_filename_from_reg [internal]
4101 * Get ValueName from hkey storing result in out
4102 * when the Value in the registry has only a filename, use driverdir as prefix
4103 * outlen is space left in out
4104 * String is stored either as unicode or ansi
4108 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
4109 LPBYTE out, DWORD outlen, LPDWORD needed)
4111 WCHAR filename[MAX_PATH];
4112 DWORD size;
4113 DWORD type;
4114 LONG ret;
4115 LPWSTR buffer = filename;
4116 LPWSTR ptr;
4118 *needed = 0;
4119 size = sizeof(filename);
4120 buffer[0] = '\0';
4121 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
4122 if (ret == ERROR_MORE_DATA) {
4123 TRACE("need dynamic buffer: %u\n", size);
4124 buffer = HeapAlloc(GetProcessHeap(), 0, size);
4125 if (!buffer) {
4126 /* No Memory is bad */
4127 return FALSE;
4129 buffer[0] = '\0';
4130 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
4133 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
4134 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
4135 return FALSE;
4138 ptr = buffer;
4139 while (ptr) {
4140 /* do we have a full path ? */
4141 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
4142 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
4144 if (!ret) {
4145 /* we must build the full Path */
4146 *needed += dirlen;
4147 if ((out) && (outlen > dirlen)) {
4148 lstrcpyW((LPWSTR)out, driverdir);
4149 out += dirlen;
4150 outlen -= dirlen;
4152 else
4153 out = NULL;
4156 /* write the filename */
4157 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
4158 if ((out) && (outlen >= size)) {
4159 lstrcpyW((LPWSTR)out, ptr);
4160 out += size;
4161 outlen -= size;
4163 else
4164 out = NULL;
4165 *needed += size;
4166 ptr += lstrlenW(ptr)+1;
4167 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
4170 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
4172 /* write the multisz-termination */
4173 if (type == REG_MULTI_SZ) {
4174 size = sizeof(WCHAR);
4176 *needed += size;
4177 if (out && (outlen >= size)) {
4178 memset (out, 0, size);
4181 return TRUE;
4184 /*****************************************************************************
4185 * WINSPOOL_GetStringFromReg
4187 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4188 * String is stored as unicode.
4190 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
4191 DWORD buflen, DWORD *needed)
4193 DWORD sz = buflen, type;
4194 LONG ret;
4196 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4197 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
4198 WARN("Got ret = %d\n", ret);
4199 *needed = 0;
4200 return FALSE;
4202 /* add space for terminating '\0' */
4203 sz += sizeof(WCHAR);
4204 *needed = sz;
4206 if (ptr)
4207 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
4209 return TRUE;
4212 /*****************************************************************************
4213 * WINSPOOL_GetDefaultDevMode
4215 * Get a default DevMode values for wineps.
4217 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr, DWORD buflen, DWORD *needed)
4219 static const WCHAR winepsW[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4221 if (buflen >= sizeof(DEVMODEW))
4223 DEVMODEW *dm = (DEVMODEW *)ptr;
4225 /* the driver will update registry with real values */
4226 memset(dm, 0, sizeof(*dm));
4227 dm->dmSize = sizeof(*dm);
4228 lstrcpyW(dm->dmDeviceName, winepsW);
4230 *needed = sizeof(DEVMODEW);
4233 /*****************************************************************************
4234 * WINSPOOL_GetDevModeFromReg
4236 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4237 * DevMode is stored either as unicode or ansi.
4239 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4240 LPBYTE ptr,
4241 DWORD buflen, DWORD *needed)
4243 DWORD sz = buflen, type;
4244 LONG ret;
4246 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4247 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4248 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4249 if (sz < sizeof(DEVMODEA))
4251 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4252 return FALSE;
4254 /* ensures that dmSize is not erratically bogus if registry is invalid */
4255 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4256 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4257 sz += (CCHDEVICENAME + CCHFORMNAME);
4258 if (ptr && (buflen >= sz)) {
4259 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4260 memcpy(ptr, dmW, sz);
4261 HeapFree(GetProcessHeap(),0,dmW);
4263 *needed = sz;
4264 return TRUE;
4267 /*********************************************************************
4268 * WINSPOOL_GetPrinter_1
4270 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4272 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
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 pi1->pName = (LPWSTR)ptr;
4284 ptr += size;
4285 left -= size;
4286 } else
4287 space = FALSE;
4288 *pcbNeeded += size;
4291 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4292 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4293 if(space && size <= left) {
4294 pi1->pDescription = (LPWSTR)ptr;
4295 ptr += size;
4296 left -= size;
4297 } else
4298 space = FALSE;
4299 *pcbNeeded += size;
4302 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4303 if(space && size <= left) {
4304 pi1->pComment = (LPWSTR)ptr;
4305 ptr += size;
4306 left -= size;
4307 } else
4308 space = FALSE;
4309 *pcbNeeded += size;
4312 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4314 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4315 memset(pi1, 0, sizeof(*pi1));
4317 return space;
4319 /*********************************************************************
4320 * WINSPOOL_GetPrinter_2
4322 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4324 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4325 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4327 DWORD size, left = cbBuf;
4328 BOOL space = (cbBuf > 0);
4329 LPBYTE ptr = buf;
4331 *pcbNeeded = 0;
4333 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4334 if(space && size <= left) {
4335 pi2->pPrinterName = (LPWSTR)ptr;
4336 ptr += size;
4337 left -= size;
4338 } else
4339 space = FALSE;
4340 *pcbNeeded += size;
4342 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4343 if(space && size <= left) {
4344 pi2->pShareName = (LPWSTR)ptr;
4345 ptr += size;
4346 left -= size;
4347 } else
4348 space = FALSE;
4349 *pcbNeeded += size;
4351 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4352 if(space && size <= left) {
4353 pi2->pPortName = (LPWSTR)ptr;
4354 ptr += size;
4355 left -= size;
4356 } else
4357 space = FALSE;
4358 *pcbNeeded += size;
4360 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4361 if(space && size <= left) {
4362 pi2->pDriverName = (LPWSTR)ptr;
4363 ptr += size;
4364 left -= size;
4365 } else
4366 space = FALSE;
4367 *pcbNeeded += size;
4369 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4370 if(space && size <= left) {
4371 pi2->pComment = (LPWSTR)ptr;
4372 ptr += size;
4373 left -= size;
4374 } else
4375 space = FALSE;
4376 *pcbNeeded += size;
4378 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4379 if(space && size <= left) {
4380 pi2->pLocation = (LPWSTR)ptr;
4381 ptr += size;
4382 left -= size;
4383 } else
4384 space = FALSE;
4385 *pcbNeeded += size;
4387 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4388 if(space && size <= left) {
4389 pi2->pDevMode = (LPDEVMODEW)ptr;
4390 ptr += size;
4391 left -= size;
4392 } else
4393 space = FALSE;
4394 *pcbNeeded += size;
4396 else
4398 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4399 if(space && size <= left) {
4400 pi2->pDevMode = (LPDEVMODEW)ptr;
4401 ptr += size;
4402 left -= size;
4403 } else
4404 space = FALSE;
4405 *pcbNeeded += size;
4407 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4408 if(space && size <= left) {
4409 pi2->pSepFile = (LPWSTR)ptr;
4410 ptr += size;
4411 left -= size;
4412 } else
4413 space = FALSE;
4414 *pcbNeeded += size;
4416 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4417 if(space && size <= left) {
4418 pi2->pPrintProcessor = (LPWSTR)ptr;
4419 ptr += size;
4420 left -= size;
4421 } else
4422 space = FALSE;
4423 *pcbNeeded += size;
4425 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4426 if(space && size <= left) {
4427 pi2->pDatatype = (LPWSTR)ptr;
4428 ptr += size;
4429 left -= size;
4430 } else
4431 space = FALSE;
4432 *pcbNeeded += size;
4434 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4435 if(space && size <= left) {
4436 pi2->pParameters = (LPWSTR)ptr;
4437 ptr += size;
4438 left -= size;
4439 } else
4440 space = FALSE;
4441 *pcbNeeded += size;
4443 if(pi2) {
4444 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4445 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4446 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4447 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4448 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4451 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4452 memset(pi2, 0, sizeof(*pi2));
4454 return space;
4457 /*********************************************************************
4458 * WINSPOOL_GetPrinter_4
4460 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4462 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4463 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4465 DWORD size, left = cbBuf;
4466 BOOL space = (cbBuf > 0);
4467 LPBYTE ptr = buf;
4469 *pcbNeeded = 0;
4471 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4472 if(space && size <= left) {
4473 pi4->pPrinterName = (LPWSTR)ptr;
4474 ptr += size;
4475 left -= size;
4476 } else
4477 space = FALSE;
4478 *pcbNeeded += size;
4480 if(pi4) {
4481 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4484 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4485 memset(pi4, 0, sizeof(*pi4));
4487 return space;
4490 /*********************************************************************
4491 * WINSPOOL_GetPrinter_5
4493 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4495 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4496 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4498 DWORD size, left = cbBuf;
4499 BOOL space = (cbBuf > 0);
4500 LPBYTE ptr = buf;
4502 *pcbNeeded = 0;
4504 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4505 if(space && size <= left) {
4506 pi5->pPrinterName = (LPWSTR)ptr;
4507 ptr += size;
4508 left -= size;
4509 } else
4510 space = FALSE;
4511 *pcbNeeded += size;
4513 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4514 if(space && size <= left) {
4515 pi5->pPortName = (LPWSTR)ptr;
4516 ptr += size;
4517 left -= size;
4518 } else
4519 space = FALSE;
4520 *pcbNeeded += size;
4522 if(pi5) {
4523 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4524 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4525 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4528 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4529 memset(pi5, 0, sizeof(*pi5));
4531 return space;
4534 /*********************************************************************
4535 * WINSPOOL_GetPrinter_7
4537 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4539 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4540 DWORD cbBuf, LPDWORD pcbNeeded)
4542 DWORD size, left = cbBuf;
4543 BOOL space = (cbBuf > 0);
4544 LPBYTE ptr = buf;
4546 *pcbNeeded = 0;
4548 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4550 ptr = NULL;
4551 size = sizeof(pi7->pszObjectGUID);
4553 if (space && size <= left) {
4554 pi7->pszObjectGUID = (LPWSTR)ptr;
4555 ptr += size;
4556 left -= size;
4557 } else
4558 space = FALSE;
4559 *pcbNeeded += size;
4560 if (pi7) {
4561 /* We do not have a Directory Service */
4562 pi7->dwAction = DSPRINT_UNPUBLISH;
4565 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4566 memset(pi7, 0, sizeof(*pi7));
4568 return space;
4571 /*********************************************************************
4572 * WINSPOOL_GetPrinter_9
4574 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4576 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4577 DWORD cbBuf, LPDWORD pcbNeeded)
4579 DWORD size;
4580 BOOL space = (cbBuf > 0);
4582 *pcbNeeded = 0;
4584 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4585 if(space && size <= cbBuf) {
4586 pi9->pDevMode = (LPDEVMODEW)buf;
4587 } else
4588 space = FALSE;
4589 *pcbNeeded += size;
4591 else
4593 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4594 if(space && size <= cbBuf) {
4595 pi9->pDevMode = (LPDEVMODEW)buf;
4596 } else
4597 space = FALSE;
4598 *pcbNeeded += size;
4601 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4602 memset(pi9, 0, sizeof(*pi9));
4604 return space;
4607 /*****************************************************************************
4608 * GetPrinterW [WINSPOOL.@]
4610 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4611 DWORD cbBuf, LPDWORD pcbNeeded)
4613 DWORD size, needed = 0, err;
4614 LPBYTE ptr = NULL;
4615 HKEY hkeyPrinter;
4616 BOOL ret;
4618 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4620 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4621 if (err)
4623 SetLastError( err );
4624 return FALSE;
4627 switch(Level) {
4628 case 1:
4630 PRINTER_INFO_1W *pi1 = (PRINTER_INFO_1W *)pPrinter;
4632 size = sizeof(PRINTER_INFO_1W);
4633 if (size <= cbBuf) {
4634 ptr = pPrinter + size;
4635 cbBuf -= size;
4636 memset(pPrinter, 0, size);
4637 } else {
4638 pi1 = NULL;
4639 cbBuf = 0;
4641 ret = WINSPOOL_GetPrinter_1(hkeyPrinter, pi1, ptr, cbBuf, &needed);
4642 needed += size;
4643 break;
4646 case 2:
4648 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4650 size = sizeof(PRINTER_INFO_2W);
4651 if(size <= cbBuf) {
4652 ptr = pPrinter + size;
4653 cbBuf -= size;
4654 memset(pPrinter, 0, size);
4655 } else {
4656 pi2 = NULL;
4657 cbBuf = 0;
4659 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4660 needed += size;
4661 break;
4664 case 4:
4666 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4668 size = sizeof(PRINTER_INFO_4W);
4669 if(size <= cbBuf) {
4670 ptr = pPrinter + size;
4671 cbBuf -= size;
4672 memset(pPrinter, 0, size);
4673 } else {
4674 pi4 = NULL;
4675 cbBuf = 0;
4677 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4678 needed += size;
4679 break;
4683 case 5:
4685 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4687 size = sizeof(PRINTER_INFO_5W);
4688 if(size <= cbBuf) {
4689 ptr = pPrinter + size;
4690 cbBuf -= size;
4691 memset(pPrinter, 0, size);
4692 } else {
4693 pi5 = NULL;
4694 cbBuf = 0;
4697 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4698 needed += size;
4699 break;
4703 case 6:
4705 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4707 size = sizeof(PRINTER_INFO_6);
4708 if (size <= cbBuf) {
4709 /* FIXME: We do not update the status yet */
4710 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4711 ret = TRUE;
4712 } else {
4713 ret = FALSE;
4716 needed += size;
4717 break;
4720 case 7:
4722 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4724 size = sizeof(PRINTER_INFO_7W);
4725 if (size <= cbBuf) {
4726 ptr = pPrinter + size;
4727 cbBuf -= size;
4728 memset(pPrinter, 0, size);
4729 } else {
4730 pi7 = NULL;
4731 cbBuf = 0;
4734 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4735 needed += size;
4736 break;
4740 case 8:
4741 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4742 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4743 /* fall through */
4744 case 9:
4746 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4748 size = sizeof(PRINTER_INFO_9W);
4749 if(size <= cbBuf) {
4750 ptr = pPrinter + size;
4751 cbBuf -= size;
4752 memset(pPrinter, 0, size);
4753 } else {
4754 pi9 = NULL;
4755 cbBuf = 0;
4758 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4759 needed += size;
4760 break;
4764 default:
4765 FIXME("Unimplemented level %d\n", Level);
4766 SetLastError(ERROR_INVALID_LEVEL);
4767 RegCloseKey(hkeyPrinter);
4768 return FALSE;
4771 RegCloseKey(hkeyPrinter);
4773 TRACE("returning %d needed = %d\n", ret, needed);
4774 if(pcbNeeded) *pcbNeeded = needed;
4775 if(!ret)
4776 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4777 return ret;
4780 /*****************************************************************************
4781 * GetPrinterA [WINSPOOL.@]
4783 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4784 DWORD cbBuf, LPDWORD pcbNeeded)
4786 BOOL ret;
4787 LPBYTE buf = NULL;
4789 if (cbBuf)
4790 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4792 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4793 if (ret)
4794 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4795 HeapFree(GetProcessHeap(), 0, buf);
4797 return ret;
4800 /*****************************************************************************
4801 * WINSPOOL_EnumPrintersW
4803 * Implementation of EnumPrintersW
4805 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4806 DWORD dwLevel, LPBYTE lpbPrinters,
4807 DWORD cbBuf, LPDWORD lpdwNeeded,
4808 LPDWORD lpdwReturned)
4811 HKEY hkeyPrinters, hkeyPrinter;
4812 WCHAR PrinterName[255];
4813 DWORD needed = 0, number = 0;
4814 DWORD used, i, left;
4815 PBYTE pi, buf;
4817 if(lpbPrinters)
4818 memset(lpbPrinters, 0, cbBuf);
4819 if(lpdwReturned)
4820 *lpdwReturned = 0;
4821 if(lpdwNeeded)
4822 *lpdwNeeded = 0;
4824 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4825 if(dwType == PRINTER_ENUM_DEFAULT)
4826 return TRUE;
4828 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4829 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4830 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4831 if (!dwType) {
4832 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4833 return TRUE;
4838 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4839 FIXME("dwType = %08x\n", dwType);
4840 SetLastError(ERROR_INVALID_FLAGS);
4841 return FALSE;
4844 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4845 ERROR_SUCCESS) {
4846 ERR("Can't create Printers key\n");
4847 return FALSE;
4850 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4851 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4852 RegCloseKey(hkeyPrinters);
4853 ERR("Can't query Printers key\n");
4854 return FALSE;
4856 TRACE("Found %d printers\n", number);
4858 switch(dwLevel) {
4859 case 1:
4860 used = number * sizeof(PRINTER_INFO_1W);
4861 break;
4862 case 2:
4863 used = number * sizeof(PRINTER_INFO_2W);
4864 break;
4865 case 4:
4866 used = number * sizeof(PRINTER_INFO_4W);
4867 break;
4868 case 5:
4869 used = number * sizeof(PRINTER_INFO_5W);
4870 break;
4872 default:
4873 SetLastError(ERROR_INVALID_LEVEL);
4874 RegCloseKey(hkeyPrinters);
4875 return FALSE;
4877 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4879 for(i = 0; i < number; i++) {
4880 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, ARRAY_SIZE(PrinterName)) != ERROR_SUCCESS) {
4881 ERR("Can't enum key number %d\n", i);
4882 RegCloseKey(hkeyPrinters);
4883 return FALSE;
4885 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4886 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4887 ERROR_SUCCESS) {
4888 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4889 RegCloseKey(hkeyPrinters);
4890 return FALSE;
4893 if(cbBuf > used) {
4894 buf = lpbPrinters + used;
4895 left = cbBuf - used;
4896 } else {
4897 buf = NULL;
4898 left = 0;
4901 switch(dwLevel) {
4902 case 1:
4903 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4904 left, &needed);
4905 used += needed;
4906 if(pi) pi += sizeof(PRINTER_INFO_1W);
4907 break;
4908 case 2:
4909 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4910 left, &needed);
4911 used += needed;
4912 if(pi) pi += sizeof(PRINTER_INFO_2W);
4913 break;
4914 case 4:
4915 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4916 left, &needed);
4917 used += needed;
4918 if(pi) pi += sizeof(PRINTER_INFO_4W);
4919 break;
4920 case 5:
4921 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4922 left, &needed);
4923 used += needed;
4924 if(pi) pi += sizeof(PRINTER_INFO_5W);
4925 break;
4926 default:
4927 ERR("Shouldn't be here!\n");
4928 RegCloseKey(hkeyPrinter);
4929 RegCloseKey(hkeyPrinters);
4930 return FALSE;
4932 RegCloseKey(hkeyPrinter);
4934 RegCloseKey(hkeyPrinters);
4936 if(lpdwNeeded)
4937 *lpdwNeeded = used;
4939 if(used > cbBuf) {
4940 if(lpbPrinters)
4941 memset(lpbPrinters, 0, cbBuf);
4942 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4943 return FALSE;
4945 if(lpdwReturned)
4946 *lpdwReturned = number;
4947 SetLastError(ERROR_SUCCESS);
4948 return TRUE;
4952 /******************************************************************
4953 * EnumPrintersW [WINSPOOL.@]
4955 * Enumerates the available printers, print servers and print
4956 * providers, depending on the specified flags, name and level.
4958 * RETURNS:
4960 * If level is set to 1:
4961 * Returns an array of PRINTER_INFO_1 data structures in the
4962 * lpbPrinters buffer.
4964 * If level is set to 2:
4965 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4966 * Returns an array of PRINTER_INFO_2 data structures in the
4967 * lpbPrinters buffer. Note that according to MSDN also an
4968 * OpenPrinter should be performed on every remote printer.
4970 * If level is set to 4 (officially WinNT only):
4971 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4972 * Fast: Only the registry is queried to retrieve printer names,
4973 * no connection to the driver is made.
4974 * Returns an array of PRINTER_INFO_4 data structures in the
4975 * lpbPrinters buffer.
4977 * If level is set to 5 (officially WinNT4/Win9x only):
4978 * Fast: Only the registry is queried to retrieve printer names,
4979 * no connection to the driver is made.
4980 * Returns an array of PRINTER_INFO_5 data structures in the
4981 * lpbPrinters buffer.
4983 * If level set to 3 or 6+:
4984 * returns zero (failure!)
4986 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4987 * for information.
4989 * BUGS:
4990 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4991 * - Only levels 2, 4 and 5 are implemented at the moment.
4992 * - 16-bit printer drivers are not enumerated.
4993 * - Returned amount of bytes used/needed does not match the real Windoze
4994 * implementation (as in this implementation, all strings are part
4995 * of the buffer, whereas Win32 keeps them somewhere else)
4996 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4998 * NOTE:
4999 * - In a regular Wine installation, no registry settings for printers
5000 * exist, which makes this function return an empty list.
5002 BOOL WINAPI EnumPrintersW(
5003 DWORD dwType, /* [in] Types of print objects to enumerate */
5004 LPWSTR lpszName, /* [in] name of objects to enumerate */
5005 DWORD dwLevel, /* [in] type of printer info structure */
5006 LPBYTE lpbPrinters, /* [out] buffer which receives info */
5007 DWORD cbBuf, /* [in] max size of buffer in bytes */
5008 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
5009 LPDWORD lpdwReturned /* [out] number of entries returned */
5012 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
5013 lpdwNeeded, lpdwReturned);
5016 /******************************************************************
5017 * EnumPrintersA [WINSPOOL.@]
5019 * See EnumPrintersW
5022 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
5023 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5025 BOOL ret;
5026 UNICODE_STRING pNameU;
5027 LPWSTR pNameW;
5028 LPBYTE pPrintersW;
5030 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
5031 pPrinters, cbBuf, pcbNeeded, pcReturned);
5033 pNameW = asciitounicode(&pNameU, pName);
5035 /* Request a buffer with a size, that is big enough for EnumPrintersW.
5036 MS Office need this */
5037 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
5039 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
5041 RtlFreeUnicodeString(&pNameU);
5042 if (ret) {
5043 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
5045 HeapFree(GetProcessHeap(), 0, pPrintersW);
5046 return ret;
5049 /*****************************************************************************
5050 * WINSPOOL_GetDriverInfoFromReg [internal]
5052 * Enters the information from the registry into the DRIVER_INFO struct
5054 * RETURNS
5055 * zero if the printer driver does not exist in the registry
5056 * (only if Level > 1) otherwise nonzero
5058 static BOOL WINSPOOL_GetDriverInfoFromReg(
5059 HKEY hkeyDrivers,
5060 LPWSTR DriverName,
5061 const printenv_t * env,
5062 DWORD Level,
5063 LPBYTE ptr, /* DRIVER_INFO */
5064 LPBYTE pDriverStrings, /* strings buffer */
5065 DWORD cbBuf, /* size of string buffer */
5066 LPDWORD pcbNeeded) /* space needed for str. */
5068 DWORD size, tmp;
5069 HKEY hkeyDriver;
5070 WCHAR driverdir[MAX_PATH];
5071 DWORD dirlen;
5072 LPBYTE strPtr = pDriverStrings;
5073 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
5075 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
5076 debugstr_w(DriverName), env,
5077 Level, di, pDriverStrings, cbBuf);
5079 if (di) ZeroMemory(di, di_sizeof[Level]);
5081 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
5082 if (*pcbNeeded <= cbBuf)
5083 strcpyW((LPWSTR)strPtr, DriverName);
5085 /* pName for level 1 has a different offset! */
5086 if (Level == 1) {
5087 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
5088 return TRUE;
5091 /* .cVersion and .pName for level > 1 */
5092 if (di) {
5093 di->cVersion = env->driverversion;
5094 di->pName = (LPWSTR) strPtr;
5095 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
5098 /* Reserve Space for the largest subdir and a Backslash*/
5099 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
5100 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
5101 /* Should never Fail */
5102 return FALSE;
5104 lstrcatW(driverdir, env->versionsubdir);
5105 lstrcatW(driverdir, backslashW);
5107 /* dirlen must not include the terminating zero */
5108 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
5110 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
5111 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
5112 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
5113 return FALSE;
5116 /* pEnvironment */
5117 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
5119 *pcbNeeded += size;
5120 if (*pcbNeeded <= cbBuf) {
5121 lstrcpyW((LPWSTR)strPtr, env->envname);
5122 if (di) di->pEnvironment = (LPWSTR)strPtr;
5123 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
5126 /* .pDriverPath is the Graphics rendering engine.
5127 The full Path is required to avoid a crash in some apps */
5128 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
5129 *pcbNeeded += size;
5130 if (*pcbNeeded <= cbBuf)
5131 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
5133 if (di) di->pDriverPath = (LPWSTR)strPtr;
5134 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
5137 /* .pDataFile: For postscript-drivers, this is the ppd-file */
5138 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
5139 *pcbNeeded += size;
5140 if (*pcbNeeded <= cbBuf)
5141 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
5143 if (di) di->pDataFile = (LPWSTR)strPtr;
5144 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5147 /* .pConfigFile is the Driver user Interface */
5148 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
5149 *pcbNeeded += size;
5150 if (*pcbNeeded <= cbBuf)
5151 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
5153 if (di) di->pConfigFile = (LPWSTR)strPtr;
5154 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5157 if (Level == 2 ) {
5158 RegCloseKey(hkeyDriver);
5159 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5160 return TRUE;
5163 if (Level == 5 ) {
5164 RegCloseKey(hkeyDriver);
5165 FIXME("level 5: incomplete\n");
5166 return TRUE;
5169 /* .pHelpFile */
5170 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
5171 *pcbNeeded += size;
5172 if (*pcbNeeded <= cbBuf)
5173 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
5175 if (di) di->pHelpFile = (LPWSTR)strPtr;
5176 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5179 /* .pDependentFiles */
5180 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
5181 *pcbNeeded += size;
5182 if (*pcbNeeded <= cbBuf)
5183 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
5185 if (di) di->pDependentFiles = (LPWSTR)strPtr;
5186 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5188 else if (GetVersion() & 0x80000000) {
5189 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
5190 size = 2 * sizeof(WCHAR);
5191 *pcbNeeded += size;
5192 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
5194 if (di) di->pDependentFiles = (LPWSTR)strPtr;
5195 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5198 /* .pMonitorName is the optional Language Monitor */
5199 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
5200 *pcbNeeded += size;
5201 if (*pcbNeeded <= cbBuf)
5202 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
5204 if (di) di->pMonitorName = (LPWSTR)strPtr;
5205 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5208 /* .pDefaultDataType */
5209 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
5210 *pcbNeeded += size;
5211 if(*pcbNeeded <= cbBuf)
5212 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
5214 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
5215 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5218 if (Level == 3 ) {
5219 RegCloseKey(hkeyDriver);
5220 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5221 return TRUE;
5224 /* .pszzPreviousNames */
5225 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
5226 *pcbNeeded += size;
5227 if(*pcbNeeded <= cbBuf)
5228 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
5230 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
5231 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5234 if (Level == 4 ) {
5235 RegCloseKey(hkeyDriver);
5236 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5237 return TRUE;
5240 /* support is missing, but not important enough for a FIXME */
5241 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5243 /* .pszMfgName */
5244 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5245 *pcbNeeded += size;
5246 if(*pcbNeeded <= cbBuf)
5247 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5249 if (di) di->pszMfgName = (LPWSTR)strPtr;
5250 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5253 /* .pszOEMUrl */
5254 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5255 *pcbNeeded += size;
5256 if(*pcbNeeded <= cbBuf)
5257 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5259 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5260 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5263 /* .pszHardwareID */
5264 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5265 *pcbNeeded += size;
5266 if(*pcbNeeded <= cbBuf)
5267 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5269 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5270 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5273 /* .pszProvider */
5274 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5275 *pcbNeeded += size;
5276 if(*pcbNeeded <= cbBuf)
5277 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5279 if (di) di->pszProvider = (LPWSTR)strPtr;
5280 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5283 if (Level == 6 ) {
5284 RegCloseKey(hkeyDriver);
5285 return TRUE;
5288 /* support is missing, but not important enough for a FIXME */
5289 TRACE("level 8: incomplete\n");
5291 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5292 RegCloseKey(hkeyDriver);
5293 return TRUE;
5296 /*****************************************************************************
5297 * GetPrinterDriverW [WINSPOOL.@]
5299 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5300 DWORD Level, LPBYTE pDriverInfo,
5301 DWORD cbBuf, LPDWORD pcbNeeded)
5303 LPCWSTR name;
5304 WCHAR DriverName[100];
5305 DWORD ret, type, size, needed = 0;
5306 LPBYTE ptr = NULL;
5307 HKEY hkeyPrinter, hkeyDrivers;
5308 const printenv_t * env;
5310 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5311 Level,pDriverInfo,cbBuf, pcbNeeded);
5313 if (cbBuf > 0)
5314 ZeroMemory(pDriverInfo, cbBuf);
5316 if (!(name = get_opened_printer_name(hPrinter))) {
5317 SetLastError(ERROR_INVALID_HANDLE);
5318 return FALSE;
5321 if (Level < 1 || Level == 7 || Level > 8) {
5322 SetLastError(ERROR_INVALID_LEVEL);
5323 return FALSE;
5326 env = validate_envW(pEnvironment);
5327 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5329 ret = open_printer_reg_key( name, &hkeyPrinter );
5330 if (ret)
5332 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5333 SetLastError( ret );
5334 return FALSE;
5337 size = sizeof(DriverName);
5338 DriverName[0] = 0;
5339 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5340 (LPBYTE)DriverName, &size);
5341 RegCloseKey(hkeyPrinter);
5342 if(ret != ERROR_SUCCESS) {
5343 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5344 return FALSE;
5347 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5348 if(!hkeyDrivers) {
5349 ERR("Can't create Drivers key\n");
5350 return FALSE;
5353 size = di_sizeof[Level];
5354 if ((size <= cbBuf) && pDriverInfo)
5355 ptr = pDriverInfo + size;
5357 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5358 env, Level, pDriverInfo, ptr,
5359 (cbBuf < size) ? 0 : cbBuf - size,
5360 &needed)) {
5361 RegCloseKey(hkeyDrivers);
5362 return FALSE;
5365 RegCloseKey(hkeyDrivers);
5367 if(pcbNeeded) *pcbNeeded = size + needed;
5368 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5369 if(cbBuf >= size + needed) return TRUE;
5370 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5371 return FALSE;
5374 /*****************************************************************************
5375 * GetPrinterDriverA [WINSPOOL.@]
5377 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5378 DWORD Level, LPBYTE pDriverInfo,
5379 DWORD cbBuf, LPDWORD pcbNeeded)
5381 BOOL ret;
5382 UNICODE_STRING pEnvW;
5383 PWSTR pwstrEnvW;
5384 LPBYTE buf = NULL;
5386 if (cbBuf)
5388 ZeroMemory(pDriverInfo, cbBuf);
5389 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5392 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5393 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5394 cbBuf, pcbNeeded);
5395 if (ret)
5396 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5398 HeapFree(GetProcessHeap(), 0, buf);
5400 RtlFreeUnicodeString(&pEnvW);
5401 return ret;
5404 /*****************************************************************************
5405 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5407 * Return the PATH for the Printer-Drivers (UNICODE)
5409 * PARAMS
5410 * pName [I] Servername (NT only) or NULL (local Computer)
5411 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5412 * Level [I] Structure-Level (must be 1)
5413 * pDriverDirectory [O] PTR to Buffer that receives the Result
5414 * cbBuf [I] Size of Buffer at pDriverDirectory
5415 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5416 * required for pDriverDirectory
5418 * RETURNS
5419 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5420 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5421 * if cbBuf is too small
5423 * Native Values returned in pDriverDirectory on Success:
5424 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5425 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5426 *| win9x(Windows 4.0): "%winsysdir%"
5428 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5430 * FIXME
5431 *- Only NULL or "" is supported for pName
5434 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5435 DWORD Level, LPBYTE pDriverDirectory,
5436 DWORD cbBuf, LPDWORD pcbNeeded)
5438 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5439 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5441 if ((backend == NULL) && !load_backend()) return FALSE;
5443 if (Level != 1) {
5444 /* (Level != 1) is ignored in win9x */
5445 SetLastError(ERROR_INVALID_LEVEL);
5446 return FALSE;
5448 if (pcbNeeded == NULL) {
5449 /* (pcbNeeded == NULL) is ignored in win9x */
5450 SetLastError(RPC_X_NULL_REF_POINTER);
5451 return FALSE;
5454 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5455 pDriverDirectory, cbBuf, pcbNeeded);
5460 /*****************************************************************************
5461 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5463 * Return the PATH for the Printer-Drivers (ANSI)
5465 * See GetPrinterDriverDirectoryW.
5467 * NOTES
5468 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5471 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5472 DWORD Level, LPBYTE pDriverDirectory,
5473 DWORD cbBuf, LPDWORD pcbNeeded)
5475 UNICODE_STRING nameW, environmentW;
5476 BOOL ret;
5477 DWORD pcbNeededW;
5478 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5479 WCHAR *driverDirectoryW = NULL;
5481 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5482 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5484 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5486 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5487 else nameW.Buffer = NULL;
5488 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5489 else environmentW.Buffer = NULL;
5491 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5492 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5493 if (ret) {
5494 DWORD needed;
5495 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5496 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5497 if(pcbNeeded)
5498 *pcbNeeded = needed;
5499 ret = needed <= cbBuf;
5500 } else
5501 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5503 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5505 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5506 RtlFreeUnicodeString(&environmentW);
5507 RtlFreeUnicodeString(&nameW);
5509 return ret;
5512 /*****************************************************************************
5513 * AddPrinterDriverA [WINSPOOL.@]
5515 * See AddPrinterDriverW.
5518 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5520 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5521 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5524 /******************************************************************************
5525 * AddPrinterDriverW (WINSPOOL.@)
5527 * Install a Printer Driver
5529 * PARAMS
5530 * pName [I] Servername or NULL (local Computer)
5531 * level [I] Level for the supplied DRIVER_INFO_*W struct
5532 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5534 * RESULTS
5535 * Success: TRUE
5536 * Failure: FALSE
5539 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5541 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5542 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5545 /*****************************************************************************
5546 * AddPrintProcessorA [WINSPOOL.@]
5548 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5549 LPSTR pPrintProcessorName)
5551 UNICODE_STRING NameW, EnvW, PathW, ProcessorW;
5552 BOOL ret;
5554 TRACE("(%s,%s,%s,%s)\n", debugstr_a(pName), debugstr_a(pEnvironment),
5555 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5557 asciitounicode(&NameW, pName);
5558 asciitounicode(&EnvW, pEnvironment);
5559 asciitounicode(&PathW, pPathName);
5560 asciitounicode(&ProcessorW, pPrintProcessorName);
5562 ret = AddPrintProcessorW(NameW.Buffer, EnvW.Buffer, PathW.Buffer, ProcessorW.Buffer);
5564 RtlFreeUnicodeString(&ProcessorW);
5565 RtlFreeUnicodeString(&PathW);
5566 RtlFreeUnicodeString(&EnvW);
5567 RtlFreeUnicodeString(&NameW);
5569 return ret;
5572 /*****************************************************************************
5573 * AddPrintProcessorW [WINSPOOL.@]
5575 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5576 LPWSTR pPrintProcessorName)
5578 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5579 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5580 return TRUE;
5583 /*****************************************************************************
5584 * AddPrintProvidorA [WINSPOOL.@]
5586 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5588 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5589 return FALSE;
5592 /*****************************************************************************
5593 * AddPrintProvidorW [WINSPOOL.@]
5595 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5597 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5598 return FALSE;
5601 /*****************************************************************************
5602 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5604 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5605 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5607 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5608 pDevModeOutput, pDevModeInput);
5609 return 0;
5612 /*****************************************************************************
5613 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5615 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5616 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5618 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5619 pDevModeOutput, pDevModeInput);
5620 return 0;
5623 /*****************************************************************************
5624 * PrinterProperties [WINSPOOL.@]
5626 * Displays a dialog to set the properties of the printer.
5628 * RETURNS
5629 * nonzero on success or zero on failure
5631 * BUGS
5632 * implemented as stub only
5634 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5635 HANDLE hPrinter /* [in] handle to printer object */
5637 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5638 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5639 return FALSE;
5642 /*****************************************************************************
5643 * EnumJobsA [WINSPOOL.@]
5646 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5647 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5648 LPDWORD pcReturned)
5650 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5651 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5653 if(pcbNeeded) *pcbNeeded = 0;
5654 if(pcReturned) *pcReturned = 0;
5655 return FALSE;
5659 /*****************************************************************************
5660 * EnumJobsW [WINSPOOL.@]
5663 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5664 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5665 LPDWORD pcReturned)
5667 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5668 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5670 if(pcbNeeded) *pcbNeeded = 0;
5671 if(pcReturned) *pcReturned = 0;
5672 return FALSE;
5675 /*****************************************************************************
5676 * WINSPOOL_EnumPrinterDrivers [internal]
5678 * Delivers information about all printer drivers installed on the
5679 * localhost or a given server
5681 * RETURNS
5682 * nonzero on success or zero on failure. If the buffer for the returned
5683 * information is too small the function will return an error
5685 * BUGS
5686 * - only implemented for localhost, foreign hosts will return an error
5688 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5689 DWORD Level, LPBYTE pDriverInfo,
5690 DWORD driver_index,
5691 DWORD cbBuf, LPDWORD pcbNeeded,
5692 LPDWORD pcFound, DWORD data_offset)
5694 { HKEY hkeyDrivers;
5695 DWORD i, size = 0;
5696 const printenv_t * env;
5698 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5699 debugstr_w(pName), debugstr_w(pEnvironment),
5700 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5702 env = validate_envW(pEnvironment);
5703 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5705 *pcFound = 0;
5707 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5708 if(!hkeyDrivers) {
5709 ERR("Can't open Drivers key\n");
5710 return FALSE;
5713 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5714 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5715 RegCloseKey(hkeyDrivers);
5716 ERR("Can't query Drivers key\n");
5717 return FALSE;
5719 TRACE("Found %d Drivers\n", *pcFound);
5721 /* get size of single struct
5722 * unicode and ascii structure have the same size
5724 size = di_sizeof[Level];
5726 if (data_offset == 0)
5727 data_offset = size * (*pcFound);
5728 *pcbNeeded = data_offset;
5730 for( i = 0; i < *pcFound; i++) {
5731 WCHAR DriverNameW[255];
5732 PBYTE table_ptr = NULL;
5733 PBYTE data_ptr = NULL;
5734 DWORD needed = 0;
5736 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, ARRAY_SIZE(DriverNameW)) != ERROR_SUCCESS) {
5737 ERR("Can't enum key number %d\n", i);
5738 RegCloseKey(hkeyDrivers);
5739 return FALSE;
5742 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5743 table_ptr = pDriverInfo + (driver_index + i) * size;
5744 if (pDriverInfo && *pcbNeeded <= cbBuf)
5745 data_ptr = pDriverInfo + *pcbNeeded;
5747 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5748 env, Level, table_ptr, data_ptr,
5749 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5750 &needed)) {
5751 RegCloseKey(hkeyDrivers);
5752 return FALSE;
5755 *pcbNeeded += needed;
5758 RegCloseKey(hkeyDrivers);
5760 if(cbBuf < *pcbNeeded){
5761 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5762 return FALSE;
5765 return TRUE;
5768 /*****************************************************************************
5769 * EnumPrinterDriversW [WINSPOOL.@]
5771 * see function EnumPrinterDrivers for RETURNS, BUGS
5773 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5774 LPBYTE pDriverInfo, DWORD cbBuf,
5775 LPDWORD pcbNeeded, LPDWORD pcReturned)
5777 static const WCHAR allW[] = {'a','l','l',0};
5778 BOOL ret;
5779 DWORD found;
5781 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5783 SetLastError(RPC_X_NULL_REF_POINTER);
5784 return FALSE;
5787 /* check for local drivers */
5788 if((pName) && (pName[0])) {
5789 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5790 SetLastError(ERROR_ACCESS_DENIED);
5791 return FALSE;
5794 /* check input parameter */
5795 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5796 SetLastError(ERROR_INVALID_LEVEL);
5797 return FALSE;
5800 if(pDriverInfo && cbBuf > 0)
5801 memset( pDriverInfo, 0, cbBuf);
5803 /* Exception: pull all printers */
5804 if (pEnvironment && !strcmpW(pEnvironment, allW))
5806 DWORD i, needed, bufsize = cbBuf;
5807 DWORD total_found = 0;
5808 DWORD data_offset;
5810 /* Precompute the overall total; we need this to know
5811 where pointers end and data begins (i.e. data_offset) */
5812 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
5814 needed = found = 0;
5815 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5816 NULL, 0, 0, &needed, &found, 0);
5817 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5818 total_found += found;
5821 data_offset = di_sizeof[Level] * total_found;
5823 *pcReturned = 0;
5824 *pcbNeeded = 0;
5825 total_found = 0;
5826 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
5828 needed = found = 0;
5829 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5830 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5831 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5832 else if (ret)
5833 *pcReturned += found;
5834 *pcbNeeded = needed;
5835 data_offset = needed;
5836 total_found += found;
5838 return ret;
5841 /* Normal behavior */
5842 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5843 0, cbBuf, pcbNeeded, &found, 0);
5844 if (ret)
5845 *pcReturned = found;
5847 return ret;
5850 /*****************************************************************************
5851 * EnumPrinterDriversA [WINSPOOL.@]
5853 * see function EnumPrinterDrivers for RETURNS, BUGS
5855 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5856 LPBYTE pDriverInfo, DWORD cbBuf,
5857 LPDWORD pcbNeeded, LPDWORD pcReturned)
5859 BOOL ret;
5860 UNICODE_STRING pNameW, pEnvironmentW;
5861 PWSTR pwstrNameW, pwstrEnvironmentW;
5862 LPBYTE buf = NULL;
5864 if (cbBuf)
5865 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5867 pwstrNameW = asciitounicode(&pNameW, pName);
5868 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5870 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5871 buf, cbBuf, pcbNeeded, pcReturned);
5872 if (ret)
5873 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5875 HeapFree(GetProcessHeap(), 0, buf);
5877 RtlFreeUnicodeString(&pNameW);
5878 RtlFreeUnicodeString(&pEnvironmentW);
5880 return ret;
5883 /******************************************************************************
5884 * EnumPortsA (WINSPOOL.@)
5886 * See EnumPortsW.
5889 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5890 LPDWORD pcbNeeded, LPDWORD pcReturned)
5892 BOOL res;
5893 LPBYTE bufferW = NULL;
5894 LPWSTR nameW = NULL;
5895 DWORD needed = 0;
5896 DWORD numentries = 0;
5897 INT len;
5899 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5900 cbBuf, pcbNeeded, pcReturned);
5902 /* convert servername to unicode */
5903 if (pName) {
5904 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5905 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5906 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5908 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5909 needed = cbBuf * sizeof(WCHAR);
5910 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5911 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5913 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5914 if (pcbNeeded) needed = *pcbNeeded;
5915 /* HeapReAlloc return NULL, when bufferW was NULL */
5916 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5917 HeapAlloc(GetProcessHeap(), 0, needed);
5919 /* Try again with the large Buffer */
5920 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5922 needed = pcbNeeded ? *pcbNeeded : 0;
5923 numentries = pcReturned ? *pcReturned : 0;
5926 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5927 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5929 if (res) {
5930 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5931 DWORD entrysize = 0;
5932 DWORD index;
5933 LPSTR ptr;
5934 LPPORT_INFO_2W pi2w;
5935 LPPORT_INFO_2A pi2a;
5937 needed = 0;
5938 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5940 /* First pass: calculate the size for all Entries */
5941 pi2w = (LPPORT_INFO_2W) bufferW;
5942 pi2a = (LPPORT_INFO_2A) pPorts;
5943 index = 0;
5944 while (index < numentries) {
5945 index++;
5946 needed += entrysize; /* PORT_INFO_?A */
5947 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5949 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5950 NULL, 0, NULL, NULL);
5951 if (Level > 1) {
5952 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5953 NULL, 0, NULL, NULL);
5954 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5955 NULL, 0, NULL, NULL);
5957 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5958 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5959 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5962 /* check for errors and quit on failure */
5963 if (cbBuf < needed) {
5964 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5965 res = FALSE;
5966 goto cleanup;
5968 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5969 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5970 cbBuf -= len ; /* free Bytes in the user-Buffer */
5971 pi2w = (LPPORT_INFO_2W) bufferW;
5972 pi2a = (LPPORT_INFO_2A) pPorts;
5973 index = 0;
5974 /* Second Pass: Fill the User Buffer (if we have one) */
5975 while ((index < numentries) && pPorts) {
5976 index++;
5977 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5978 pi2a->pPortName = ptr;
5979 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5980 ptr, cbBuf , NULL, NULL);
5981 ptr += len;
5982 cbBuf -= len;
5983 if (Level > 1) {
5984 pi2a->pMonitorName = ptr;
5985 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5986 ptr, cbBuf, NULL, NULL);
5987 ptr += len;
5988 cbBuf -= len;
5990 pi2a->pDescription = ptr;
5991 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5992 ptr, cbBuf, NULL, NULL);
5993 ptr += len;
5994 cbBuf -= len;
5996 pi2a->fPortType = pi2w->fPortType;
5997 pi2a->Reserved = 0; /* documented: "must be zero" */
6000 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
6001 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
6002 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
6006 cleanup:
6007 if (pcbNeeded) *pcbNeeded = needed;
6008 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6010 HeapFree(GetProcessHeap(), 0, nameW);
6011 HeapFree(GetProcessHeap(), 0, bufferW);
6013 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
6014 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
6016 return (res);
6020 /******************************************************************************
6021 * EnumPortsW (WINSPOOL.@)
6023 * Enumerate available Ports
6025 * PARAMS
6026 * pName [I] Servername or NULL (local Computer)
6027 * Level [I] Structure-Level (1 or 2)
6028 * pPorts [O] PTR to Buffer that receives the Result
6029 * cbBuf [I] Size of Buffer at pPorts
6030 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
6031 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
6033 * RETURNS
6034 * Success: TRUE
6035 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
6038 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6041 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
6042 cbBuf, pcbNeeded, pcReturned);
6044 if ((backend == NULL) && !load_backend()) return FALSE;
6046 /* Level is not checked in win9x */
6047 if (!Level || (Level > 2)) {
6048 WARN("level (%d) is ignored in win9x\n", Level);
6049 SetLastError(ERROR_INVALID_LEVEL);
6050 return FALSE;
6052 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
6053 SetLastError(RPC_X_NULL_REF_POINTER);
6054 return FALSE;
6057 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
6060 /******************************************************************************
6061 * GetDefaultPrinterW (WINSPOOL.@)
6063 * FIXME
6064 * This function must read the value from data 'device' of key
6065 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
6067 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
6069 BOOL retval = TRUE;
6070 DWORD insize, len;
6071 WCHAR *buffer, *ptr;
6073 if (!namesize)
6075 SetLastError(ERROR_INVALID_PARAMETER);
6076 return FALSE;
6079 /* make the buffer big enough for the stuff from the profile/registry,
6080 * the content must fit into the local buffer to compute the correct
6081 * size even if the extern buffer is too small or not given.
6082 * (20 for ,driver,port) */
6083 insize = *namesize;
6084 len = max(100, (insize + 20));
6085 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
6087 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
6089 SetLastError (ERROR_FILE_NOT_FOUND);
6090 retval = FALSE;
6091 goto end;
6093 TRACE("%s\n", debugstr_w(buffer));
6095 if ((ptr = strchrW(buffer, ',')) == NULL)
6097 SetLastError(ERROR_INVALID_NAME);
6098 retval = FALSE;
6099 goto end;
6102 *ptr = 0;
6103 *namesize = strlenW(buffer) + 1;
6104 if(!name || (*namesize > insize))
6106 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6107 retval = FALSE;
6108 goto end;
6110 strcpyW(name, buffer);
6112 end:
6113 HeapFree( GetProcessHeap(), 0, buffer);
6114 return retval;
6118 /******************************************************************************
6119 * GetDefaultPrinterA (WINSPOOL.@)
6121 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
6123 BOOL retval = TRUE;
6124 DWORD insize = 0;
6125 WCHAR *bufferW = NULL;
6127 if (!namesize)
6129 SetLastError(ERROR_INVALID_PARAMETER);
6130 return FALSE;
6133 if(name && *namesize) {
6134 insize = *namesize;
6135 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
6138 if(!GetDefaultPrinterW( bufferW, namesize)) {
6139 retval = FALSE;
6140 goto end;
6143 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
6144 NULL, NULL);
6145 if (!*namesize)
6147 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
6148 retval = FALSE;
6150 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
6152 end:
6153 HeapFree( GetProcessHeap(), 0, bufferW);
6154 return retval;
6158 /******************************************************************************
6159 * SetDefaultPrinterW (WINSPOOL.204)
6161 * Set the Name of the Default Printer
6163 * PARAMS
6164 * pszPrinter [I] Name of the Printer or NULL
6166 * RETURNS
6167 * Success: True
6168 * Failure: FALSE
6170 * NOTES
6171 * When the Parameter is NULL or points to an Empty String and
6172 * a Default Printer was already present, then this Function changes nothing.
6173 * Without a Default Printer and NULL (or an Empty String) as Parameter,
6174 * the First enumerated local Printer is used.
6177 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
6179 WCHAR default_printer[MAX_PATH];
6180 LPWSTR buffer = NULL;
6181 HKEY hreg;
6182 DWORD size;
6183 DWORD namelen;
6184 LONG lres;
6186 TRACE("(%s)\n", debugstr_w(pszPrinter));
6187 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
6189 default_printer[0] = '\0';
6190 size = ARRAY_SIZE(default_printer);
6192 /* if we have a default Printer, do nothing. */
6193 if (GetDefaultPrinterW(default_printer, &size))
6194 return TRUE;
6196 pszPrinter = NULL;
6197 /* we have no default Printer: search local Printers and use the first */
6198 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
6200 default_printer[0] = '\0';
6201 size = ARRAY_SIZE(default_printer);
6202 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
6204 pszPrinter = default_printer;
6205 TRACE("using %s\n", debugstr_w(pszPrinter));
6207 RegCloseKey(hreg);
6210 if (pszPrinter == NULL) {
6211 TRACE("no local printer found\n");
6212 SetLastError(ERROR_FILE_NOT_FOUND);
6213 return FALSE;
6217 /* "pszPrinter" is never empty or NULL here. */
6218 namelen = lstrlenW(pszPrinter);
6219 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
6220 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
6221 if (!buffer ||
6222 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
6223 HeapFree(GetProcessHeap(), 0, buffer);
6224 SetLastError(ERROR_FILE_NOT_FOUND);
6225 return FALSE;
6228 /* read the devices entry for the printer (driver,port) to build the string for the
6229 default device entry (printer,driver,port) */
6230 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
6231 buffer[namelen] = ',';
6232 namelen++; /* move index to the start of the driver */
6234 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
6235 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
6236 if (!lres) {
6237 HKEY hdev;
6239 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev))
6241 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (BYTE *)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6242 RegCloseKey(hdev);
6245 else
6247 if (lres != ERROR_FILE_NOT_FOUND)
6248 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6250 SetLastError(ERROR_INVALID_PRINTER_NAME);
6253 RegCloseKey(hreg);
6254 HeapFree(GetProcessHeap(), 0, buffer);
6255 return (lres == ERROR_SUCCESS);
6258 /******************************************************************************
6259 * SetDefaultPrinterA (WINSPOOL.202)
6261 * See SetDefaultPrinterW.
6264 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6266 LPWSTR bufferW = NULL;
6267 BOOL res;
6269 TRACE("(%s)\n", debugstr_a(pszPrinter));
6270 if(pszPrinter) {
6271 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6272 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6273 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6275 res = SetDefaultPrinterW(bufferW);
6276 HeapFree(GetProcessHeap(), 0, bufferW);
6277 return res;
6280 /******************************************************************************
6281 * SetPrinterDataExA (WINSPOOL.@)
6283 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6284 LPCSTR pValueName, DWORD Type,
6285 LPBYTE pData, DWORD cbData)
6287 HKEY hkeyPrinter, hkeySubkey;
6288 DWORD ret;
6290 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6291 debugstr_a(pValueName), Type, pData, cbData);
6293 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6294 != ERROR_SUCCESS)
6295 return ret;
6297 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6298 != ERROR_SUCCESS) {
6299 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6300 RegCloseKey(hkeyPrinter);
6301 return ret;
6303 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6304 RegCloseKey(hkeySubkey);
6305 RegCloseKey(hkeyPrinter);
6306 return ret;
6309 /******************************************************************************
6310 * SetPrinterDataExW (WINSPOOL.@)
6312 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6313 LPCWSTR pValueName, DWORD Type,
6314 LPBYTE pData, DWORD cbData)
6316 HKEY hkeyPrinter, hkeySubkey;
6317 DWORD ret;
6319 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6320 debugstr_w(pValueName), Type, pData, cbData);
6322 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6323 != ERROR_SUCCESS)
6324 return ret;
6326 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6327 != ERROR_SUCCESS) {
6328 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6329 RegCloseKey(hkeyPrinter);
6330 return ret;
6332 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6333 RegCloseKey(hkeySubkey);
6334 RegCloseKey(hkeyPrinter);
6335 return ret;
6338 /******************************************************************************
6339 * SetPrinterDataA (WINSPOOL.@)
6341 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6342 LPBYTE pData, DWORD cbData)
6344 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6345 pData, cbData);
6348 /******************************************************************************
6349 * SetPrinterDataW (WINSPOOL.@)
6351 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6352 LPBYTE pData, DWORD cbData)
6354 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6355 pData, cbData);
6358 /******************************************************************************
6359 * GetPrinterDataExA (WINSPOOL.@)
6361 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6362 LPCSTR pValueName, LPDWORD pType,
6363 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6365 opened_printer_t *printer;
6366 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6367 DWORD ret;
6369 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6370 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6372 printer = get_opened_printer(hPrinter);
6373 if(!printer) return ERROR_INVALID_HANDLE;
6375 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6376 if (ret) return ret;
6378 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6380 if (printer->name) {
6382 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6383 if (ret) {
6384 RegCloseKey(hkeyPrinters);
6385 return ret;
6387 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6388 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6389 RegCloseKey(hkeyPrinter);
6390 RegCloseKey(hkeyPrinters);
6391 return ret;
6394 *pcbNeeded = nSize;
6395 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6396 0, pType, pData, pcbNeeded);
6398 if (!ret && !pData) ret = ERROR_MORE_DATA;
6400 RegCloseKey(hkeySubkey);
6401 RegCloseKey(hkeyPrinter);
6402 RegCloseKey(hkeyPrinters);
6404 TRACE("--> %d\n", ret);
6405 return ret;
6408 /******************************************************************************
6409 * GetPrinterDataExW (WINSPOOL.@)
6411 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6412 LPCWSTR pValueName, LPDWORD pType,
6413 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6415 opened_printer_t *printer;
6416 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6417 DWORD ret;
6419 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6420 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6422 printer = get_opened_printer(hPrinter);
6423 if(!printer) return ERROR_INVALID_HANDLE;
6425 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6426 if (ret) return ret;
6428 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6430 if (printer->name) {
6432 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6433 if (ret) {
6434 RegCloseKey(hkeyPrinters);
6435 return ret;
6437 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6438 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6439 RegCloseKey(hkeyPrinter);
6440 RegCloseKey(hkeyPrinters);
6441 return ret;
6444 *pcbNeeded = nSize;
6445 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6446 0, pType, pData, pcbNeeded);
6448 if (!ret && !pData) ret = ERROR_MORE_DATA;
6450 RegCloseKey(hkeySubkey);
6451 RegCloseKey(hkeyPrinter);
6452 RegCloseKey(hkeyPrinters);
6454 TRACE("--> %d\n", ret);
6455 return ret;
6458 /******************************************************************************
6459 * GetPrinterDataA (WINSPOOL.@)
6461 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6462 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6464 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6465 pData, nSize, pcbNeeded);
6468 /******************************************************************************
6469 * GetPrinterDataW (WINSPOOL.@)
6471 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6472 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6474 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6475 pData, nSize, pcbNeeded);
6478 /*******************************************************************************
6479 * EnumPrinterDataExW [WINSPOOL.@]
6481 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6482 LPBYTE pEnumValues, DWORD cbEnumValues,
6483 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6485 HKEY hkPrinter, hkSubKey;
6486 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6487 cbValueNameLen, cbMaxValueLen, cbValueLen,
6488 cbBufSize, dwType;
6489 LPWSTR lpValueName;
6490 HANDLE hHeap;
6491 PBYTE lpValue;
6492 PPRINTER_ENUM_VALUESW ppev;
6494 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6496 if (pKeyName == NULL || *pKeyName == 0)
6497 return ERROR_INVALID_PARAMETER;
6499 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6500 if (ret != ERROR_SUCCESS)
6502 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6503 hPrinter, ret);
6504 return ret;
6507 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6508 if (ret != ERROR_SUCCESS)
6510 r = RegCloseKey (hkPrinter);
6511 if (r != ERROR_SUCCESS)
6512 WARN ("RegCloseKey returned %i\n", r);
6513 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6514 debugstr_w (pKeyName), ret);
6515 return ret;
6518 ret = RegCloseKey (hkPrinter);
6519 if (ret != ERROR_SUCCESS)
6521 ERR ("RegCloseKey returned %i\n", ret);
6522 r = RegCloseKey (hkSubKey);
6523 if (r != ERROR_SUCCESS)
6524 WARN ("RegCloseKey returned %i\n", r);
6525 return ret;
6528 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6529 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6530 if (ret != ERROR_SUCCESS)
6532 r = RegCloseKey (hkSubKey);
6533 if (r != ERROR_SUCCESS)
6534 WARN ("RegCloseKey returned %i\n", r);
6535 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6536 return ret;
6539 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6540 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6542 if (cValues == 0) /* empty key */
6544 r = RegCloseKey (hkSubKey);
6545 if (r != ERROR_SUCCESS)
6546 WARN ("RegCloseKey returned %i\n", r);
6547 *pcbEnumValues = *pnEnumValues = 0;
6548 return ERROR_SUCCESS;
6551 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6553 hHeap = GetProcessHeap ();
6554 if (hHeap == NULL)
6556 ERR ("GetProcessHeap failed\n");
6557 r = RegCloseKey (hkSubKey);
6558 if (r != ERROR_SUCCESS)
6559 WARN ("RegCloseKey returned %i\n", r);
6560 return ERROR_OUTOFMEMORY;
6563 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6564 if (lpValueName == NULL)
6566 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6567 r = RegCloseKey (hkSubKey);
6568 if (r != ERROR_SUCCESS)
6569 WARN ("RegCloseKey returned %i\n", r);
6570 return ERROR_OUTOFMEMORY;
6573 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6574 if (lpValue == NULL)
6576 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6577 if (HeapFree (hHeap, 0, lpValueName) == 0)
6578 WARN ("HeapFree failed with code %i\n", GetLastError ());
6579 r = RegCloseKey (hkSubKey);
6580 if (r != ERROR_SUCCESS)
6581 WARN ("RegCloseKey returned %i\n", r);
6582 return ERROR_OUTOFMEMORY;
6585 TRACE ("pass 1: calculating buffer required for all names and values\n");
6587 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6589 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6591 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6593 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6594 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6595 NULL, NULL, lpValue, &cbValueLen);
6596 if (ret != ERROR_SUCCESS)
6598 if (HeapFree (hHeap, 0, lpValue) == 0)
6599 WARN ("HeapFree failed with code %i\n", GetLastError ());
6600 if (HeapFree (hHeap, 0, lpValueName) == 0)
6601 WARN ("HeapFree failed with code %i\n", GetLastError ());
6602 r = RegCloseKey (hkSubKey);
6603 if (r != ERROR_SUCCESS)
6604 WARN ("RegCloseKey returned %i\n", r);
6605 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6606 return ret;
6609 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6610 debugstr_w (lpValueName), dwIndex,
6611 cbValueNameLen + 1, cbValueLen);
6613 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6614 cbBufSize += cbValueLen;
6617 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6619 *pcbEnumValues = cbBufSize;
6620 *pnEnumValues = cValues;
6622 if (cbEnumValues < cbBufSize) /* buffer too small */
6624 if (HeapFree (hHeap, 0, lpValue) == 0)
6625 WARN ("HeapFree failed with code %i\n", GetLastError ());
6626 if (HeapFree (hHeap, 0, lpValueName) == 0)
6627 WARN ("HeapFree failed with code %i\n", GetLastError ());
6628 r = RegCloseKey (hkSubKey);
6629 if (r != ERROR_SUCCESS)
6630 WARN ("RegCloseKey returned %i\n", r);
6631 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6632 return ERROR_MORE_DATA;
6635 TRACE ("pass 2: copying all names and values to buffer\n");
6637 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6638 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6640 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6642 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6643 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6644 NULL, &dwType, lpValue, &cbValueLen);
6645 if (ret != ERROR_SUCCESS)
6647 if (HeapFree (hHeap, 0, lpValue) == 0)
6648 WARN ("HeapFree failed with code %i\n", GetLastError ());
6649 if (HeapFree (hHeap, 0, lpValueName) == 0)
6650 WARN ("HeapFree failed with code %i\n", GetLastError ());
6651 r = RegCloseKey (hkSubKey);
6652 if (r != ERROR_SUCCESS)
6653 WARN ("RegCloseKey returned %i\n", r);
6654 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6655 return ret;
6658 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6659 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6660 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6661 pEnumValues += cbValueNameLen;
6663 /* return # of *bytes* (including trailing \0), not # of chars */
6664 ppev[dwIndex].cbValueName = cbValueNameLen;
6666 ppev[dwIndex].dwType = dwType;
6668 memcpy (pEnumValues, lpValue, cbValueLen);
6669 ppev[dwIndex].pData = pEnumValues;
6670 pEnumValues += cbValueLen;
6672 ppev[dwIndex].cbData = cbValueLen;
6674 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6675 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6678 if (HeapFree (hHeap, 0, lpValue) == 0)
6680 ret = GetLastError ();
6681 ERR ("HeapFree failed with code %i\n", ret);
6682 if (HeapFree (hHeap, 0, lpValueName) == 0)
6683 WARN ("HeapFree failed with code %i\n", GetLastError ());
6684 r = RegCloseKey (hkSubKey);
6685 if (r != ERROR_SUCCESS)
6686 WARN ("RegCloseKey returned %i\n", r);
6687 return ret;
6690 if (HeapFree (hHeap, 0, lpValueName) == 0)
6692 ret = GetLastError ();
6693 ERR ("HeapFree failed with code %i\n", ret);
6694 r = RegCloseKey (hkSubKey);
6695 if (r != ERROR_SUCCESS)
6696 WARN ("RegCloseKey returned %i\n", r);
6697 return ret;
6700 ret = RegCloseKey (hkSubKey);
6701 if (ret != ERROR_SUCCESS)
6703 ERR ("RegCloseKey returned %i\n", ret);
6704 return ret;
6707 return ERROR_SUCCESS;
6710 /*******************************************************************************
6711 * EnumPrinterDataExA [WINSPOOL.@]
6713 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6714 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6715 * what Windows 2000 SP1 does.
6718 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6719 LPBYTE pEnumValues, DWORD cbEnumValues,
6720 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6722 INT len;
6723 LPWSTR pKeyNameW;
6724 DWORD ret, dwIndex, dwBufSize;
6725 HANDLE hHeap;
6726 LPSTR pBuffer;
6728 TRACE ("%p %s\n", hPrinter, pKeyName);
6730 if (pKeyName == NULL || *pKeyName == 0)
6731 return ERROR_INVALID_PARAMETER;
6733 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6734 if (len == 0)
6736 ret = GetLastError ();
6737 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6738 return ret;
6741 hHeap = GetProcessHeap ();
6742 if (hHeap == NULL)
6744 ERR ("GetProcessHeap failed\n");
6745 return ERROR_OUTOFMEMORY;
6748 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6749 if (pKeyNameW == NULL)
6751 ERR ("Failed to allocate %i bytes from process heap\n",
6752 (LONG)(len * sizeof (WCHAR)));
6753 return ERROR_OUTOFMEMORY;
6756 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6758 ret = GetLastError ();
6759 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6760 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6761 WARN ("HeapFree failed with code %i\n", GetLastError ());
6762 return ret;
6765 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6766 pcbEnumValues, pnEnumValues);
6767 if (ret != ERROR_SUCCESS)
6769 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6770 WARN ("HeapFree failed with code %i\n", GetLastError ());
6771 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6772 return ret;
6775 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6777 ret = GetLastError ();
6778 ERR ("HeapFree failed with code %i\n", ret);
6779 return ret;
6782 if (*pnEnumValues == 0) /* empty key */
6783 return ERROR_SUCCESS;
6785 dwBufSize = 0;
6786 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6788 PPRINTER_ENUM_VALUESW ppev =
6789 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6791 if (dwBufSize < ppev->cbValueName)
6792 dwBufSize = ppev->cbValueName;
6794 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6795 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6796 dwBufSize = ppev->cbData;
6799 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6801 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6802 if (pBuffer == NULL)
6804 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6805 return ERROR_OUTOFMEMORY;
6808 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6810 PPRINTER_ENUM_VALUESW ppev =
6811 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6813 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6814 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6815 NULL);
6816 if (len == 0)
6818 ret = GetLastError ();
6819 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6820 if (HeapFree (hHeap, 0, pBuffer) == 0)
6821 WARN ("HeapFree failed with code %i\n", GetLastError ());
6822 return ret;
6825 memcpy (ppev->pValueName, pBuffer, len);
6827 TRACE ("Converted '%s' from Unicode to ANSI\n", pBuffer);
6829 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6830 ppev->dwType != REG_MULTI_SZ)
6831 continue;
6833 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6834 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6835 if (len == 0)
6837 ret = GetLastError ();
6838 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6839 if (HeapFree (hHeap, 0, pBuffer) == 0)
6840 WARN ("HeapFree failed with code %i\n", GetLastError ());
6841 return ret;
6844 memcpy (ppev->pData, pBuffer, len);
6846 TRACE ("Converted '%s' from Unicode to ANSI\n", pBuffer);
6847 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6850 if (HeapFree (hHeap, 0, pBuffer) == 0)
6852 ret = GetLastError ();
6853 ERR ("HeapFree failed with code %i\n", ret);
6854 return ret;
6857 return ERROR_SUCCESS;
6860 /******************************************************************************
6861 * AbortPrinter (WINSPOOL.@)
6863 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6865 FIXME("(%p), stub!\n", hPrinter);
6866 return TRUE;
6869 /******************************************************************************
6870 * AddPortA (WINSPOOL.@)
6872 * See AddPortW.
6875 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6877 LPWSTR nameW = NULL;
6878 LPWSTR monitorW = NULL;
6879 DWORD len;
6880 BOOL res;
6882 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6884 if (pName) {
6885 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6886 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6887 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6890 if (pMonitorName) {
6891 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6892 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6893 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6895 res = AddPortW(nameW, hWnd, monitorW);
6896 HeapFree(GetProcessHeap(), 0, nameW);
6897 HeapFree(GetProcessHeap(), 0, monitorW);
6898 return res;
6901 /******************************************************************************
6902 * AddPortW (WINSPOOL.@)
6904 * Add a Port for a specific Monitor
6906 * PARAMS
6907 * pName [I] Servername or NULL (local Computer)
6908 * hWnd [I] Handle to parent Window for the Dialog-Box
6909 * pMonitorName [I] Name of the Monitor that manage the Port
6911 * RETURNS
6912 * Success: TRUE
6913 * Failure: FALSE
6916 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6918 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6920 if ((backend == NULL) && !load_backend()) return FALSE;
6922 if (!pMonitorName) {
6923 SetLastError(RPC_X_NULL_REF_POINTER);
6924 return FALSE;
6927 return backend->fpAddPort(pName, hWnd, pMonitorName);
6930 /******************************************************************************
6931 * AddPortExA (WINSPOOL.@)
6933 * See AddPortExW.
6936 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6938 PORT_INFO_2W pi2W;
6939 PORT_INFO_2A * pi2A;
6940 LPWSTR nameW = NULL;
6941 LPWSTR monitorW = NULL;
6942 DWORD len;
6943 BOOL res;
6945 pi2A = (PORT_INFO_2A *) pBuffer;
6947 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6948 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6950 if ((level < 1) || (level > 2)) {
6951 SetLastError(ERROR_INVALID_LEVEL);
6952 return FALSE;
6955 if (!pi2A) {
6956 SetLastError(ERROR_INVALID_PARAMETER);
6957 return FALSE;
6960 if (pName) {
6961 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6962 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6963 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6966 if (pMonitorName) {
6967 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6968 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6969 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6972 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6974 if (pi2A->pPortName) {
6975 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6976 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6977 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6980 if (level > 1) {
6981 if (pi2A->pMonitorName) {
6982 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6983 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6984 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6987 if (pi2A->pDescription) {
6988 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6989 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6990 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6992 pi2W.fPortType = pi2A->fPortType;
6993 pi2W.Reserved = pi2A->Reserved;
6996 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6998 HeapFree(GetProcessHeap(), 0, nameW);
6999 HeapFree(GetProcessHeap(), 0, monitorW);
7000 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
7001 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
7002 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
7003 return res;
7007 /******************************************************************************
7008 * AddPortExW (WINSPOOL.@)
7010 * Add a Port for a specific Monitor, without presenting a user interface
7012 * PARAMS
7013 * pName [I] Servername or NULL (local Computer)
7014 * level [I] Structure-Level (1 or 2) for pBuffer
7015 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
7016 * pMonitorName [I] Name of the Monitor that manage the Port
7018 * RETURNS
7019 * Success: TRUE
7020 * Failure: FALSE
7023 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
7025 PORT_INFO_2W * pi2;
7027 pi2 = (PORT_INFO_2W *) pBuffer;
7029 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
7030 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
7031 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
7032 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
7034 if ((backend == NULL) && !load_backend()) return FALSE;
7036 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
7037 SetLastError(ERROR_INVALID_PARAMETER);
7038 return FALSE;
7041 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
7044 /******************************************************************************
7045 * AddPrinterConnectionA (WINSPOOL.@)
7047 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
7049 FIXME("%s\n", debugstr_a(pName));
7050 return FALSE;
7053 /******************************************************************************
7054 * AddPrinterConnectionW (WINSPOOL.@)
7056 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
7058 FIXME("%s\n", debugstr_w(pName));
7059 return FALSE;
7062 /******************************************************************************
7063 * AddPrinterDriverExW (WINSPOOL.@)
7065 * Install a Printer Driver with the Option to upgrade / downgrade the Files
7067 * PARAMS
7068 * pName [I] Servername or NULL (local Computer)
7069 * level [I] Level for the supplied DRIVER_INFO_*W struct
7070 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
7071 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
7073 * RESULTS
7074 * Success: TRUE
7075 * Failure: FALSE
7078 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
7080 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
7082 if ((backend == NULL) && !load_backend()) return FALSE;
7084 if (level < 2 || level == 5 || level == 7 || level > 8) {
7085 SetLastError(ERROR_INVALID_LEVEL);
7086 return FALSE;
7089 if (!pDriverInfo) {
7090 SetLastError(ERROR_INVALID_PARAMETER);
7091 return FALSE;
7094 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
7097 /******************************************************************************
7098 * AddPrinterDriverExA (WINSPOOL.@)
7100 * See AddPrinterDriverExW.
7103 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
7105 DRIVER_INFO_8A *diA;
7106 DRIVER_INFO_8W diW;
7107 LPWSTR nameW = NULL;
7108 DWORD lenA;
7109 DWORD len;
7110 BOOL res = FALSE;
7112 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
7114 diA = (DRIVER_INFO_8A *) pDriverInfo;
7115 ZeroMemory(&diW, sizeof(diW));
7117 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
7118 SetLastError(ERROR_INVALID_LEVEL);
7119 return FALSE;
7122 if (diA == NULL) {
7123 SetLastError(ERROR_INVALID_PARAMETER);
7124 return FALSE;
7127 /* convert servername to unicode */
7128 if (pName) {
7129 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7130 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7131 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7134 /* common fields */
7135 diW.cVersion = diA->cVersion;
7137 if (diA->pName) {
7138 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
7139 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7140 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
7143 if (diA->pEnvironment) {
7144 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
7145 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7146 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
7149 if (diA->pDriverPath) {
7150 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
7151 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7152 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
7155 if (diA->pDataFile) {
7156 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
7157 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7158 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
7161 if (diA->pConfigFile) {
7162 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
7163 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7164 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
7167 if ((Level > 2) && diA->pHelpFile) {
7168 len = MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, NULL, 0);
7169 diW.pHelpFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7170 MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, diW.pHelpFile, len);
7173 if ((Level > 2) && diA->pDependentFiles) {
7174 lenA = multi_sz_lenA(diA->pDependentFiles);
7175 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
7176 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7177 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
7180 if ((Level > 2) && diA->pMonitorName) {
7181 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
7182 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7183 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
7186 if ((Level > 2) && diA->pDefaultDataType) {
7187 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
7188 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7189 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
7192 if ((Level > 3) && diA->pszzPreviousNames) {
7193 lenA = multi_sz_lenA(diA->pszzPreviousNames);
7194 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
7195 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7196 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
7199 if (Level > 5) {
7200 diW.ftDriverDate = diA->ftDriverDate;
7201 diW.dwlDriverVersion = diA->dwlDriverVersion;
7204 if ((Level > 5) && diA->pszMfgName) {
7205 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
7206 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7207 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
7210 if ((Level > 5) && diA->pszOEMUrl) {
7211 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
7212 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7213 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
7216 if ((Level > 5) && diA->pszHardwareID) {
7217 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
7218 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7219 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
7222 if ((Level > 5) && diA->pszProvider) {
7223 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
7224 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7225 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
7228 if ((Level > 7) && diA->pszPrintProcessor) {
7229 len = MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, NULL, 0);
7230 diW.pszPrintProcessor = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7231 MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, diW.pszPrintProcessor, len);
7234 if ((Level > 7) && diA->pszVendorSetup) {
7235 len = MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, NULL, 0);
7236 diW.pszVendorSetup = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7237 MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, diW.pszVendorSetup, len);
7240 if ((Level > 7) && diA->pszzColorProfiles) {
7241 lenA = multi_sz_lenA(diA->pszzColorProfiles);
7242 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, NULL, 0);
7243 diW.pszzColorProfiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7244 MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, diW.pszzColorProfiles, len);
7247 if ((Level > 7) && diA->pszInfPath) {
7248 len = MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, NULL, 0);
7249 diW.pszInfPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7250 MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, diW.pszInfPath, len);
7253 if ((Level > 7) && diA->pszzCoreDriverDependencies) {
7254 lenA = multi_sz_lenA(diA->pszzCoreDriverDependencies);
7255 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, NULL, 0);
7256 diW.pszzCoreDriverDependencies = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7257 MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, diW.pszzCoreDriverDependencies, len);
7260 if (Level > 7) {
7261 diW.dwPrinterDriverAttributes = diA->dwPrinterDriverAttributes;
7262 diW.ftMinInboxDriverVerDate = diA->ftMinInboxDriverVerDate;
7263 diW.dwlMinInboxDriverVerVersion = diA->dwlMinInboxDriverVerVersion;
7266 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
7267 TRACE("got %u with %u\n", res, GetLastError());
7268 HeapFree(GetProcessHeap(), 0, nameW);
7269 HeapFree(GetProcessHeap(), 0, diW.pName);
7270 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
7271 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
7272 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
7273 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
7274 HeapFree(GetProcessHeap(), 0, diW.pHelpFile);
7275 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
7276 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
7277 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
7278 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
7279 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
7280 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
7281 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
7282 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
7283 HeapFree(GetProcessHeap(), 0, diW.pszPrintProcessor);
7284 HeapFree(GetProcessHeap(), 0, diW.pszVendorSetup);
7285 HeapFree(GetProcessHeap(), 0, diW.pszzColorProfiles);
7286 HeapFree(GetProcessHeap(), 0, diW.pszInfPath);
7287 HeapFree(GetProcessHeap(), 0, diW.pszzCoreDriverDependencies);
7289 TRACE("=> %u with %u\n", res, GetLastError());
7290 return res;
7293 /******************************************************************************
7294 * ConfigurePortA (WINSPOOL.@)
7296 * See ConfigurePortW.
7299 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7301 LPWSTR nameW = NULL;
7302 LPWSTR portW = NULL;
7303 INT len;
7304 DWORD res;
7306 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7308 /* convert servername to unicode */
7309 if (pName) {
7310 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7311 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7312 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7315 /* convert portname to unicode */
7316 if (pPortName) {
7317 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7318 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7319 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7322 res = ConfigurePortW(nameW, hWnd, portW);
7323 HeapFree(GetProcessHeap(), 0, nameW);
7324 HeapFree(GetProcessHeap(), 0, portW);
7325 return res;
7328 /******************************************************************************
7329 * ConfigurePortW (WINSPOOL.@)
7331 * Display the Configuration-Dialog for a specific Port
7333 * PARAMS
7334 * pName [I] Servername or NULL (local Computer)
7335 * hWnd [I] Handle to parent Window for the Dialog-Box
7336 * pPortName [I] Name of the Port, that should be configured
7338 * RETURNS
7339 * Success: TRUE
7340 * Failure: FALSE
7343 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7346 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7348 if ((backend == NULL) && !load_backend()) return FALSE;
7350 if (!pPortName) {
7351 SetLastError(RPC_X_NULL_REF_POINTER);
7352 return FALSE;
7355 return backend->fpConfigurePort(pName, hWnd, pPortName);
7358 /******************************************************************************
7359 * ConnectToPrinterDlg (WINSPOOL.@)
7361 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7363 FIXME("%p %x\n", hWnd, Flags);
7364 return NULL;
7367 /******************************************************************************
7368 * DeletePrinterConnectionA (WINSPOOL.@)
7370 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7372 FIXME("%s\n", debugstr_a(pName));
7373 return TRUE;
7376 /******************************************************************************
7377 * DeletePrinterConnectionW (WINSPOOL.@)
7379 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7381 FIXME("%s\n", debugstr_w(pName));
7382 return TRUE;
7385 /******************************************************************************
7386 * DeletePrinterDriverExW (WINSPOOL.@)
7388 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7389 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7391 HKEY hkey_drivers;
7392 BOOL ret = FALSE;
7394 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7395 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7397 if(pName && pName[0])
7399 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7400 SetLastError(ERROR_INVALID_PARAMETER);
7401 return FALSE;
7404 if(dwDeleteFlag)
7406 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7407 SetLastError(ERROR_INVALID_PARAMETER);
7408 return FALSE;
7411 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7413 if(!hkey_drivers)
7415 ERR("Can't open drivers key\n");
7416 return FALSE;
7419 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7420 ret = TRUE;
7422 RegCloseKey(hkey_drivers);
7424 return ret;
7427 /******************************************************************************
7428 * DeletePrinterDriverExA (WINSPOOL.@)
7430 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7431 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7433 UNICODE_STRING NameW, EnvW, DriverW;
7434 BOOL ret;
7436 asciitounicode(&NameW, pName);
7437 asciitounicode(&EnvW, pEnvironment);
7438 asciitounicode(&DriverW, pDriverName);
7440 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7442 RtlFreeUnicodeString(&DriverW);
7443 RtlFreeUnicodeString(&EnvW);
7444 RtlFreeUnicodeString(&NameW);
7446 return ret;
7449 /******************************************************************************
7450 * DeletePrinterDataExW (WINSPOOL.@)
7452 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7453 LPCWSTR pValueName)
7455 FIXME("%p %s %s\n", hPrinter,
7456 debugstr_w(pKeyName), debugstr_w(pValueName));
7457 return ERROR_INVALID_PARAMETER;
7460 /******************************************************************************
7461 * DeletePrinterDataExA (WINSPOOL.@)
7463 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7464 LPCSTR pValueName)
7466 FIXME("%p %s %s\n", hPrinter,
7467 debugstr_a(pKeyName), debugstr_a(pValueName));
7468 return ERROR_INVALID_PARAMETER;
7471 /******************************************************************************
7472 * DeletePrintProcessorA (WINSPOOL.@)
7474 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7476 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7477 debugstr_a(pPrintProcessorName));
7478 return TRUE;
7481 /******************************************************************************
7482 * DeletePrintProcessorW (WINSPOOL.@)
7484 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7486 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7487 debugstr_w(pPrintProcessorName));
7488 return TRUE;
7491 /******************************************************************************
7492 * DeletePrintProvidorA (WINSPOOL.@)
7494 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7496 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7497 debugstr_a(pPrintProviderName));
7498 return TRUE;
7501 /******************************************************************************
7502 * DeletePrintProvidorW (WINSPOOL.@)
7504 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7506 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7507 debugstr_w(pPrintProviderName));
7508 return TRUE;
7511 /******************************************************************************
7512 * EnumFormsA (WINSPOOL.@)
7514 BOOL WINAPI EnumFormsA( HANDLE printer, DWORD level, BYTE *form, DWORD size, DWORD *needed, DWORD *count )
7516 const DWORD *string_info = form_string_info( level );
7517 BOOL ret;
7518 DWORD i;
7520 if (!string_info) return FALSE;
7522 ret = EnumFormsW( printer, level, form, size, needed, count );
7523 if (ret)
7524 for (i = 0; i < *count; i++)
7525 packed_struct_WtoA( form + i * string_info[0], string_info );
7527 return ret;
7530 /******************************************************************************
7531 * EnumFormsW (WINSPOOL.@)
7533 BOOL WINAPI EnumFormsW( HANDLE printer, DWORD level, BYTE *form, DWORD size, DWORD *needed, DWORD *count )
7535 HANDLE handle = get_backend_handle( printer );
7537 TRACE( "(%p, %d, %p, %d, %p, %p)\n", printer, level, form, size, needed, count );
7539 if (!handle)
7541 SetLastError( ERROR_INVALID_HANDLE );
7542 return FALSE;
7545 if (!needed || !count)
7547 SetLastError( RPC_X_NULL_REF_POINTER );
7548 return FALSE;
7551 if (!form && size)
7553 SetLastError( ERROR_INVALID_USER_BUFFER );
7554 return FALSE;
7557 return backend->fpEnumForms( handle, level, form, size, needed, count );
7560 /*****************************************************************************
7561 * EnumMonitorsA [WINSPOOL.@]
7563 * See EnumMonitorsW.
7566 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7567 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7569 BOOL res;
7570 LPBYTE bufferW = NULL;
7571 LPWSTR nameW = NULL;
7572 DWORD needed = 0;
7573 DWORD numentries = 0;
7574 INT len;
7576 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7577 cbBuf, pcbNeeded, pcReturned);
7579 /* convert servername to unicode */
7580 if (pName) {
7581 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7582 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7583 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7585 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7586 needed = cbBuf * sizeof(WCHAR);
7587 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7588 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7590 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7591 if (pcbNeeded) needed = *pcbNeeded;
7592 /* HeapReAlloc return NULL, when bufferW was NULL */
7593 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7594 HeapAlloc(GetProcessHeap(), 0, needed);
7596 /* Try again with the large Buffer */
7597 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7599 numentries = pcReturned ? *pcReturned : 0;
7600 needed = 0;
7602 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7603 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7605 if (res) {
7606 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7607 DWORD entrysize = 0;
7608 DWORD index;
7609 LPSTR ptr;
7610 LPMONITOR_INFO_2W mi2w;
7611 LPMONITOR_INFO_2A mi2a;
7613 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7614 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7616 /* First pass: calculate the size for all Entries */
7617 mi2w = (LPMONITOR_INFO_2W) bufferW;
7618 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7619 index = 0;
7620 while (index < numentries) {
7621 index++;
7622 needed += entrysize; /* MONITOR_INFO_?A */
7623 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7625 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7626 NULL, 0, NULL, NULL);
7627 if (Level > 1) {
7628 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7629 NULL, 0, NULL, NULL);
7630 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7631 NULL, 0, NULL, NULL);
7633 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7634 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7635 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7638 /* check for errors and quit on failure */
7639 if (cbBuf < needed) {
7640 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7641 res = FALSE;
7642 goto emA_cleanup;
7644 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7645 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7646 cbBuf -= len ; /* free Bytes in the user-Buffer */
7647 mi2w = (LPMONITOR_INFO_2W) bufferW;
7648 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7649 index = 0;
7650 /* Second Pass: Fill the User Buffer (if we have one) */
7651 while ((index < numentries) && pMonitors) {
7652 index++;
7653 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7654 mi2a->pName = ptr;
7655 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7656 ptr, cbBuf , NULL, NULL);
7657 ptr += len;
7658 cbBuf -= len;
7659 if (Level > 1) {
7660 mi2a->pEnvironment = ptr;
7661 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7662 ptr, cbBuf, NULL, NULL);
7663 ptr += len;
7664 cbBuf -= len;
7666 mi2a->pDLLName = ptr;
7667 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7668 ptr, cbBuf, NULL, NULL);
7669 ptr += len;
7670 cbBuf -= len;
7672 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7673 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7674 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7677 emA_cleanup:
7678 if (pcbNeeded) *pcbNeeded = needed;
7679 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7681 HeapFree(GetProcessHeap(), 0, nameW);
7682 HeapFree(GetProcessHeap(), 0, bufferW);
7684 TRACE("returning %d with %d (%d byte for %d entries)\n",
7685 (res), GetLastError(), needed, numentries);
7687 return (res);
7691 /*****************************************************************************
7692 * EnumMonitorsW [WINSPOOL.@]
7694 * Enumerate available Port-Monitors
7696 * PARAMS
7697 * pName [I] Servername or NULL (local Computer)
7698 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7699 * pMonitors [O] PTR to Buffer that receives the Result
7700 * cbBuf [I] Size of Buffer at pMonitors
7701 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7702 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7704 * RETURNS
7705 * Success: TRUE
7706 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7709 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7710 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7713 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7714 cbBuf, pcbNeeded, pcReturned);
7716 if ((backend == NULL) && !load_backend()) return FALSE;
7718 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7719 SetLastError(RPC_X_NULL_REF_POINTER);
7720 return FALSE;
7723 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7726 /******************************************************************************
7727 * SpoolerInit (WINSPOOL.@)
7729 * Initialize the Spooler
7731 * RETURNS
7732 * Success: TRUE
7733 * Failure: FALSE
7735 * NOTES
7736 * The function fails on windows, when the spooler service is not running
7739 BOOL WINAPI SpoolerInit(void)
7742 if ((backend == NULL) && !load_backend()) return FALSE;
7743 return TRUE;
7746 /******************************************************************************
7747 * XcvDataW (WINSPOOL.@)
7749 * Execute commands in the Printmonitor DLL
7751 * PARAMS
7752 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7753 * pszDataName [i] Name of the command to execute
7754 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7755 * cbInputData [i] Size in Bytes of Buffer at pInputData
7756 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7757 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7758 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7759 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7761 * RETURNS
7762 * Success: TRUE
7763 * Failure: FALSE
7765 * NOTES
7766 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7767 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7769 * Minimal List of commands, that a Printmonitor DLL should support:
7771 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7772 *| "AddPort" : Add a Port
7773 *| "DeletePort": Delete a Port
7775 * Many Printmonitors support additional commands. Examples for localspl.dll:
7776 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7777 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7780 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7781 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7782 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7784 opened_printer_t *printer;
7786 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7787 pInputData, cbInputData, pOutputData,
7788 cbOutputData, pcbOutputNeeded, pdwStatus);
7790 if ((backend == NULL) && !load_backend()) return FALSE;
7792 printer = get_opened_printer(hXcv);
7793 if (!printer || (!printer->backend_printer)) {
7794 SetLastError(ERROR_INVALID_HANDLE);
7795 return FALSE;
7798 if (!pcbOutputNeeded) {
7799 SetLastError(ERROR_INVALID_PARAMETER);
7800 return FALSE;
7803 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7804 SetLastError(RPC_X_NULL_REF_POINTER);
7805 return FALSE;
7808 *pcbOutputNeeded = 0;
7810 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7811 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7815 /*****************************************************************************
7816 * EnumPrinterDataA [WINSPOOL.@]
7819 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7820 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7821 DWORD cbData, LPDWORD pcbData )
7823 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7824 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7825 return ERROR_NO_MORE_ITEMS;
7828 /*****************************************************************************
7829 * EnumPrinterDataW [WINSPOOL.@]
7832 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7833 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7834 DWORD cbData, LPDWORD pcbData )
7836 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7837 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7838 return ERROR_NO_MORE_ITEMS;
7841 /*****************************************************************************
7842 * EnumPrinterKeyA [WINSPOOL.@]
7845 DWORD WINAPI EnumPrinterKeyA(HANDLE printer, const CHAR *key, CHAR *subkey, DWORD size, DWORD *needed)
7847 FIXME("%p %s %p %x %p\n", printer, debugstr_a(key), subkey, size, needed);
7848 return ERROR_CALL_NOT_IMPLEMENTED;
7851 /*****************************************************************************
7852 * EnumPrinterKeyW [WINSPOOL.@]
7855 DWORD WINAPI EnumPrinterKeyW(HANDLE printer, const WCHAR *key, WCHAR *subkey, DWORD size, DWORD *needed)
7857 FIXME("%p %s %p %x %p\n", printer, debugstr_w(key), subkey, size, needed);
7858 return ERROR_CALL_NOT_IMPLEMENTED;
7861 /*****************************************************************************
7862 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7865 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7866 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7867 LPDWORD pcbNeeded, LPDWORD pcReturned)
7869 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7870 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7871 pcbNeeded, pcReturned);
7872 return FALSE;
7875 /*****************************************************************************
7876 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7879 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7880 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7881 LPDWORD pcbNeeded, LPDWORD pcReturned)
7883 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7884 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7885 pcbNeeded, pcReturned);
7886 return FALSE;
7889 /*****************************************************************************
7890 * EnumPrintProcessorsA [WINSPOOL.@]
7892 * See EnumPrintProcessorsW.
7895 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7896 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7898 BOOL res;
7899 LPBYTE bufferW = NULL;
7900 LPWSTR nameW = NULL;
7901 LPWSTR envW = NULL;
7902 DWORD needed = 0;
7903 DWORD numentries = 0;
7904 INT len;
7906 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7907 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7909 /* convert names to unicode */
7910 if (pName) {
7911 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7912 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7913 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7915 if (pEnvironment) {
7916 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7917 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7918 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7921 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7922 needed = cbBuf * sizeof(WCHAR);
7923 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7924 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7926 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7927 if (pcbNeeded) needed = *pcbNeeded;
7928 /* HeapReAlloc return NULL, when bufferW was NULL */
7929 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7930 HeapAlloc(GetProcessHeap(), 0, needed);
7932 /* Try again with the large Buffer */
7933 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7935 numentries = pcReturned ? *pcReturned : 0;
7936 needed = 0;
7938 if (res) {
7939 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7940 DWORD index;
7941 LPSTR ptr;
7942 PPRINTPROCESSOR_INFO_1W ppiw;
7943 PPRINTPROCESSOR_INFO_1A ppia;
7945 /* First pass: calculate the size for all Entries */
7946 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7947 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7948 index = 0;
7949 while (index < numentries) {
7950 index++;
7951 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7952 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7954 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7955 NULL, 0, NULL, NULL);
7957 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7958 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7961 /* check for errors and quit on failure */
7962 if (cbBuf < needed) {
7963 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7964 res = FALSE;
7965 goto epp_cleanup;
7968 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7969 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7970 cbBuf -= len ; /* free Bytes in the user-Buffer */
7971 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7972 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7973 index = 0;
7974 /* Second Pass: Fill the User Buffer (if we have one) */
7975 while ((index < numentries) && pPPInfo) {
7976 index++;
7977 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7978 ppia->pName = ptr;
7979 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7980 ptr, cbBuf , NULL, NULL);
7981 ptr += len;
7982 cbBuf -= len;
7984 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7985 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7989 epp_cleanup:
7990 if (pcbNeeded) *pcbNeeded = needed;
7991 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7993 HeapFree(GetProcessHeap(), 0, nameW);
7994 HeapFree(GetProcessHeap(), 0, envW);
7995 HeapFree(GetProcessHeap(), 0, bufferW);
7997 TRACE("returning %d with %d (%d byte for %d entries)\n",
7998 (res), GetLastError(), needed, numentries);
8000 return (res);
8003 /*****************************************************************************
8004 * EnumPrintProcessorsW [WINSPOOL.@]
8006 * Enumerate available Print Processors
8008 * PARAMS
8009 * pName [I] Servername or NULL (local Computer)
8010 * pEnvironment [I] Printing-Environment or NULL (Default)
8011 * Level [I] Structure-Level (Only 1 is allowed)
8012 * pPPInfo [O] PTR to Buffer that receives the Result
8013 * cbBuf [I] Size of Buffer at pPPInfo
8014 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
8015 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
8017 * RETURNS
8018 * Success: TRUE
8019 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
8022 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
8023 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
8026 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
8027 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
8029 if ((backend == NULL) && !load_backend()) return FALSE;
8031 if (!pcbNeeded || !pcReturned) {
8032 SetLastError(RPC_X_NULL_REF_POINTER);
8033 return FALSE;
8036 if (!pPPInfo && (cbBuf > 0)) {
8037 SetLastError(ERROR_INVALID_USER_BUFFER);
8038 return FALSE;
8041 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
8042 cbBuf, pcbNeeded, pcReturned);
8045 /*****************************************************************************
8046 * ExtDeviceMode [WINSPOOL.@]
8049 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
8050 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
8051 DWORD fMode)
8053 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
8054 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
8055 debugstr_a(pProfile), fMode);
8056 return -1;
8059 /*****************************************************************************
8060 * FindClosePrinterChangeNotification [WINSPOOL.@]
8063 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
8065 FIXME("Stub: %p\n", hChange);
8066 return TRUE;
8069 /*****************************************************************************
8070 * FindFirstPrinterChangeNotification [WINSPOOL.@]
8073 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
8074 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
8076 FIXME("Stub: %p %x %x %p\n",
8077 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
8078 return INVALID_HANDLE_VALUE;
8081 /*****************************************************************************
8082 * FindNextPrinterChangeNotification [WINSPOOL.@]
8085 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
8086 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
8088 FIXME("Stub: %p %p %p %p\n",
8089 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
8090 return FALSE;
8093 /*****************************************************************************
8094 * FreePrinterNotifyInfo [WINSPOOL.@]
8097 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
8099 FIXME("Stub: %p\n", pPrinterNotifyInfo);
8100 return TRUE;
8103 /*****************************************************************************
8104 * string_to_buf
8106 * Copies a unicode string into a buffer. The buffer will either contain unicode or
8107 * ansi depending on the unicode parameter.
8109 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
8111 if(!str)
8113 *size = 0;
8114 return TRUE;
8117 if(unicode)
8119 *size = (strlenW(str) + 1) * sizeof(WCHAR);
8120 if(*size <= cb)
8122 memcpy(ptr, str, *size);
8123 return TRUE;
8125 return FALSE;
8127 else
8129 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
8130 if(*size <= cb)
8132 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
8133 return TRUE;
8135 return FALSE;
8139 /*****************************************************************************
8140 * get_job_info_1
8142 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
8143 LPDWORD pcbNeeded, BOOL unicode)
8145 DWORD size, left = cbBuf;
8146 BOOL space = (cbBuf > 0);
8147 LPBYTE ptr = buf;
8149 *pcbNeeded = 0;
8151 if(space)
8153 ji1->JobId = job->job_id;
8156 string_to_buf(job->document_title, ptr, left, &size, unicode);
8157 if(space && size <= left)
8159 ji1->pDocument = (LPWSTR)ptr;
8160 ptr += size;
8161 left -= size;
8163 else
8164 space = FALSE;
8165 *pcbNeeded += size;
8167 if (job->printer_name)
8169 string_to_buf(job->printer_name, ptr, left, &size, unicode);
8170 if(space && size <= left)
8172 ji1->pPrinterName = (LPWSTR)ptr;
8173 ptr += size;
8174 left -= size;
8176 else
8177 space = FALSE;
8178 *pcbNeeded += size;
8181 return space;
8184 /*****************************************************************************
8185 * get_job_info_2
8187 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
8188 LPDWORD pcbNeeded, BOOL unicode)
8190 DWORD size, left = cbBuf;
8191 DWORD shift;
8192 BOOL space = (cbBuf > 0);
8193 LPBYTE ptr = buf;
8194 LPDEVMODEA dmA = NULL;
8195 LPDEVMODEW devmode;
8197 *pcbNeeded = 0;
8199 if(space)
8201 ji2->JobId = job->job_id;
8204 string_to_buf(job->document_title, ptr, left, &size, unicode);
8205 if(space && size <= left)
8207 ji2->pDocument = (LPWSTR)ptr;
8208 ptr += size;
8209 left -= size;
8211 else
8212 space = FALSE;
8213 *pcbNeeded += size;
8215 if (job->printer_name)
8217 string_to_buf(job->printer_name, ptr, left, &size, unicode);
8218 if(space && size <= left)
8220 ji2->pPrinterName = (LPWSTR)ptr;
8221 ptr += size;
8222 left -= size;
8224 else
8225 space = FALSE;
8226 *pcbNeeded += size;
8229 if (job->devmode)
8231 if (!unicode)
8233 dmA = DEVMODEdupWtoA(job->devmode);
8234 devmode = (LPDEVMODEW) dmA;
8235 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
8237 else
8239 devmode = job->devmode;
8240 size = devmode->dmSize + devmode->dmDriverExtra;
8243 if (!devmode)
8244 FIXME("Can't convert DEVMODE W to A\n");
8245 else
8247 /* align DEVMODE to a DWORD boundary */
8248 shift = (4 - (*pcbNeeded & 3)) & 3;
8249 size += shift;
8251 if (size <= left)
8253 ptr += shift;
8254 memcpy(ptr, devmode, size-shift);
8255 ji2->pDevMode = (LPDEVMODEW)ptr;
8256 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
8257 ptr += size-shift;
8258 left -= size;
8260 else
8261 space = FALSE;
8262 *pcbNeeded +=size;
8266 return space;
8269 /*****************************************************************************
8270 * get_job_info
8272 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8273 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
8275 BOOL ret = FALSE;
8276 DWORD needed = 0, size;
8277 job_t *job;
8278 LPBYTE ptr = pJob;
8280 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
8282 EnterCriticalSection(&printer_handles_cs);
8283 job = get_job(hPrinter, JobId);
8284 if(!job)
8285 goto end;
8287 switch(Level)
8289 case 1:
8290 size = sizeof(JOB_INFO_1W);
8291 if(cbBuf >= size)
8293 cbBuf -= size;
8294 ptr += size;
8295 memset(pJob, 0, size);
8297 else
8298 cbBuf = 0;
8299 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
8300 needed += size;
8301 break;
8303 case 2:
8304 size = sizeof(JOB_INFO_2W);
8305 if(cbBuf >= size)
8307 cbBuf -= size;
8308 ptr += size;
8309 memset(pJob, 0, size);
8311 else
8312 cbBuf = 0;
8313 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
8314 needed += size;
8315 break;
8317 case 3:
8318 size = sizeof(JOB_INFO_3);
8319 if(cbBuf >= size)
8321 cbBuf -= size;
8322 memset(pJob, 0, size);
8323 ret = TRUE;
8325 else
8326 cbBuf = 0;
8327 needed = size;
8328 break;
8330 default:
8331 SetLastError(ERROR_INVALID_LEVEL);
8332 goto end;
8334 if(pcbNeeded)
8335 *pcbNeeded = needed;
8336 end:
8337 LeaveCriticalSection(&printer_handles_cs);
8338 return ret;
8341 /*****************************************************************************
8342 * GetJobA [WINSPOOL.@]
8345 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8346 DWORD cbBuf, LPDWORD pcbNeeded)
8348 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8351 /*****************************************************************************
8352 * GetJobW [WINSPOOL.@]
8355 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8356 DWORD cbBuf, LPDWORD pcbNeeded)
8358 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8361 /*****************************************************************************
8362 * schedule_pipe
8364 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8366 #ifdef HAVE_FORK
8367 char *unixname, *cmdA;
8368 DWORD len;
8369 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8370 BOOL ret = FALSE;
8371 char buf[1024];
8372 pid_t pid, wret;
8373 int status;
8375 if(!(unixname = wine_get_unix_file_name(filename)))
8376 return FALSE;
8378 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8379 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8380 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8382 TRACE("printing with: %s\n", cmdA);
8384 if((file_fd = open(unixname, O_RDONLY)) == -1)
8385 goto end;
8387 if (pipe(fds))
8389 ERR("pipe() failed!\n");
8390 goto end;
8393 if ((pid = fork()) == 0)
8395 close(0);
8396 dup2(fds[0], 0);
8397 close(fds[1]);
8399 /* reset signals that we previously set to SIG_IGN */
8400 signal(SIGPIPE, SIG_DFL);
8402 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8403 _exit(1);
8405 else if (pid == -1)
8407 ERR("fork() failed!\n");
8408 goto end;
8411 close(fds[0]);
8412 fds[0] = -1;
8413 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8414 write(fds[1], buf, no_read);
8416 close(fds[1]);
8417 fds[1] = -1;
8419 /* reap child */
8420 do {
8421 wret = waitpid(pid, &status, 0);
8422 } while (wret < 0 && errno == EINTR);
8423 if (wret < 0)
8425 ERR("waitpid() failed!\n");
8426 goto end;
8428 if (!WIFEXITED(status) || WEXITSTATUS(status))
8430 ERR("child process failed! %d\n", status);
8431 goto end;
8434 ret = TRUE;
8436 end:
8437 if(file_fd != -1) close(file_fd);
8438 if(fds[0] != -1) close(fds[0]);
8439 if(fds[1] != -1) close(fds[1]);
8441 HeapFree(GetProcessHeap(), 0, cmdA);
8442 HeapFree(GetProcessHeap(), 0, unixname);
8443 return ret;
8444 #else
8445 return FALSE;
8446 #endif
8449 /*****************************************************************************
8450 * schedule_lpr
8452 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8454 static const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8455 WCHAR *cmd;
8456 BOOL r;
8458 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8459 sprintfW(cmd, fmtW, printer_name);
8461 r = schedule_pipe(cmd, filename);
8463 HeapFree(GetProcessHeap(), 0, cmd);
8464 return r;
8467 #ifdef SONAME_LIBCUPS
8468 /*****************************************************************************
8469 * get_cups_jobs_ticket_options
8471 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8472 * The CUPS scheduler only looks for these in Print-File requests, and since
8473 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8474 * parsed.
8476 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8478 FILE *fp = fopen( file, "r" );
8479 char buf[257]; /* DSC max of 256 + '\0' */
8480 const char *ps_adobe = "%!PS-Adobe-";
8481 const char *cups_job = "%cupsJobTicket:";
8483 if (!fp) return num_options;
8484 if (!fgets( buf, sizeof(buf), fp )) goto end;
8485 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8486 while (fgets( buf, sizeof(buf), fp ))
8488 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8489 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8492 end:
8493 fclose( fp );
8494 return num_options;
8497 static int get_cups_default_options( const char *printer, int num_options, cups_option_t **options )
8499 cups_dest_t *dest;
8500 int i;
8502 if (!pcupsGetNamedDest) return num_options;
8504 dest = pcupsGetNamedDest( NULL, printer, NULL );
8505 if (!dest) return num_options;
8507 for (i = 0; i < dest->num_options; i++)
8509 if (!pcupsGetOption( dest->options[i].name, num_options, *options ))
8510 num_options = pcupsAddOption( dest->options[i].name, dest->options[i].value,
8511 num_options, options );
8514 pcupsFreeDests( 1, dest );
8515 return num_options;
8517 #endif
8519 /*****************************************************************************
8520 * schedule_cups
8522 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8524 #ifdef SONAME_LIBCUPS
8525 if(pcupsPrintFile)
8527 char *unixname, *queue, *unix_doc_title;
8528 DWORD len;
8529 BOOL ret;
8530 int num_options = 0, i;
8531 cups_option_t *options = NULL;
8533 if(!(unixname = wine_get_unix_file_name(filename)))
8534 return FALSE;
8536 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8537 queue = HeapAlloc(GetProcessHeap(), 0, len);
8538 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8540 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8541 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8542 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8544 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8545 num_options = get_cups_default_options( queue, num_options, &options );
8547 TRACE( "printing via cups with options:\n" );
8548 for (i = 0; i < num_options; i++)
8549 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8551 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8552 if (ret == 0 && pcupsLastErrorString)
8553 WARN("cupsPrintFile failed with error %s\n", debugstr_a(pcupsLastErrorString()));
8555 pcupsFreeOptions( num_options, options );
8557 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8558 HeapFree(GetProcessHeap(), 0, queue);
8559 HeapFree(GetProcessHeap(), 0, unixname);
8560 return ret;
8562 else
8563 #endif
8565 return schedule_lpr(printer_name, filename);
8569 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8571 LPWSTR filename;
8573 switch(msg)
8575 case WM_INITDIALOG:
8576 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8577 return TRUE;
8579 case WM_COMMAND:
8580 if(HIWORD(wparam) == BN_CLICKED)
8582 if(LOWORD(wparam) == IDOK)
8584 HANDLE hf;
8585 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8586 LPWSTR *output;
8588 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8589 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8591 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8593 WCHAR caption[200], message[200];
8594 int mb_ret;
8596 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, ARRAY_SIZE(caption));
8597 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, ARRAY_SIZE(message));
8598 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8599 if(mb_ret == IDCANCEL)
8601 HeapFree(GetProcessHeap(), 0, filename);
8602 return TRUE;
8605 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8606 if(hf == INVALID_HANDLE_VALUE)
8608 WCHAR caption[200], message[200];
8610 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, ARRAY_SIZE(caption));
8611 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, ARRAY_SIZE(message));
8612 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8613 HeapFree(GetProcessHeap(), 0, filename);
8614 return TRUE;
8616 CloseHandle(hf);
8617 DeleteFileW(filename);
8618 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8619 *output = filename;
8620 EndDialog(hwnd, IDOK);
8621 return TRUE;
8623 if(LOWORD(wparam) == IDCANCEL)
8625 EndDialog(hwnd, IDCANCEL);
8626 return TRUE;
8629 return FALSE;
8631 return FALSE;
8634 /*****************************************************************************
8635 * get_filename
8637 static BOOL get_filename(LPWSTR *filename)
8639 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8640 file_dlg_proc, (LPARAM)filename) == IDOK;
8643 /*****************************************************************************
8644 * schedule_file
8646 static BOOL schedule_file(LPCWSTR filename)
8648 LPWSTR output = NULL;
8650 if(get_filename(&output))
8652 BOOL r;
8653 TRACE("copy to %s\n", debugstr_w(output));
8654 r = CopyFileW(filename, output, FALSE);
8655 HeapFree(GetProcessHeap(), 0, output);
8656 return r;
8658 return FALSE;
8661 /*****************************************************************************
8662 * schedule_unixfile
8664 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8666 int in_fd, out_fd, no_read;
8667 char buf[1024];
8668 BOOL ret = FALSE;
8669 char *unixname, *outputA;
8670 DWORD len;
8672 if(!(unixname = wine_get_unix_file_name(filename)))
8673 return FALSE;
8675 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8676 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8677 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8679 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8680 in_fd = open(unixname, O_RDONLY);
8681 if(out_fd == -1 || in_fd == -1)
8682 goto end;
8684 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8685 write(out_fd, buf, no_read);
8687 ret = TRUE;
8688 end:
8689 if(in_fd != -1) close(in_fd);
8690 if(out_fd != -1) close(out_fd);
8691 HeapFree(GetProcessHeap(), 0, outputA);
8692 HeapFree(GetProcessHeap(), 0, unixname);
8693 return ret;
8696 /*****************************************************************************
8697 * ScheduleJob [WINSPOOL.@]
8700 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8702 opened_printer_t *printer;
8703 BOOL ret = FALSE;
8704 struct list *cursor, *cursor2;
8706 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8707 EnterCriticalSection(&printer_handles_cs);
8708 printer = get_opened_printer(hPrinter);
8709 if(!printer)
8710 goto end;
8712 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8714 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8715 HANDLE hf;
8717 if(job->job_id != dwJobID) continue;
8719 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8720 if(hf != INVALID_HANDLE_VALUE)
8722 PRINTER_INFO_5W *pi5 = NULL;
8723 LPWSTR portname = job->portname;
8724 DWORD needed;
8725 HKEY hkey;
8726 WCHAR output[1024];
8727 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8728 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8730 if (!portname)
8732 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8733 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8734 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8735 portname = pi5->pPortName;
8737 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8738 debugstr_w(portname));
8740 output[0] = 0;
8742 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8743 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8745 DWORD type, count = sizeof(output);
8746 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8747 RegCloseKey(hkey);
8749 if(output[0] == '|')
8751 ret = schedule_pipe(output + 1, job->filename);
8753 else if(output[0])
8755 ret = schedule_unixfile(output, job->filename);
8757 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8759 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8761 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8763 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8765 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8767 ret = schedule_file(job->filename);
8769 else if(isalpha(portname[0]) && portname[1] == ':')
8771 TRACE("copying to %s\n", debugstr_w(portname));
8772 ret = CopyFileW(job->filename, portname, FALSE);
8774 else
8776 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8778 HeapFree(GetProcessHeap(), 0, pi5);
8779 CloseHandle(hf);
8780 DeleteFileW(job->filename);
8782 list_remove(cursor);
8783 HeapFree(GetProcessHeap(), 0, job->document_title);
8784 HeapFree(GetProcessHeap(), 0, job->printer_name);
8785 HeapFree(GetProcessHeap(), 0, job->portname);
8786 HeapFree(GetProcessHeap(), 0, job->filename);
8787 HeapFree(GetProcessHeap(), 0, job->devmode);
8788 HeapFree(GetProcessHeap(), 0, job);
8789 break;
8791 end:
8792 LeaveCriticalSection(&printer_handles_cs);
8793 return ret;
8796 /*****************************************************************************
8797 * StartDocDlgA [WINSPOOL.@]
8799 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8801 UNICODE_STRING usBuffer;
8802 DOCINFOW docW = { 0 };
8803 LPWSTR retW;
8804 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8805 LPSTR ret = NULL;
8807 docW.cbSize = sizeof(docW);
8808 if (doc->lpszDocName)
8810 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8811 if (!(docW.lpszDocName = docnameW)) goto failed;
8813 if (doc->lpszOutput)
8815 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8816 if (!(docW.lpszOutput = outputW)) goto failed;
8818 if (doc->lpszDatatype)
8820 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8821 if (!(docW.lpszDatatype = datatypeW)) goto failed;
8823 docW.fwType = doc->fwType;
8825 retW = StartDocDlgW(hPrinter, &docW);
8827 if(retW)
8829 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8830 ret = HeapAlloc(GetProcessHeap(), 0, len);
8831 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8832 HeapFree(GetProcessHeap(), 0, retW);
8835 failed:
8836 HeapFree(GetProcessHeap(), 0, datatypeW);
8837 HeapFree(GetProcessHeap(), 0, outputW);
8838 HeapFree(GetProcessHeap(), 0, docnameW);
8840 return ret;
8843 /*****************************************************************************
8844 * StartDocDlgW [WINSPOOL.@]
8846 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8847 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8848 * port is "FILE:". Also returns the full path if passed a relative path.
8850 * The caller should free the returned string from the process heap.
8852 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8854 LPWSTR ret = NULL;
8855 DWORD len, attr;
8857 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8859 PRINTER_INFO_5W *pi5;
8860 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8861 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8862 return NULL;
8863 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8864 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8865 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8867 HeapFree(GetProcessHeap(), 0, pi5);
8868 return NULL;
8870 HeapFree(GetProcessHeap(), 0, pi5);
8873 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8875 LPWSTR name;
8877 if (get_filename(&name))
8879 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8881 HeapFree(GetProcessHeap(), 0, name);
8882 return NULL;
8884 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8885 GetFullPathNameW(name, len, ret, NULL);
8886 HeapFree(GetProcessHeap(), 0, name);
8888 return ret;
8891 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8892 return NULL;
8894 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8895 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8897 attr = GetFileAttributesW(ret);
8898 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8900 HeapFree(GetProcessHeap(), 0, ret);
8901 ret = NULL;
8903 return ret;
8906 /*****************************************************************************
8907 * UploadPrinterDriverPackageA [WINSPOOL.@]
8909 HRESULT WINAPI UploadPrinterDriverPackageA( LPCSTR server, LPCSTR path, LPCSTR env,
8910 DWORD flags, HWND hwnd, LPSTR dst, PULONG dstlen )
8912 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server), debugstr_a(path), debugstr_a(env),
8913 flags, hwnd, dst, dstlen);
8914 return E_NOTIMPL;
8917 /*****************************************************************************
8918 * UploadPrinterDriverPackageW [WINSPOOL.@]
8920 HRESULT WINAPI UploadPrinterDriverPackageW( LPCWSTR server, LPCWSTR path, LPCWSTR env,
8921 DWORD flags, HWND hwnd, LPWSTR dst, PULONG dstlen )
8923 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server), debugstr_w(path), debugstr_w(env),
8924 flags, hwnd, dst, dstlen);
8925 return E_NOTIMPL;
8928 /*****************************************************************************
8929 * PerfOpen [WINSPOOL.@]
8931 DWORD WINAPI PerfOpen(LPWSTR context)
8933 FIXME("%s: stub\n", debugstr_w(context));
8934 return ERROR_SUCCESS;
8937 /*****************************************************************************
8938 * PerfClose [WINSPOOL.@]
8940 DWORD WINAPI PerfClose(void)
8942 FIXME("stub\n");
8943 return ERROR_SUCCESS;
8946 /*****************************************************************************
8947 * PerfCollect [WINSPOOL.@]
8949 DWORD WINAPI PerfCollect(LPWSTR query, LPVOID *data, LPDWORD size, LPDWORD obj_count)
8951 FIXME("%s, %p, %p, %p: stub\n", debugstr_w(query), data, size, obj_count);
8952 *size = 0;
8953 *obj_count = 0;
8954 return ERROR_SUCCESS;