mfplat: Implement MFCreateMediaBufferFromMediaType() for audio types.
[wine.git] / dlls / winspool.drv / info.c
blob0065801d9042a3b212f9a4ee43329fbdf0ada432
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 "wine/library.h"
111 #include "windef.h"
112 #include "winbase.h"
113 #include "winuser.h"
114 #include "winerror.h"
115 #include "winreg.h"
116 #include "wingdi.h"
117 #include "winspool.h"
118 #include "winternl.h"
119 #include "wine/windef16.h"
120 #include "wine/unicode.h"
121 #include "wine/debug.h"
122 #include "wine/list.h"
123 #include "winnls.h"
125 #include "ddk/winsplp.h"
126 #include "wspool.h"
128 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
130 /* ############################### */
132 static CRITICAL_SECTION printer_handles_cs;
133 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
135 0, 0, &printer_handles_cs,
136 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
137 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
139 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
141 /* ############################### */
143 typedef struct {
144 DWORD job_id;
145 HANDLE hf;
146 } started_doc_t;
148 typedef struct {
149 struct list jobs;
150 LONG ref;
151 } jobqueue_t;
153 typedef struct {
154 LPWSTR name;
155 LPWSTR printername;
156 HANDLE backend_printer;
157 jobqueue_t *queue;
158 started_doc_t *doc;
159 DEVMODEW *devmode;
160 } opened_printer_t;
162 typedef struct {
163 struct list entry;
164 DWORD job_id;
165 WCHAR *filename;
166 WCHAR *portname;
167 WCHAR *document_title;
168 WCHAR *printer_name;
169 LPDEVMODEW devmode;
170 } job_t;
173 typedef struct {
174 LPCWSTR envname;
175 LPCWSTR subdir;
176 DWORD driverversion;
177 LPCWSTR versionregpath;
178 LPCWSTR versionsubdir;
179 } printenv_t;
181 /* ############################### */
183 static opened_printer_t **printer_handles;
184 static UINT nb_printer_handles;
185 static LONG next_job_id = 1;
187 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
188 WORD fwCapability, LPSTR lpszOutput,
189 LPDEVMODEA lpdm );
190 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
191 LPSTR lpszDevice, LPSTR lpszPort,
192 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
193 DWORD fwMode );
195 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
196 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
197 'c','o','n','t','r','o','l','\\',
198 'P','r','i','n','t','\\',
199 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
200 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
202 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
203 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
204 'C','o','n','t','r','o','l','\\',
205 'P','r','i','n','t','\\',
206 'P','r','i','n','t','e','r','s',0};
208 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
209 'M','i','c','r','o','s','o','f','t','\\',
210 'W','i','n','d','o','w','s',' ','N','T','\\',
211 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
212 'W','i','n','d','o','w','s',0};
214 static const WCHAR user_printers_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 'D','e','v','i','c','e','s',0};
220 static const WCHAR WinNT_CV_PrinterPortsW[] = { '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 'P','r','i','n','t','e','r','P','o','r','t','s',0};
226 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
227 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
228 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
229 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
230 static const WCHAR subdir_x64W[] = {'x','6','4',0};
231 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
232 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
233 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
234 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
235 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
237 static const WCHAR AttributesW[] = {'A','t','t','r','i','b','u','t','e','s',0};
238 static const WCHAR backslashW[] = {'\\',0};
239 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
240 'i','o','n',' ','F','i','l','e',0};
241 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
242 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
243 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
244 static const WCHAR Default_PriorityW[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
245 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
246 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
247 static const WCHAR dnsTimeoutW[] = {'d','n','s','T','i','m','e','o','u','t',0};
248 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
249 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
250 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
251 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
252 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
253 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
254 static const WCHAR NameW[] = {'N','a','m','e',0};
255 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
256 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
257 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
258 static const WCHAR PortW[] = {'P','o','r','t',0};
259 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
260 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
261 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
262 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
263 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
264 static const WCHAR PriorityW[] = {'P','r','i','o','r','i','t','y',0};
265 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
266 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
267 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
268 static const WCHAR StartTimeW[] = {'S','t','a','r','t','T','i','m','e',0};
269 static const WCHAR StatusW[] = {'S','t','a','t','u','s',0};
270 static const WCHAR txTimeoutW[] = {'t','x','T','i','m','e','o','u','t',0};
271 static const WCHAR UntilTimeW[] = {'U','n','t','i','l','T','i','m','e',0};
272 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
273 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
274 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
275 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
276 static WCHAR rawW[] = {'R','A','W',0};
277 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
278 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
279 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
280 static const WCHAR commaW[] = {',',0};
281 static WCHAR emptyStringW[] = {0};
283 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
285 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
286 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
287 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
289 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
290 'D','o','c','u','m','e','n','t',0};
292 static const WCHAR PPD_Overrides[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
293 static const WCHAR DefaultPageSize[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
295 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
296 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
297 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
298 0, sizeof(DRIVER_INFO_8W)};
301 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
302 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
303 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
304 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
305 sizeof(PRINTER_INFO_9W)};
307 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
308 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
309 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
311 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
313 /******************************************************************
314 * validate the user-supplied printing-environment [internal]
316 * PARAMS
317 * env [I] PTR to Environment-String or NULL
319 * RETURNS
320 * Failure: NULL
321 * Success: PTR to printenv_t
323 * NOTES
324 * An empty string is handled the same way as NULL.
325 * SetLastError(ERROR_INVALID_ENVIRONMENT) is called on Failure
329 static const printenv_t * validate_envW(LPCWSTR env)
331 const printenv_t *result = NULL;
332 unsigned int i;
334 TRACE("testing %s\n", debugstr_w(env));
335 if (env && env[0])
337 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
339 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
341 result = all_printenv[i];
342 break;
346 if (result == NULL) {
347 FIXME("unsupported Environment: %s\n", debugstr_w(env));
348 SetLastError(ERROR_INVALID_ENVIRONMENT);
350 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
352 else
354 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
356 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
358 return result;
362 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
363 if passed a NULL string. This returns NULLs to the result.
365 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
367 if ( (src) )
369 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
370 return usBufferPtr->Buffer;
372 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
373 return NULL;
376 static LPWSTR strdupW(LPCWSTR p)
378 LPWSTR ret;
379 DWORD len;
381 if(!p) return NULL;
382 len = (strlenW(p) + 1) * sizeof(WCHAR);
383 ret = HeapAlloc(GetProcessHeap(), 0, len);
384 memcpy(ret, p, len);
385 return ret;
388 static LPSTR strdupWtoA( LPCWSTR str )
390 LPSTR ret;
391 INT len;
393 if (!str) return NULL;
394 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
395 ret = HeapAlloc( GetProcessHeap(), 0, len );
396 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
397 return ret;
400 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
402 DEVMODEW *ret;
404 if (!dm) return NULL;
405 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
406 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
407 return ret;
410 /***********************************************************
411 * DEVMODEdupWtoA
412 * Creates an ansi copy of supplied devmode
414 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
416 LPDEVMODEA dmA;
417 DWORD size;
419 if (!dmW) return NULL;
420 size = dmW->dmSize - CCHDEVICENAME -
421 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
423 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
424 if (!dmA) return NULL;
426 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
427 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
429 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
431 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
432 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
434 else
436 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
437 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
438 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
439 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
441 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
444 dmA->dmSize = size;
445 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
446 return dmA;
450 /******************************************************************
451 * verify, that the filename is a local file
454 static inline BOOL is_local_file(LPWSTR name)
456 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
459 /* ################################ */
461 static int multi_sz_lenA(const char *str)
463 const char *ptr = str;
464 if(!str) return 0;
467 ptr += lstrlenA(ptr) + 1;
468 } while(*ptr);
470 return ptr - str + 1;
473 /*****************************************************************************
474 * get_dword_from_reg
476 * Return DWORD associated with name from hkey.
478 static DWORD get_dword_from_reg( HKEY hkey, const WCHAR *name )
480 DWORD sz = sizeof(DWORD), type, value = 0;
481 LONG ret;
483 ret = RegQueryValueExW( hkey, name, 0, &type, (LPBYTE)&value, &sz );
485 if (ret != ERROR_SUCCESS)
487 WARN( "Got ret = %d on name %s\n", ret, debugstr_w(name) );
488 return 0;
490 if (type != REG_DWORD)
492 ERR( "Got type %d\n", type );
493 return 0;
495 return value;
498 static inline DWORD set_reg_DWORD( HKEY hkey, const WCHAR *keyname, const DWORD value )
500 return RegSetValueExW( hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value) );
503 /******************************************************************
504 * get_opened_printer
505 * Get the pointer to the opened printer referred by the handle
507 static opened_printer_t *get_opened_printer(HANDLE hprn)
509 UINT_PTR idx = (UINT_PTR)hprn;
510 opened_printer_t *ret = NULL;
512 EnterCriticalSection(&printer_handles_cs);
514 if ((idx > 0) && (idx <= nb_printer_handles)) {
515 ret = printer_handles[idx - 1];
517 LeaveCriticalSection(&printer_handles_cs);
518 return ret;
521 /******************************************************************
522 * get_opened_printer_name
523 * Get the pointer to the opened printer name referred by the handle
525 static LPCWSTR get_opened_printer_name(HANDLE hprn)
527 opened_printer_t *printer = get_opened_printer(hprn);
528 if(!printer) return NULL;
529 return printer->name;
532 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
534 HKEY printers;
535 DWORD err;
537 *key = NULL;
538 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
539 if (err) return err;
541 err = RegOpenKeyW( printers, name, key );
542 if (err) err = ERROR_INVALID_PRINTER_NAME;
543 RegCloseKey( printers );
544 return err;
547 /******************************************************************
548 * WINSPOOL_GetOpenedPrinterRegKey
551 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
553 LPCWSTR name = get_opened_printer_name(hPrinter);
555 if(!name) return ERROR_INVALID_HANDLE;
556 return open_printer_reg_key( name, phkey );
559 static void
560 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
561 char qbuf[200];
563 /* If forcing, or no profile string entry for device yet, set the entry
565 * The always change entry if not WINEPS yet is discussable.
567 if (force ||
568 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
569 !strcmp(qbuf,"*") ||
570 !strstr(qbuf,"WINEPS.DRV")
572 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
573 HKEY hkey;
575 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
576 WriteProfileStringA("windows","device",buf);
577 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
578 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
579 RegCloseKey(hkey);
581 HeapFree(GetProcessHeap(),0,buf);
585 static BOOL add_printer_driver(const WCHAR *name, WCHAR *ppd)
587 DRIVER_INFO_3W di3;
588 unsigned int i;
589 BOOL res;
591 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
592 di3.cVersion = 3;
593 di3.pName = (WCHAR*)name;
594 di3.pDriverPath = driver_nt;
595 di3.pDataFile = ppd;
596 di3.pConfigFile = driver_nt;
597 di3.pDefaultDataType = rawW;
599 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
601 di3.pEnvironment = (WCHAR *) all_printenv[i]->envname;
602 if (all_printenv[i]->envname == envname_win40W)
604 /* We use wineps16.drv as driver for 16 bit */
605 di3.pDriverPath = driver_9x;
606 di3.pConfigFile = driver_9x;
608 res = AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY );
609 TRACE("got %d and %d for %s (%s)\n", res, GetLastError(), debugstr_w(name), debugstr_w(di3.pEnvironment));
611 if (!res && (GetLastError() != ERROR_PRINTER_DRIVER_ALREADY_INSTALLED))
613 ERR("failed with %u for %s (%s) %s\n", GetLastError(), debugstr_w(name),
614 debugstr_w(di3.pEnvironment), debugstr_w(di3.pDriverPath));
615 return FALSE;
619 return TRUE;
622 static inline char *expand_env_string( char *str, DWORD type )
624 if (type == REG_EXPAND_SZ)
626 char *tmp;
627 DWORD needed = ExpandEnvironmentStringsA( str, NULL, 0 );
628 tmp = HeapAlloc( GetProcessHeap(), 0, needed );
629 if (tmp)
631 ExpandEnvironmentStringsA( str, tmp, needed );
632 HeapFree( GetProcessHeap(), 0, str );
633 return tmp;
636 return str;
639 static char *get_fallback_ppd_name( const char *printer_name )
641 static const WCHAR ppds_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
642 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
643 HKEY hkey;
644 DWORD needed, type;
645 char *ret = NULL;
647 if (RegOpenKeyW( HKEY_CURRENT_USER, ppds_key, &hkey ) == ERROR_SUCCESS )
649 const char *value_name = NULL;
651 if (RegQueryValueExA( hkey, printer_name, 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
652 value_name = printer_name;
653 else if (RegQueryValueExA( hkey, "generic", 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
654 value_name = "generic";
656 if (value_name)
658 ret = HeapAlloc( GetProcessHeap(), 0, needed );
659 if (!ret) return NULL;
660 RegQueryValueExA( hkey, value_name, 0, &type, (BYTE *)ret, &needed );
662 RegCloseKey( hkey );
663 if (ret) return expand_env_string( ret, type );
665 return NULL;
668 static BOOL copy_file( const char *src, const char *dst )
670 int fds[2] = {-1, -1}, num;
671 char buf[1024];
672 BOOL ret = FALSE;
674 fds[0] = open( src, O_RDONLY );
675 fds[1] = open( dst, O_CREAT | O_TRUNC | O_WRONLY, 0666 );
676 if (fds[0] == -1 || fds[1] == -1) goto fail;
678 while ((num = read( fds[0], buf, sizeof(buf) )) != 0)
680 if (num == -1) goto fail;
681 if (write( fds[1], buf, num ) != num) goto fail;
683 ret = TRUE;
685 fail:
686 if (fds[1] != -1) close( fds[1] );
687 if (fds[0] != -1) close( fds[0] );
688 return ret;
691 static BOOL get_internal_fallback_ppd( const WCHAR *ppd )
693 static const WCHAR typeW[] = {'P','P','D','F','I','L','E',0};
695 char *ptr, *end;
696 DWORD size, written;
697 HANDLE file;
698 BOOL ret;
699 HRSRC res = FindResourceW( WINSPOOL_hInstance, MAKEINTRESOURCEW(1), typeW );
701 if (!res || !(ptr = LoadResource( WINSPOOL_hInstance, res ))) return FALSE;
702 size = SizeofResource( WINSPOOL_hInstance, res );
703 end = memchr( ptr, 0, size ); /* resource file may contain additional nulls */
704 if (end) size = end - ptr;
705 file = CreateFileW( ppd, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0 );
706 if (file == INVALID_HANDLE_VALUE) return FALSE;
707 ret = WriteFile( file, ptr, size, &written, NULL ) && written == size;
708 CloseHandle( file );
709 if (ret) TRACE( "using internal fallback for %s\n", debugstr_w( ppd ));
710 else DeleteFileW( ppd );
711 return ret;
714 static BOOL get_fallback_ppd( const char *printer_name, const WCHAR *ppd )
716 char *dst, *src = get_fallback_ppd_name( printer_name );
717 BOOL ret = FALSE;
719 if (!src) return get_internal_fallback_ppd( ppd );
721 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name), debugstr_w(ppd), debugstr_a(src) );
723 if (!(dst = wine_get_unix_file_name( ppd ))) goto fail;
725 if (symlink( src, dst ) == -1)
726 if (errno != ENOSYS || !copy_file( src, dst ))
727 goto fail;
729 ret = TRUE;
730 fail:
731 HeapFree( GetProcessHeap(), 0, dst );
732 HeapFree( GetProcessHeap(), 0, src );
733 return ret;
736 static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
738 static const WCHAR dot_ppd[] = {'.','p','p','d',0};
739 int len = (strlenW( dir ) + strlenW( file_name )) * sizeof(WCHAR) + sizeof(dot_ppd);
740 WCHAR *ppd = HeapAlloc( GetProcessHeap(), 0, len );
742 if (!ppd) return NULL;
743 strcpyW( ppd, dir );
744 strcatW( ppd, file_name );
745 strcatW( ppd, dot_ppd );
747 return ppd;
750 static WCHAR *get_ppd_dir( void )
752 static const WCHAR wine_ppds[] = {'w','i','n','e','_','p','p','d','s','\\',0};
753 DWORD len;
754 WCHAR *dir, tmp_path[MAX_PATH];
755 BOOL res;
757 len = GetTempPathW( ARRAY_SIZE( tmp_path ), tmp_path );
758 if (!len) return NULL;
759 dir = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
760 if (!dir) return NULL;
762 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
763 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
764 res = CreateDirectoryW( dir, NULL );
765 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
767 HeapFree( GetProcessHeap(), 0, dir );
768 dir = NULL;
770 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
771 return dir;
774 static void unlink_ppd( const WCHAR *ppd )
776 char *unix_name = wine_get_unix_file_name( ppd );
777 unlink( unix_name );
778 HeapFree( GetProcessHeap(), 0, unix_name );
781 #ifdef SONAME_LIBCUPS
783 static void *cupshandle;
785 #define CUPS_FUNCS \
786 DO_FUNC(cupsAddOption); \
787 DO_FUNC(cupsFreeDests); \
788 DO_FUNC(cupsFreeOptions); \
789 DO_FUNC(cupsGetDests); \
790 DO_FUNC(cupsGetOption); \
791 DO_FUNC(cupsParseOptions); \
792 DO_FUNC(cupsPrintFile)
793 #define CUPS_OPT_FUNCS \
794 DO_FUNC(cupsGetNamedDest); \
795 DO_FUNC(cupsGetPPD); \
796 DO_FUNC(cupsGetPPD3); \
797 DO_FUNC(cupsLastErrorString)
799 #define DO_FUNC(f) static typeof(f) *p##f
800 CUPS_FUNCS;
801 #undef DO_FUNC
802 static cups_dest_t * (*pcupsGetNamedDest)(http_t *, const char *, const char *);
803 static const char * (*pcupsGetPPD)(const char *);
804 static http_status_t (*pcupsGetPPD3)(http_t *, const char *, time_t *, char *, size_t);
805 static const char * (*pcupsLastErrorString)(void);
807 static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name,
808 time_t *modtime, char *buffer,
809 size_t bufsize )
811 const char *ppd;
813 if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
815 if (!pcupsGetPPD) return HTTP_NOT_FOUND;
817 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
819 *modtime = 0;
820 ppd = pcupsGetPPD( name );
822 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
824 if (!ppd) return HTTP_NOT_FOUND;
826 if (rename( ppd, buffer ) == -1)
828 BOOL res = copy_file( ppd, buffer );
829 unlink( ppd );
830 if (!res) return HTTP_NOT_FOUND;
832 return HTTP_OK;
835 static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
837 time_t modtime = 0;
838 http_status_t http_status;
839 char *unix_name = wine_get_unix_file_name( ppd );
841 TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
843 if (!unix_name) return FALSE;
845 http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
846 unix_name, strlen( unix_name ) + 1 );
848 if (http_status != HTTP_OK) unlink( unix_name );
849 HeapFree( GetProcessHeap(), 0, unix_name );
851 if (http_status == HTTP_OK) return TRUE;
853 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
854 debugstr_a(printer_name), http_status );
855 return get_fallback_ppd( printer_name, ppd );
858 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
860 const char *value;
861 WCHAR *ret;
862 int len;
864 value = pcupsGetOption( name, num_options, options );
865 if (!value) return NULL;
867 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
868 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
869 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
871 return ret;
874 static cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
876 WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
877 cups_ptype_t ret = 0;
879 if (type && *type)
881 ret = (cups_ptype_t)strtoulW( type, &end, 10 );
882 if (*end) ret = 0;
884 HeapFree( GetProcessHeap(), 0, type );
885 return ret;
888 static void load_cups(void)
890 cupshandle = wine_dlopen( SONAME_LIBCUPS, RTLD_NOW, NULL, 0 );
891 if (!cupshandle) return;
893 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
895 #define DO_FUNC(x) \
896 p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); \
897 if (!p##x) \
899 ERR("failed to load symbol %s\n", #x); \
900 cupshandle = NULL; \
901 return; \
903 CUPS_FUNCS;
904 #undef DO_FUNC
905 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 )
906 CUPS_OPT_FUNCS;
907 #undef DO_FUNC
910 static BOOL CUPS_LoadPrinters(void)
912 int i, nrofdests;
913 BOOL hadprinter = FALSE, haddefault = FALSE;
914 cups_dest_t *dests;
915 PRINTER_INFO_2W pi2;
916 WCHAR *port, *ppd_dir = NULL, *ppd;
917 HKEY hkeyPrinter, hkeyPrinters;
918 WCHAR nameW[MAX_PATH];
919 HANDLE added_printer;
920 cups_ptype_t printer_type;
922 if (!cupshandle) return FALSE;
924 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
925 ERROR_SUCCESS) {
926 ERR("Can't create Printers key\n");
927 return FALSE;
930 nrofdests = pcupsGetDests(&dests);
931 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
932 for (i=0;i<nrofdests;i++) {
933 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, ARRAY_SIZE(nameW));
934 printer_type = get_cups_printer_type( dests + i );
936 TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
938 if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
940 TRACE( "skipping scanner-only device\n" );
941 continue;
944 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
945 lstrcpyW(port, CUPS_Port);
946 lstrcatW(port, nameW);
948 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
949 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
950 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
951 and continue */
952 TRACE("Printer already exists\n");
953 /* overwrite old LPR:* port */
954 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
955 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
956 /* flag that the PPD file should be checked for an update */
957 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
958 RegCloseKey(hkeyPrinter);
959 } else {
960 BOOL added_driver = FALSE;
962 if (!ppd_dir && !(ppd_dir = get_ppd_dir()))
964 HeapFree( GetProcessHeap(), 0, port );
965 break;
967 ppd = get_ppd_filename( ppd_dir, nameW );
968 if (get_cups_ppd( dests[i].name, ppd ))
970 added_driver = add_printer_driver( nameW, ppd );
971 unlink_ppd( ppd );
973 HeapFree( GetProcessHeap(), 0, ppd );
974 if (!added_driver)
976 HeapFree( GetProcessHeap(), 0, port );
977 continue;
980 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
981 pi2.pPrinterName = nameW;
982 pi2.pDatatype = rawW;
983 pi2.pPrintProcessor = WinPrintW;
984 pi2.pDriverName = nameW;
985 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
986 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
987 pi2.pPortName = port;
988 pi2.pParameters = emptyStringW;
989 pi2.pShareName = emptyStringW;
990 pi2.pSepFile = emptyStringW;
992 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
993 if (added_printer) ClosePrinter( added_printer );
994 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
995 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
997 HeapFree( GetProcessHeap(), 0, pi2.pComment );
998 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
1000 HeapFree( GetProcessHeap(), 0, port );
1002 hadprinter = TRUE;
1003 if (dests[i].is_default) {
1004 SetDefaultPrinterW(nameW);
1005 haddefault = TRUE;
1009 if (ppd_dir)
1011 RemoveDirectoryW( ppd_dir );
1012 HeapFree( GetProcessHeap(), 0, ppd_dir );
1015 if (hadprinter && !haddefault) {
1016 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, ARRAY_SIZE(nameW));
1017 SetDefaultPrinterW(nameW);
1019 pcupsFreeDests(nrofdests, dests);
1020 RegCloseKey(hkeyPrinters);
1021 return TRUE;
1024 #endif
1026 static char *get_queue_name( HANDLE printer, BOOL *cups )
1028 WCHAR *port, *name = NULL;
1029 DWORD err, needed, type;
1030 char *ret = NULL;
1031 HKEY key;
1033 *cups = FALSE;
1035 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1036 if (err) return NULL;
1037 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1038 if (err) goto end;
1039 port = HeapAlloc( GetProcessHeap(), 0, needed );
1040 if (!port) goto end;
1041 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1043 if (!strncmpW( port, CUPS_Port, ARRAY_SIZE( CUPS_Port ) -1 ))
1045 name = port + ARRAY_SIZE( CUPS_Port ) - 1;
1046 *cups = TRUE;
1048 else if (!strncmpW( port, LPR_Port, ARRAY_SIZE( LPR_Port ) -1 ))
1049 name = port + ARRAY_SIZE( LPR_Port ) - 1;
1050 if (name)
1052 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1053 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1054 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1056 HeapFree( GetProcessHeap(), 0, port );
1057 end:
1058 RegCloseKey( key );
1059 return ret;
1063 static void set_ppd_overrides( HANDLE printer )
1065 WCHAR *wstr = NULL;
1066 int size = 0;
1067 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1068 OSStatus status;
1069 PMPrintSession session = NULL;
1070 PMPageFormat format = NULL;
1071 PMPaper paper;
1072 CFStringRef paper_name;
1073 CFRange range;
1075 status = PMCreateSession( &session );
1076 if (status) goto end;
1078 status = PMCreatePageFormat( &format );
1079 if (status) goto end;
1081 status = PMSessionDefaultPageFormat( session, format );
1082 if (status) goto end;
1084 status = PMGetPageFormatPaper( format, &paper );
1085 if (status) goto end;
1087 status = PMPaperGetPPDPaperName( paper, &paper_name );
1088 if (status) goto end;
1090 range.location = 0;
1091 range.length = CFStringGetLength( paper_name );
1092 size = (range.length + 1) * sizeof(WCHAR);
1094 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1095 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1096 wstr[range.length] = 0;
1098 end:
1099 if (format) PMRelease( format );
1100 if (session) PMRelease( session );
1101 #endif
1103 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1104 HeapFree( GetProcessHeap(), 0, wstr );
1107 static BOOL update_driver( HANDLE printer )
1109 BOOL ret, is_cups;
1110 const WCHAR *name = get_opened_printer_name( printer );
1111 WCHAR *ppd_dir, *ppd;
1112 char *queue_name;
1114 if (!name) return FALSE;
1115 queue_name = get_queue_name( printer, &is_cups );
1116 if (!queue_name) return FALSE;
1118 if (!(ppd_dir = get_ppd_dir()))
1120 HeapFree( GetProcessHeap(), 0, queue_name );
1121 return FALSE;
1123 ppd = get_ppd_filename( ppd_dir, name );
1125 #ifdef SONAME_LIBCUPS
1126 if (is_cups)
1127 ret = get_cups_ppd( queue_name, ppd );
1128 else
1129 #endif
1130 ret = get_fallback_ppd( queue_name, ppd );
1132 if (ret)
1134 TRACE( "updating driver %s\n", debugstr_w( name ) );
1135 ret = add_printer_driver( name, ppd );
1136 unlink_ppd( ppd );
1138 HeapFree( GetProcessHeap(), 0, ppd_dir );
1139 HeapFree( GetProcessHeap(), 0, ppd );
1140 HeapFree( GetProcessHeap(), 0, queue_name );
1142 set_ppd_overrides( printer );
1144 /* call into the driver to update the devmode */
1145 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1147 return ret;
1150 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1152 PRINTER_INFO_2A pinfo2a;
1153 const char *r;
1154 size_t name_len;
1155 char *e,*s,*name,*prettyname,*devname;
1156 BOOL ret = FALSE, set_default = FALSE;
1157 char *port = NULL, *env_default;
1158 HKEY hkeyPrinter, hkeyPrinters = NULL;
1159 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1160 HANDLE added_printer;
1162 while (isspace(*pent)) pent++;
1163 r = strchr(pent,':');
1164 if (r)
1165 name_len = r - pent;
1166 else
1167 name_len = strlen(pent);
1168 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1169 memcpy(name, pent, name_len);
1170 name[name_len] = '\0';
1171 if (r)
1172 pent = r;
1173 else
1174 pent = "";
1176 TRACE("name=%s entry=%s\n",name, pent);
1178 if(ispunct(*name)) { /* a tc entry, not a real printer */
1179 TRACE("skipping tc entry\n");
1180 goto end;
1183 if(strstr(pent,":server")) { /* server only version so skip */
1184 TRACE("skipping server entry\n");
1185 goto end;
1188 /* Determine whether this is a postscript printer. */
1190 ret = TRUE;
1191 env_default = getenv("PRINTER");
1192 prettyname = name;
1193 /* Get longest name, usually the one at the right for later display. */
1194 while((s=strchr(prettyname,'|'))) {
1195 *s = '\0';
1196 e = s;
1197 while(isspace(*--e)) *e = '\0';
1198 TRACE("\t%s\n", debugstr_a(prettyname));
1199 if(env_default && !_strnicmp(prettyname, env_default, -1)) set_default = TRUE;
1200 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1203 e = prettyname + strlen(prettyname);
1204 while(isspace(*--e)) *e = '\0';
1205 TRACE("\t%s\n", debugstr_a(prettyname));
1206 if(env_default && !_strnicmp(prettyname, env_default, -1)) set_default = TRUE;
1208 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1209 * if it is too long, we use it as comment below. */
1210 devname = prettyname;
1211 if (strlen(devname)>=CCHDEVICENAME-1)
1212 devname = name;
1213 if (strlen(devname)>=CCHDEVICENAME-1) {
1214 ret = FALSE;
1215 goto end;
1218 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1219 sprintf(port,"LPR:%s",name);
1221 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1222 ERROR_SUCCESS) {
1223 ERR("Can't create Printers key\n");
1224 ret = FALSE;
1225 goto end;
1228 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, ARRAY_SIZE(devnameW));
1230 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1231 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1232 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1233 and continue */
1234 TRACE("Printer already exists\n");
1235 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1236 /* flag that the PPD file should be checked for an update */
1237 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1238 RegCloseKey(hkeyPrinter);
1239 } else {
1240 static CHAR data_type[] = "RAW",
1241 print_proc[] = "WinPrint",
1242 comment[] = "WINEPS Printer using LPR",
1243 params[] = "<parameters?>",
1244 share_name[] = "<share name?>",
1245 sep_file[] = "<sep file?>";
1246 BOOL added_driver = FALSE;
1248 if (!ppd_dir && !(ppd_dir = get_ppd_dir())) goto end;
1249 ppd = get_ppd_filename( ppd_dir, devnameW );
1250 if (get_fallback_ppd( devname, ppd ))
1252 added_driver = add_printer_driver( devnameW, ppd );
1253 unlink_ppd( ppd );
1255 HeapFree( GetProcessHeap(), 0, ppd );
1256 if (!added_driver) goto end;
1258 memset(&pinfo2a,0,sizeof(pinfo2a));
1259 pinfo2a.pPrinterName = devname;
1260 pinfo2a.pDatatype = data_type;
1261 pinfo2a.pPrintProcessor = print_proc;
1262 pinfo2a.pDriverName = devname;
1263 pinfo2a.pComment = comment;
1264 pinfo2a.pLocation = prettyname;
1265 pinfo2a.pPortName = port;
1266 pinfo2a.pParameters = params;
1267 pinfo2a.pShareName = share_name;
1268 pinfo2a.pSepFile = sep_file;
1270 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1271 if (added_printer) ClosePrinter( added_printer );
1272 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1273 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1276 if (isfirst || set_default)
1277 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1279 end:
1280 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1281 if (ppd_dir)
1283 RemoveDirectoryW( ppd_dir );
1284 HeapFree( GetProcessHeap(), 0, ppd_dir );
1286 HeapFree(GetProcessHeap(), 0, port);
1287 HeapFree(GetProcessHeap(), 0, name);
1288 return ret;
1291 static BOOL
1292 PRINTCAP_LoadPrinters(void) {
1293 BOOL hadprinter = FALSE;
1294 char buf[200];
1295 FILE *f;
1296 char *pent = NULL;
1297 BOOL had_bash = FALSE;
1299 f = fopen("/etc/printcap","r");
1300 if (!f)
1301 return FALSE;
1303 while(fgets(buf,sizeof(buf),f)) {
1304 char *start, *end;
1306 end=strchr(buf,'\n');
1307 if (end) *end='\0';
1309 start = buf;
1310 while(isspace(*start)) start++;
1311 if(*start == '#' || *start == '\0')
1312 continue;
1314 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1315 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1316 HeapFree(GetProcessHeap(),0,pent);
1317 pent = NULL;
1320 if (end && *--end == '\\') {
1321 *end = '\0';
1322 had_bash = TRUE;
1323 } else
1324 had_bash = FALSE;
1326 if (pent) {
1327 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1328 strcat(pent,start);
1329 } else {
1330 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1331 strcpy(pent,start);
1335 if(pent) {
1336 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1337 HeapFree(GetProcessHeap(),0,pent);
1339 fclose(f);
1340 return hadprinter;
1343 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1345 if (value)
1346 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1347 (lstrlenW(value) + 1) * sizeof(WCHAR));
1348 else
1349 return ERROR_FILE_NOT_FOUND;
1352 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1354 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1355 DWORD ret = ERROR_FILE_NOT_FOUND;
1357 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1358 and we support these drivers. NT writes DEVMODEW so somehow
1359 we'll need to distinguish between these when we support NT
1360 drivers */
1362 if (dmA)
1364 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1365 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1366 HeapFree( GetProcessHeap(), 0, dmA );
1369 return ret;
1372 /******************************************************************
1373 * get_servername_from_name (internal)
1375 * for an external server, a copy of the serverpart from the full name is returned
1378 static LPWSTR get_servername_from_name(LPCWSTR name)
1380 LPWSTR server;
1381 LPWSTR ptr;
1382 WCHAR buffer[MAX_PATH];
1383 DWORD len;
1385 if (name == NULL) return NULL;
1386 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1388 server = strdupW(&name[2]); /* skip over both backslash */
1389 if (server == NULL) return NULL;
1391 /* strip '\' and the printername */
1392 ptr = strchrW(server, '\\');
1393 if (ptr) ptr[0] = '\0';
1395 TRACE("found %s\n", debugstr_w(server));
1397 len = ARRAY_SIZE(buffer);
1398 if (GetComputerNameW(buffer, &len)) {
1399 if (lstrcmpW(buffer, server) == 0) {
1400 /* The requested Servername is our computername */
1401 HeapFree(GetProcessHeap(), 0, server);
1402 return NULL;
1405 return server;
1408 /******************************************************************
1409 * get_basename_from_name (internal)
1411 * skip over the serverpart from the full name
1414 static LPCWSTR get_basename_from_name(LPCWSTR name)
1416 if (name == NULL) return NULL;
1417 if ((name[0] == '\\') && (name[1] == '\\')) {
1418 /* skip over the servername and search for the following '\' */
1419 name = strchrW(&name[2], '\\');
1420 if ((name) && (name[1])) {
1421 /* found a separator ('\') followed by a name:
1422 skip over the separator and return the rest */
1423 name++;
1425 else
1427 /* no basename present (we found only a servername) */
1428 return NULL;
1431 return name;
1434 static void free_printer_entry( opened_printer_t *printer )
1436 /* the queue is shared, so don't free that here */
1437 HeapFree( GetProcessHeap(), 0, printer->printername );
1438 HeapFree( GetProcessHeap(), 0, printer->name );
1439 HeapFree( GetProcessHeap(), 0, printer->devmode );
1440 HeapFree( GetProcessHeap(), 0, printer );
1443 /******************************************************************
1444 * get_opened_printer_entry
1445 * Get the first place empty in the opened printer table
1447 * ToDo:
1448 * - pDefault is ignored
1450 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1452 UINT_PTR handle = nb_printer_handles, i;
1453 jobqueue_t *queue = NULL;
1454 opened_printer_t *printer = NULL;
1455 LPWSTR servername;
1456 LPCWSTR printername;
1458 if ((backend == NULL) && !load_backend()) return NULL;
1460 servername = get_servername_from_name(name);
1461 if (servername) {
1462 FIXME("server %s not supported\n", debugstr_w(servername));
1463 HeapFree(GetProcessHeap(), 0, servername);
1464 SetLastError(ERROR_INVALID_PRINTER_NAME);
1465 return NULL;
1468 printername = get_basename_from_name(name);
1469 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1471 /* an empty printername is invalid */
1472 if (printername && (!printername[0])) {
1473 SetLastError(ERROR_INVALID_PARAMETER);
1474 return NULL;
1477 EnterCriticalSection(&printer_handles_cs);
1479 for (i = 0; i < nb_printer_handles; i++)
1481 if (!printer_handles[i])
1483 if(handle == nb_printer_handles)
1484 handle = i;
1486 else
1488 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1489 queue = printer_handles[i]->queue;
1493 if (handle >= nb_printer_handles)
1495 opened_printer_t **new_array;
1496 if (printer_handles)
1497 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1498 (nb_printer_handles + 16) * sizeof(*new_array) );
1499 else
1500 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1501 (nb_printer_handles + 16) * sizeof(*new_array) );
1503 if (!new_array)
1505 handle = 0;
1506 goto end;
1508 printer_handles = new_array;
1509 nb_printer_handles += 16;
1512 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1514 handle = 0;
1515 goto end;
1518 /* get a printer handle from the backend */
1519 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1520 handle = 0;
1521 goto end;
1524 /* clone the base name. This is NULL for the printserver */
1525 printer->printername = strdupW(printername);
1527 /* clone the full name */
1528 printer->name = strdupW(name);
1529 if (name && (!printer->name)) {
1530 handle = 0;
1531 goto end;
1534 if (pDefault && pDefault->pDevMode)
1535 printer->devmode = dup_devmode( pDefault->pDevMode );
1537 if(queue)
1538 printer->queue = queue;
1539 else
1541 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1542 if (!printer->queue) {
1543 handle = 0;
1544 goto end;
1546 list_init(&printer->queue->jobs);
1547 printer->queue->ref = 0;
1549 InterlockedIncrement(&printer->queue->ref);
1551 printer_handles[handle] = printer;
1552 handle++;
1553 end:
1554 LeaveCriticalSection(&printer_handles_cs);
1555 if (!handle && printer) {
1556 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1557 free_printer_entry( printer );
1560 return (HANDLE)handle;
1563 static void old_printer_check( BOOL delete_phase )
1565 PRINTER_INFO_5W* pi;
1566 DWORD needed, type, num, delete, i, size;
1567 const DWORD one = 1;
1568 HKEY key;
1569 HANDLE hprn;
1571 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1572 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1574 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1575 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1576 for (i = 0; i < num; i++)
1578 if (!pi[i].pPortName) continue;
1580 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1581 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1582 continue;
1584 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1586 if (!delete_phase)
1588 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1589 RegCloseKey( key );
1591 else
1593 delete = 0;
1594 size = sizeof( delete );
1595 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1596 RegCloseKey( key );
1597 if (delete)
1599 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1600 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1602 DeletePrinter( hprn );
1603 ClosePrinter( hprn );
1605 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1609 HeapFree(GetProcessHeap(), 0, pi);
1612 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1613 'M','U','T','E','X','_','_','\0'};
1614 static HANDLE init_mutex;
1616 void WINSPOOL_LoadSystemPrinters(void)
1618 HKEY hkey, hkeyPrinters;
1619 DWORD needed, num, i;
1620 WCHAR PrinterName[256];
1621 BOOL done = FALSE;
1623 #ifdef SONAME_LIBCUPS
1624 load_cups();
1625 #endif
1627 /* FIXME: The init code should be moved to spoolsv.exe */
1628 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1629 if (!init_mutex)
1631 ERR( "Failed to create mutex\n" );
1632 return;
1634 if (GetLastError() == ERROR_ALREADY_EXISTS)
1636 WaitForSingleObject( init_mutex, INFINITE );
1637 ReleaseMutex( init_mutex );
1638 TRACE( "Init already done\n" );
1639 return;
1642 /* This ensures that all printer entries have a valid Name value. If causes
1643 problems later if they don't. If one is found to be missed we create one
1644 and set it equal to the name of the key */
1645 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1646 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1647 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1648 for(i = 0; i < num; i++) {
1649 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, ARRAY_SIZE(PrinterName)) == ERROR_SUCCESS) {
1650 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1651 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1652 set_reg_szW(hkey, NameW, PrinterName);
1654 RegCloseKey(hkey);
1659 RegCloseKey(hkeyPrinters);
1662 old_printer_check( FALSE );
1664 #ifdef SONAME_LIBCUPS
1665 done = CUPS_LoadPrinters();
1666 #endif
1668 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1669 PRINTCAP_LoadPrinters();
1671 old_printer_check( TRUE );
1673 ReleaseMutex( init_mutex );
1674 return;
1677 /******************************************************************
1678 * get_job
1680 * Get the pointer to the specified job.
1681 * Should hold the printer_handles_cs before calling.
1683 static job_t *get_job(HANDLE hprn, DWORD JobId)
1685 opened_printer_t *printer = get_opened_printer(hprn);
1686 job_t *job;
1688 if(!printer) return NULL;
1689 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1691 if(job->job_id == JobId)
1692 return job;
1694 return NULL;
1697 /***********************************************************
1698 * DEVMODEcpyAtoW
1700 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1702 BOOL Formname;
1703 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1704 DWORD size;
1706 Formname = (dmA->dmSize > off_formname);
1707 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1708 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1709 dmW->dmDeviceName, CCHDEVICENAME);
1710 if(!Formname) {
1711 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1712 dmA->dmSize - CCHDEVICENAME);
1713 } else {
1714 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1715 off_formname - CCHDEVICENAME);
1716 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1717 dmW->dmFormName, CCHFORMNAME);
1718 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1719 (off_formname + CCHFORMNAME));
1721 dmW->dmSize = size;
1722 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1723 dmA->dmDriverExtra);
1724 return dmW;
1727 /******************************************************************
1728 * convert_printerinfo_W_to_A [internal]
1731 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1732 DWORD level, DWORD outlen, DWORD numentries)
1734 DWORD id = 0;
1735 LPSTR ptr;
1736 INT len;
1738 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1740 len = pi_sizeof[level] * numentries;
1741 ptr = (LPSTR) out + len;
1742 outlen -= len;
1744 /* copy the numbers of all PRINTER_INFO_* first */
1745 memcpy(out, pPrintersW, len);
1747 while (id < numentries) {
1748 switch (level) {
1749 case 1:
1751 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1752 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1754 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1755 if (piW->pDescription) {
1756 piA->pDescription = ptr;
1757 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1758 ptr, outlen, NULL, NULL);
1759 ptr += len;
1760 outlen -= len;
1762 if (piW->pName) {
1763 piA->pName = ptr;
1764 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1765 ptr, outlen, NULL, NULL);
1766 ptr += len;
1767 outlen -= len;
1769 if (piW->pComment) {
1770 piA->pComment = ptr;
1771 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1772 ptr, outlen, NULL, NULL);
1773 ptr += len;
1774 outlen -= len;
1776 break;
1779 case 2:
1781 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1782 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1783 LPDEVMODEA dmA;
1785 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1786 if (piW->pServerName) {
1787 piA->pServerName = ptr;
1788 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1789 ptr, outlen, NULL, NULL);
1790 ptr += len;
1791 outlen -= len;
1793 if (piW->pPrinterName) {
1794 piA->pPrinterName = ptr;
1795 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1796 ptr, outlen, NULL, NULL);
1797 ptr += len;
1798 outlen -= len;
1800 if (piW->pShareName) {
1801 piA->pShareName = ptr;
1802 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1803 ptr, outlen, NULL, NULL);
1804 ptr += len;
1805 outlen -= len;
1807 if (piW->pPortName) {
1808 piA->pPortName = ptr;
1809 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1810 ptr, outlen, NULL, NULL);
1811 ptr += len;
1812 outlen -= len;
1814 if (piW->pDriverName) {
1815 piA->pDriverName = ptr;
1816 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1817 ptr, outlen, NULL, NULL);
1818 ptr += len;
1819 outlen -= len;
1821 if (piW->pComment) {
1822 piA->pComment = ptr;
1823 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1824 ptr, outlen, NULL, NULL);
1825 ptr += len;
1826 outlen -= len;
1828 if (piW->pLocation) {
1829 piA->pLocation = ptr;
1830 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1831 ptr, outlen, NULL, NULL);
1832 ptr += len;
1833 outlen -= len;
1836 dmA = DEVMODEdupWtoA(piW->pDevMode);
1837 if (dmA) {
1838 /* align DEVMODEA to a DWORD boundary */
1839 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1840 ptr += len;
1841 outlen -= len;
1843 piA->pDevMode = (LPDEVMODEA) ptr;
1844 len = dmA->dmSize + dmA->dmDriverExtra;
1845 memcpy(ptr, dmA, len);
1846 HeapFree(GetProcessHeap(), 0, dmA);
1848 ptr += len;
1849 outlen -= len;
1852 if (piW->pSepFile) {
1853 piA->pSepFile = ptr;
1854 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1855 ptr, outlen, NULL, NULL);
1856 ptr += len;
1857 outlen -= len;
1859 if (piW->pPrintProcessor) {
1860 piA->pPrintProcessor = ptr;
1861 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1862 ptr, outlen, NULL, NULL);
1863 ptr += len;
1864 outlen -= len;
1866 if (piW->pDatatype) {
1867 piA->pDatatype = ptr;
1868 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1869 ptr, outlen, NULL, NULL);
1870 ptr += len;
1871 outlen -= len;
1873 if (piW->pParameters) {
1874 piA->pParameters = ptr;
1875 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1876 ptr, outlen, NULL, NULL);
1877 ptr += len;
1878 outlen -= len;
1880 if (piW->pSecurityDescriptor) {
1881 piA->pSecurityDescriptor = NULL;
1882 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1884 break;
1887 case 4:
1889 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1890 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1892 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1894 if (piW->pPrinterName) {
1895 piA->pPrinterName = ptr;
1896 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1897 ptr, outlen, NULL, NULL);
1898 ptr += len;
1899 outlen -= len;
1901 if (piW->pServerName) {
1902 piA->pServerName = ptr;
1903 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1904 ptr, outlen, NULL, NULL);
1905 ptr += len;
1906 outlen -= len;
1908 break;
1911 case 5:
1913 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1914 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1916 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1918 if (piW->pPrinterName) {
1919 piA->pPrinterName = ptr;
1920 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1921 ptr, outlen, NULL, NULL);
1922 ptr += len;
1923 outlen -= len;
1925 if (piW->pPortName) {
1926 piA->pPortName = ptr;
1927 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1928 ptr, outlen, NULL, NULL);
1929 ptr += len;
1930 outlen -= len;
1932 break;
1935 case 6: /* 6A and 6W are the same structure */
1936 break;
1938 case 7:
1940 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1941 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1943 TRACE("(%u) #%u\n", level, id);
1944 if (piW->pszObjectGUID) {
1945 piA->pszObjectGUID = ptr;
1946 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1947 ptr, outlen, NULL, NULL);
1948 ptr += len;
1949 outlen -= len;
1951 break;
1954 case 8:
1955 case 9:
1957 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1958 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1959 LPDEVMODEA dmA;
1961 TRACE("(%u) #%u\n", level, id);
1962 dmA = DEVMODEdupWtoA(piW->pDevMode);
1963 if (dmA) {
1964 /* align DEVMODEA to a DWORD boundary */
1965 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1966 ptr += len;
1967 outlen -= len;
1969 piA->pDevMode = (LPDEVMODEA) ptr;
1970 len = dmA->dmSize + dmA->dmDriverExtra;
1971 memcpy(ptr, dmA, len);
1972 HeapFree(GetProcessHeap(), 0, dmA);
1974 ptr += len;
1975 outlen -= len;
1978 break;
1981 default:
1982 FIXME("for level %u\n", level);
1984 pPrintersW += pi_sizeof[level];
1985 out += pi_sizeof[level];
1986 id++;
1990 /******************************************************************
1991 * convert_driverinfo_W_to_A [internal]
1994 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1995 DWORD level, DWORD outlen, DWORD numentries)
1997 DWORD id = 0;
1998 LPSTR ptr;
1999 INT len;
2001 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
2003 len = di_sizeof[level] * numentries;
2004 ptr = (LPSTR) out + len;
2005 outlen -= len;
2007 /* copy the numbers of all PRINTER_INFO_* first */
2008 memcpy(out, pDriversW, len);
2010 #define COPY_STRING(fld) \
2011 { if (diW->fld){ \
2012 diA->fld = ptr; \
2013 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
2014 ptr += len; outlen -= len;\
2016 #define COPY_MULTIZ_STRING(fld) \
2017 { LPWSTR p = diW->fld; if (p){ \
2018 diA->fld = ptr; \
2019 do {\
2020 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2021 ptr += len; outlen -= len; p += len;\
2023 while(len > 1 && outlen > 0); \
2026 while (id < numentries)
2028 switch (level)
2030 case 1:
2032 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
2033 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
2035 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2037 COPY_STRING(pName);
2038 break;
2040 case 2:
2042 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2043 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2045 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2047 COPY_STRING(pName);
2048 COPY_STRING(pEnvironment);
2049 COPY_STRING(pDriverPath);
2050 COPY_STRING(pDataFile);
2051 COPY_STRING(pConfigFile);
2052 break;
2054 case 3:
2056 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2057 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2059 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2061 COPY_STRING(pName);
2062 COPY_STRING(pEnvironment);
2063 COPY_STRING(pDriverPath);
2064 COPY_STRING(pDataFile);
2065 COPY_STRING(pConfigFile);
2066 COPY_STRING(pHelpFile);
2067 COPY_MULTIZ_STRING(pDependentFiles);
2068 COPY_STRING(pMonitorName);
2069 COPY_STRING(pDefaultDataType);
2070 break;
2072 case 4:
2074 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2075 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2077 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2079 COPY_STRING(pName);
2080 COPY_STRING(pEnvironment);
2081 COPY_STRING(pDriverPath);
2082 COPY_STRING(pDataFile);
2083 COPY_STRING(pConfigFile);
2084 COPY_STRING(pHelpFile);
2085 COPY_MULTIZ_STRING(pDependentFiles);
2086 COPY_STRING(pMonitorName);
2087 COPY_STRING(pDefaultDataType);
2088 COPY_MULTIZ_STRING(pszzPreviousNames);
2089 break;
2091 case 5:
2093 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2094 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2096 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2098 COPY_STRING(pName);
2099 COPY_STRING(pEnvironment);
2100 COPY_STRING(pDriverPath);
2101 COPY_STRING(pDataFile);
2102 COPY_STRING(pConfigFile);
2103 break;
2105 case 6:
2107 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2108 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2110 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2112 COPY_STRING(pName);
2113 COPY_STRING(pEnvironment);
2114 COPY_STRING(pDriverPath);
2115 COPY_STRING(pDataFile);
2116 COPY_STRING(pConfigFile);
2117 COPY_STRING(pHelpFile);
2118 COPY_MULTIZ_STRING(pDependentFiles);
2119 COPY_STRING(pMonitorName);
2120 COPY_STRING(pDefaultDataType);
2121 COPY_MULTIZ_STRING(pszzPreviousNames);
2122 COPY_STRING(pszMfgName);
2123 COPY_STRING(pszOEMUrl);
2124 COPY_STRING(pszHardwareID);
2125 COPY_STRING(pszProvider);
2126 break;
2128 case 8:
2130 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2131 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2133 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2135 COPY_STRING(pName);
2136 COPY_STRING(pEnvironment);
2137 COPY_STRING(pDriverPath);
2138 COPY_STRING(pDataFile);
2139 COPY_STRING(pConfigFile);
2140 COPY_STRING(pHelpFile);
2141 COPY_MULTIZ_STRING(pDependentFiles);
2142 COPY_STRING(pMonitorName);
2143 COPY_STRING(pDefaultDataType);
2144 COPY_MULTIZ_STRING(pszzPreviousNames);
2145 COPY_STRING(pszMfgName);
2146 COPY_STRING(pszOEMUrl);
2147 COPY_STRING(pszHardwareID);
2148 COPY_STRING(pszProvider);
2149 COPY_STRING(pszPrintProcessor);
2150 COPY_STRING(pszVendorSetup);
2151 COPY_MULTIZ_STRING(pszzColorProfiles);
2152 COPY_STRING(pszInfPath);
2153 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2154 break;
2158 default:
2159 FIXME("for level %u\n", level);
2162 pDriversW += di_sizeof[level];
2163 out += di_sizeof[level];
2164 id++;
2167 #undef COPY_STRING
2168 #undef COPY_MULTIZ_STRING
2172 /***********************************************************
2173 * printer_info_AtoW
2175 static void *printer_info_AtoW( const void *data, DWORD level )
2177 void *ret;
2178 UNICODE_STRING usBuffer;
2180 if (!data) return NULL;
2182 if (level < 1 || level > 9) return NULL;
2184 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2185 if (!ret) return NULL;
2187 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2189 switch (level)
2191 case 2:
2193 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2194 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2196 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2197 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2198 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2199 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2200 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2201 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2202 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2203 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2204 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2205 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2206 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2207 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2208 break;
2211 case 8:
2212 case 9:
2214 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2215 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2217 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2218 break;
2221 default:
2222 FIXME( "Unhandled level %d\n", level );
2223 HeapFree( GetProcessHeap(), 0, ret );
2224 return NULL;
2227 return ret;
2230 /***********************************************************
2231 * free_printer_info
2233 static void free_printer_info( void *data, DWORD level )
2235 if (!data) return;
2237 switch (level)
2239 case 2:
2241 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2243 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2244 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2245 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2246 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2247 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2248 HeapFree( GetProcessHeap(), 0, piW->pComment );
2249 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2250 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2251 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2252 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2253 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2254 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2255 break;
2258 case 8:
2259 case 9:
2261 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2263 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2264 break;
2267 default:
2268 FIXME( "Unhandled level %d\n", level );
2271 HeapFree( GetProcessHeap(), 0, data );
2272 return;
2275 /******************************************************************
2276 * DeviceCapabilities [WINSPOOL.@]
2277 * DeviceCapabilitiesA [WINSPOOL.@]
2280 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2281 LPSTR pOutput, LPDEVMODEA lpdm)
2283 INT ret;
2285 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice), debugstr_a(pPort), cap, pOutput, lpdm);
2287 if (!GDI_CallDeviceCapabilities16)
2289 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2290 (LPCSTR)104 );
2291 if (!GDI_CallDeviceCapabilities16) return -1;
2293 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2295 /* If DC_PAPERSIZE map POINT16s to POINTs */
2296 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2297 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2298 POINT *pt = (POINT *)pOutput;
2299 INT i;
2300 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2301 for(i = 0; i < ret; i++, pt++)
2303 pt->x = tmp[i].x;
2304 pt->y = tmp[i].y;
2306 HeapFree( GetProcessHeap(), 0, tmp );
2308 return ret;
2312 /*****************************************************************************
2313 * DeviceCapabilitiesW [WINSPOOL.@]
2315 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2318 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2319 WORD fwCapability, LPWSTR pOutput,
2320 const DEVMODEW *pDevMode)
2322 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2323 LPSTR pDeviceA = strdupWtoA(pDevice);
2324 LPSTR pPortA = strdupWtoA(pPort);
2325 INT ret;
2327 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability, pOutput, pDevMode);
2329 if(pOutput && (fwCapability == DC_BINNAMES ||
2330 fwCapability == DC_FILEDEPENDENCIES ||
2331 fwCapability == DC_PAPERNAMES)) {
2332 /* These need A -> W translation */
2333 INT size = 0, i;
2334 LPSTR pOutputA;
2335 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2336 dmA);
2337 if(ret == -1)
2338 return ret;
2339 switch(fwCapability) {
2340 case DC_BINNAMES:
2341 size = 24;
2342 break;
2343 case DC_PAPERNAMES:
2344 case DC_FILEDEPENDENCIES:
2345 size = 64;
2346 break;
2348 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2349 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2350 dmA);
2351 for(i = 0; i < ret; i++)
2352 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2353 pOutput + (i * size), size);
2354 HeapFree(GetProcessHeap(), 0, pOutputA);
2355 } else {
2356 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2357 (LPSTR)pOutput, dmA);
2359 HeapFree(GetProcessHeap(),0,pPortA);
2360 HeapFree(GetProcessHeap(),0,pDeviceA);
2361 HeapFree(GetProcessHeap(),0,dmA);
2362 return ret;
2365 /******************************************************************
2366 * DocumentPropertiesA [WINSPOOL.@]
2368 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2370 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2371 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2372 LPDEVMODEA pDevModeInput,DWORD fMode )
2374 LPSTR lpName = pDeviceName, dupname = NULL;
2375 static CHAR port[] = "LPT1:";
2376 LONG ret;
2378 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2379 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2382 if(!pDeviceName || !*pDeviceName) {
2383 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2384 if(!lpNameW) {
2385 ERR("no name from hPrinter?\n");
2386 SetLastError(ERROR_INVALID_HANDLE);
2387 return -1;
2389 lpName = dupname = strdupWtoA(lpNameW);
2392 if (!GDI_CallExtDeviceMode16)
2394 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2395 (LPCSTR)102 );
2396 if (!GDI_CallExtDeviceMode16) {
2397 ERR("No CallExtDeviceMode16?\n");
2398 ret = -1;
2399 goto end;
2402 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2403 pDevModeInput, NULL, fMode);
2405 end:
2406 HeapFree(GetProcessHeap(), 0, dupname);
2407 return ret;
2411 /*****************************************************************************
2412 * DocumentPropertiesW (WINSPOOL.@)
2414 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2416 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2417 LPWSTR pDeviceName,
2418 LPDEVMODEW pDevModeOutput,
2419 LPDEVMODEW pDevModeInput, DWORD fMode)
2422 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2423 LPDEVMODEA pDevModeInputA;
2424 LPDEVMODEA pDevModeOutputA = NULL;
2425 LONG ret;
2427 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2428 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2429 fMode);
2430 if(pDevModeOutput) {
2431 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2432 if(ret < 0) return ret;
2433 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2435 pDevModeInputA = (fMode & DM_IN_BUFFER) ? DEVMODEdupWtoA(pDevModeInput) : NULL;
2436 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2437 pDevModeInputA, fMode);
2438 if(pDevModeOutput) {
2439 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2440 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2442 if(fMode == 0 && ret > 0)
2443 ret += (CCHDEVICENAME + CCHFORMNAME);
2444 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2445 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2446 return ret;
2449 /*****************************************************************************
2450 * IsValidDevmodeA [WINSPOOL.@]
2452 * Validate a DEVMODE structure and fix errors if possible.
2455 BOOL WINAPI IsValidDevmodeA(PDEVMODEA pDevMode, SIZE_T size)
2457 FIXME("(%p,%ld): stub\n", pDevMode, size);
2459 if(!pDevMode)
2460 return FALSE;
2462 return TRUE;
2465 /*****************************************************************************
2466 * IsValidDevmodeW [WINSPOOL.@]
2468 * Validate a DEVMODE structure and fix errors if possible.
2471 BOOL WINAPI IsValidDevmodeW(PDEVMODEW dm, SIZE_T size)
2473 static const struct
2475 DWORD flag;
2476 SIZE_T size;
2477 } map[] =
2479 #define F_SIZE(field) FIELD_OFFSET(DEVMODEW, field) + sizeof(dm->field)
2480 { DM_ORIENTATION, F_SIZE(u1.s1.dmOrientation) },
2481 { DM_PAPERSIZE, F_SIZE(u1.s1.dmPaperSize) },
2482 { DM_PAPERLENGTH, F_SIZE(u1.s1.dmPaperLength) },
2483 { DM_PAPERWIDTH, F_SIZE(u1.s1.dmPaperWidth) },
2484 { DM_SCALE, F_SIZE(u1.s1.dmScale) },
2485 { DM_COPIES, F_SIZE(u1.s1.dmCopies) },
2486 { DM_DEFAULTSOURCE, F_SIZE(u1.s1.dmDefaultSource) },
2487 { DM_PRINTQUALITY, F_SIZE(u1.s1.dmPrintQuality) },
2488 { DM_POSITION, F_SIZE(u1.s2.dmPosition) },
2489 { DM_DISPLAYORIENTATION, F_SIZE(u1.s2.dmDisplayOrientation) },
2490 { DM_DISPLAYFIXEDOUTPUT, F_SIZE(u1.s2.dmDisplayFixedOutput) },
2491 { DM_COLOR, F_SIZE(dmColor) },
2492 { DM_DUPLEX, F_SIZE(dmDuplex) },
2493 { DM_YRESOLUTION, F_SIZE(dmYResolution) },
2494 { DM_TTOPTION, F_SIZE(dmTTOption) },
2495 { DM_COLLATE, F_SIZE(dmCollate) },
2496 { DM_FORMNAME, F_SIZE(dmFormName) },
2497 { DM_LOGPIXELS, F_SIZE(dmLogPixels) },
2498 { DM_BITSPERPEL, F_SIZE(dmBitsPerPel) },
2499 { DM_PELSWIDTH, F_SIZE(dmPelsWidth) },
2500 { DM_PELSHEIGHT, F_SIZE(dmPelsHeight) },
2501 { DM_DISPLAYFLAGS, F_SIZE(u2.dmDisplayFlags) },
2502 { DM_NUP, F_SIZE(u2.dmNup) },
2503 { DM_DISPLAYFREQUENCY, F_SIZE(dmDisplayFrequency) },
2504 { DM_ICMMETHOD, F_SIZE(dmICMMethod) },
2505 { DM_ICMINTENT, F_SIZE(dmICMIntent) },
2506 { DM_MEDIATYPE, F_SIZE(dmMediaType) },
2507 { DM_DITHERTYPE, F_SIZE(dmDitherType) },
2508 { DM_PANNINGWIDTH, F_SIZE(dmPanningWidth) },
2509 { DM_PANNINGHEIGHT, F_SIZE(dmPanningHeight) }
2510 #undef F_SIZE
2512 int i;
2514 if (!dm) return FALSE;
2515 if (size < FIELD_OFFSET(DEVMODEW, dmFields) + sizeof(dm->dmFields)) return FALSE;
2517 for (i = 0; i < ARRAY_SIZE(map); i++)
2518 if ((dm->dmFields & map[i].flag) && size < map[i].size)
2519 return FALSE;
2521 return TRUE;
2524 /******************************************************************
2525 * OpenPrinterA [WINSPOOL.@]
2527 * See OpenPrinterW.
2530 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2531 LPPRINTER_DEFAULTSA pDefault)
2533 UNICODE_STRING lpPrinterNameW;
2534 UNICODE_STRING usBuffer;
2535 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2536 PWSTR pwstrPrinterNameW;
2537 BOOL ret;
2539 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName), phPrinter, pDefault);
2541 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2543 if(pDefault) {
2544 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2545 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2546 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2547 pDefaultW = &DefaultW;
2549 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2550 if(pDefault) {
2551 RtlFreeUnicodeString(&usBuffer);
2552 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2554 RtlFreeUnicodeString(&lpPrinterNameW);
2555 return ret;
2558 /******************************************************************
2559 * OpenPrinterW [WINSPOOL.@]
2561 * Open a Printer / Printserver or a Printer-Object
2563 * PARAMS
2564 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2565 * phPrinter [O] The resulting Handle is stored here
2566 * pDefault [I] PTR to Default Printer Settings or NULL
2568 * RETURNS
2569 * Success: TRUE
2570 * Failure: FALSE
2572 * NOTES
2573 * lpPrinterName is one of:
2574 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2575 *| Printer: "PrinterName"
2576 *| Printer-Object: "PrinterName,Job xxx"
2577 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2578 *| XcvPort: "Servername,XcvPort PortName"
2580 * BUGS
2581 *| Printer-Object not supported
2582 *| pDefaults is ignored
2585 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2587 HKEY key;
2589 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2591 if(!phPrinter) {
2592 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2593 SetLastError(ERROR_INVALID_PARAMETER);
2594 return FALSE;
2597 /* Get the unique handle of the printer or Printserver */
2598 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2600 if (*phPrinter && WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key ) == ERROR_SUCCESS)
2602 DWORD deleting = 0, size = sizeof( deleting ), type;
2603 DWORD status;
2604 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2605 WaitForSingleObject( init_mutex, INFINITE );
2606 status = get_dword_from_reg( key, StatusW );
2607 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2608 ReleaseMutex( init_mutex );
2609 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2610 update_driver( *phPrinter );
2611 RegCloseKey( key );
2614 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2615 return (*phPrinter != 0);
2618 /******************************************************************
2619 * AddMonitorA [WINSPOOL.@]
2621 * See AddMonitorW.
2624 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2626 LPWSTR nameW = NULL;
2627 INT len;
2628 BOOL res;
2629 LPMONITOR_INFO_2A mi2a;
2630 MONITOR_INFO_2W mi2w;
2632 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2633 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2634 debugstr_a(mi2a ? mi2a->pName : NULL),
2635 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2636 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2638 if (Level != 2) {
2639 SetLastError(ERROR_INVALID_LEVEL);
2640 return FALSE;
2643 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2644 if (mi2a == NULL) {
2645 return FALSE;
2648 if (pName) {
2649 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2650 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2651 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2654 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2655 if (mi2a->pName) {
2656 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2657 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2658 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2660 if (mi2a->pEnvironment) {
2661 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2662 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2663 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2665 if (mi2a->pDLLName) {
2666 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2667 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2668 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2671 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2673 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2674 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2675 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2677 HeapFree(GetProcessHeap(), 0, nameW);
2678 return (res);
2681 /******************************************************************************
2682 * AddMonitorW [WINSPOOL.@]
2684 * Install a Printmonitor
2686 * PARAMS
2687 * pName [I] Servername or NULL (local Computer)
2688 * Level [I] Structure-Level (Must be 2)
2689 * pMonitors [I] PTR to MONITOR_INFO_2
2691 * RETURNS
2692 * Success: TRUE
2693 * Failure: FALSE
2695 * NOTES
2696 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2699 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2701 LPMONITOR_INFO_2W mi2w;
2703 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2704 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2705 debugstr_w(mi2w ? mi2w->pName : NULL),
2706 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2707 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2709 if ((backend == NULL) && !load_backend()) return FALSE;
2711 if (Level != 2) {
2712 SetLastError(ERROR_INVALID_LEVEL);
2713 return FALSE;
2716 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2717 if (mi2w == NULL) {
2718 return FALSE;
2721 return backend->fpAddMonitor(pName, Level, pMonitors);
2724 /******************************************************************
2725 * DeletePrinterDriverA [WINSPOOL.@]
2728 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2730 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2733 /******************************************************************
2734 * DeletePrinterDriverW [WINSPOOL.@]
2737 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2739 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2742 /******************************************************************
2743 * DeleteMonitorA [WINSPOOL.@]
2745 * See DeleteMonitorW.
2748 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2750 LPWSTR nameW = NULL;
2751 LPWSTR EnvironmentW = NULL;
2752 LPWSTR MonitorNameW = NULL;
2753 BOOL res;
2754 INT len;
2756 if (pName) {
2757 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2758 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2759 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2762 if (pEnvironment) {
2763 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2764 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2765 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2767 if (pMonitorName) {
2768 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2769 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2770 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2773 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2775 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2776 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2777 HeapFree(GetProcessHeap(), 0, nameW);
2778 return (res);
2781 /******************************************************************
2782 * DeleteMonitorW [WINSPOOL.@]
2784 * Delete a specific Printmonitor from a Printing-Environment
2786 * PARAMS
2787 * pName [I] Servername or NULL (local Computer)
2788 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2789 * pMonitorName [I] Name of the Monitor, that should be deleted
2791 * RETURNS
2792 * Success: TRUE
2793 * Failure: FALSE
2795 * NOTES
2796 * pEnvironment is ignored in Windows for the local Computer.
2799 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2802 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2803 debugstr_w(pMonitorName));
2805 if ((backend == NULL) && !load_backend()) return FALSE;
2807 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2811 /******************************************************************
2812 * DeletePortA [WINSPOOL.@]
2814 * See DeletePortW.
2817 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2819 LPWSTR nameW = NULL;
2820 LPWSTR portW = NULL;
2821 INT len;
2822 DWORD res;
2824 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2826 /* convert servername to unicode */
2827 if (pName) {
2828 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2829 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2830 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2833 /* convert portname to unicode */
2834 if (pPortName) {
2835 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2836 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2837 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2840 res = DeletePortW(nameW, hWnd, portW);
2841 HeapFree(GetProcessHeap(), 0, nameW);
2842 HeapFree(GetProcessHeap(), 0, portW);
2843 return res;
2846 /******************************************************************
2847 * DeletePortW [WINSPOOL.@]
2849 * Delete a specific Port
2851 * PARAMS
2852 * pName [I] Servername or NULL (local Computer)
2853 * hWnd [I] Handle to parent Window for the Dialog-Box
2854 * pPortName [I] Name of the Port, that should be deleted
2856 * RETURNS
2857 * Success: TRUE
2858 * Failure: FALSE
2861 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2863 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2865 if ((backend == NULL) && !load_backend()) return FALSE;
2867 if (!pPortName) {
2868 SetLastError(RPC_X_NULL_REF_POINTER);
2869 return FALSE;
2872 return backend->fpDeletePort(pName, hWnd, pPortName);
2875 /******************************************************************************
2876 * WritePrinter [WINSPOOL.@]
2878 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2880 opened_printer_t *printer;
2881 BOOL ret = FALSE;
2883 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2885 EnterCriticalSection(&printer_handles_cs);
2886 printer = get_opened_printer(hPrinter);
2887 if(!printer)
2889 SetLastError(ERROR_INVALID_HANDLE);
2890 goto end;
2893 if(!printer->doc)
2895 SetLastError(ERROR_SPL_NO_STARTDOC);
2896 goto end;
2899 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2900 end:
2901 LeaveCriticalSection(&printer_handles_cs);
2902 return ret;
2905 /*****************************************************************************
2906 * AddFormA [WINSPOOL.@]
2908 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2910 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2911 return TRUE;
2914 /*****************************************************************************
2915 * AddFormW [WINSPOOL.@]
2917 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2919 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2920 return TRUE;
2923 /*****************************************************************************
2924 * AddJobA [WINSPOOL.@]
2926 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2928 BOOL ret;
2929 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2930 DWORD needed;
2932 if(Level != 1) {
2933 SetLastError(ERROR_INVALID_LEVEL);
2934 return FALSE;
2937 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2939 if(ret) {
2940 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2941 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2942 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2943 if(*pcbNeeded > cbBuf) {
2944 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2945 ret = FALSE;
2946 } else {
2947 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2948 addjobA->JobId = addjobW->JobId;
2949 addjobA->Path = (char *)(addjobA + 1);
2950 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2953 return ret;
2956 /*****************************************************************************
2957 * AddJobW [WINSPOOL.@]
2959 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2961 opened_printer_t *printer;
2962 job_t *job;
2963 BOOL ret = FALSE;
2964 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2965 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2966 WCHAR path[MAX_PATH], filename[MAX_PATH];
2967 DWORD len;
2968 ADDJOB_INFO_1W *addjob;
2970 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2972 EnterCriticalSection(&printer_handles_cs);
2974 printer = get_opened_printer(hPrinter);
2976 if(!printer) {
2977 SetLastError(ERROR_INVALID_HANDLE);
2978 goto end;
2981 if(Level != 1) {
2982 SetLastError(ERROR_INVALID_LEVEL);
2983 goto end;
2986 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2987 if(!job)
2988 goto end;
2990 job->job_id = InterlockedIncrement(&next_job_id);
2992 len = GetSystemDirectoryW(path, ARRAY_SIZE(path));
2993 if(path[len - 1] != '\\')
2994 path[len++] = '\\';
2995 memcpy(path + len, spool_path, sizeof(spool_path));
2996 sprintfW(filename, fmtW, path, job->job_id);
2998 len = strlenW(filename);
2999 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
3000 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
3001 job->portname = NULL;
3002 job->document_title = strdupW(default_doc_title);
3003 job->printer_name = strdupW(printer->name);
3004 job->devmode = dup_devmode( printer->devmode );
3005 list_add_tail(&printer->queue->jobs, &job->entry);
3007 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
3008 if(*pcbNeeded <= cbBuf) {
3009 addjob = (ADDJOB_INFO_1W*)pData;
3010 addjob->JobId = job->job_id;
3011 addjob->Path = (WCHAR *)(addjob + 1);
3012 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
3013 ret = TRUE;
3014 } else
3015 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3017 end:
3018 LeaveCriticalSection(&printer_handles_cs);
3019 return ret;
3022 /*****************************************************************************
3023 * GetPrintProcessorDirectoryA [WINSPOOL.@]
3025 * Return the PATH for the Print-Processors
3027 * See GetPrintProcessorDirectoryW.
3031 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
3032 DWORD level, LPBYTE Info,
3033 DWORD cbBuf, LPDWORD pcbNeeded)
3035 LPWSTR serverW = NULL;
3036 LPWSTR envW = NULL;
3037 BOOL ret;
3038 INT len;
3040 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
3041 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
3044 if (server) {
3045 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
3046 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3047 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
3050 if (env) {
3051 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
3052 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3053 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
3056 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
3057 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
3059 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
3060 cbBuf, pcbNeeded);
3062 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
3063 cbBuf, NULL, NULL) > 0;
3066 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3067 HeapFree(GetProcessHeap(), 0, envW);
3068 HeapFree(GetProcessHeap(), 0, serverW);
3069 return ret;
3072 /*****************************************************************************
3073 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3075 * Return the PATH for the Print-Processors
3077 * PARAMS
3078 * server [I] Servername (NT only) or NULL (local Computer)
3079 * env [I] Printing-Environment (see below) or NULL (Default)
3080 * level [I] Structure-Level (must be 1)
3081 * Info [O] PTR to Buffer that receives the Result
3082 * cbBuf [I] Size of Buffer at "Info"
3083 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3084 * required for the Buffer at "Info"
3086 * RETURNS
3087 * Success: TRUE and in pcbNeeded the Bytes used in Info
3088 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3089 * if cbBuf is too small
3091 * Native Values returned in Info on Success:
3092 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3093 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3094 *| win9x(Windows 4.0): "%winsysdir%"
3096 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3098 * BUGS
3099 * Only NULL or "" is supported for server
3102 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3103 DWORD level, LPBYTE Info,
3104 DWORD cbBuf, LPDWORD pcbNeeded)
3107 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3108 Info, cbBuf, pcbNeeded);
3110 if ((backend == NULL) && !load_backend()) return FALSE;
3112 if (level != 1) {
3113 /* (Level != 1) is ignored in win9x */
3114 SetLastError(ERROR_INVALID_LEVEL);
3115 return FALSE;
3118 if (pcbNeeded == NULL) {
3119 /* (pcbNeeded == NULL) is ignored in win9x */
3120 SetLastError(RPC_X_NULL_REF_POINTER);
3121 return FALSE;
3124 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3127 /*****************************************************************************
3128 * WINSPOOL_OpenDriverReg [internal]
3130 * opens the registry for the printer drivers depending on the given input
3131 * variable pEnvironment
3133 * RETURNS:
3134 * the opened hkey on success
3135 * NULL on error
3137 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3139 HKEY retval = NULL;
3140 LPWSTR buffer;
3141 const printenv_t * env;
3143 TRACE("(%s)\n", debugstr_w(pEnvironment));
3145 env = validate_envW(pEnvironment);
3146 if (!env) return NULL;
3148 buffer = HeapAlloc( GetProcessHeap(), 0,
3149 (strlenW(DriversW) + strlenW(env->envname) +
3150 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3151 if(buffer) {
3152 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3153 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3154 HeapFree(GetProcessHeap(), 0, buffer);
3156 return retval;
3159 /*****************************************************************************
3160 * set_devices_and_printerports [internal]
3162 * set the [Devices] and [PrinterPorts] entries for a printer.
3165 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3167 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3168 WCHAR *devline;
3169 HKEY hkey;
3171 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3173 /* FIXME: the driver must change to "winspool" */
3174 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3175 if (devline) {
3176 lstrcpyW(devline, driver_nt);
3177 lstrcatW(devline, commaW);
3178 lstrcatW(devline, pi->pPortName);
3180 TRACE("using %s\n", debugstr_w(devline));
3181 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
3182 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3183 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3184 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3185 RegCloseKey(hkey);
3188 lstrcatW(devline, timeout_15_45);
3189 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
3190 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3191 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3192 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3193 RegCloseKey(hkey);
3195 HeapFree(GetProcessHeap(), 0, devline);
3199 /*****************************************************************************
3200 * AddPrinterW [WINSPOOL.@]
3202 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3204 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3205 LPDEVMODEW dm;
3206 HANDLE retval;
3207 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3208 LONG size;
3210 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3212 if(pName && *pName) {
3213 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3214 SetLastError(ERROR_INVALID_PARAMETER);
3215 return 0;
3217 if(Level != 2) {
3218 ERR("Level = %d, unsupported!\n", Level);
3219 SetLastError(ERROR_INVALID_LEVEL);
3220 return 0;
3222 if(!pPrinter) {
3223 SetLastError(ERROR_INVALID_PARAMETER);
3224 return 0;
3226 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3227 ERROR_SUCCESS) {
3228 ERR("Can't create Printers key\n");
3229 return 0;
3231 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3232 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3233 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3234 RegCloseKey(hkeyPrinter);
3235 RegCloseKey(hkeyPrinters);
3236 return 0;
3238 RegCloseKey(hkeyPrinter);
3240 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3241 if(!hkeyDrivers) {
3242 ERR("Can't create Drivers key\n");
3243 RegCloseKey(hkeyPrinters);
3244 return 0;
3246 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3247 ERROR_SUCCESS) {
3248 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3249 RegCloseKey(hkeyPrinters);
3250 RegCloseKey(hkeyDrivers);
3251 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3252 return 0;
3254 RegCloseKey(hkeyDriver);
3255 RegCloseKey(hkeyDrivers);
3257 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3258 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3259 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3260 RegCloseKey(hkeyPrinters);
3261 return 0;
3264 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3265 ERROR_SUCCESS) {
3266 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3267 SetLastError(ERROR_INVALID_PRINTER_NAME);
3268 RegCloseKey(hkeyPrinters);
3269 return 0;
3272 set_devices_and_printerports(pi);
3274 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3275 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3276 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3277 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3278 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3279 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3280 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3281 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3282 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3283 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3284 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3285 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3286 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3287 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3288 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3289 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3290 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3291 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3293 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3295 if (size < 0)
3297 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3298 size = sizeof(DEVMODEW);
3300 if(pi->pDevMode)
3301 dm = pi->pDevMode;
3302 else
3304 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3305 dm->dmSize = size;
3306 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3308 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3309 HeapFree( GetProcessHeap(), 0, dm );
3310 dm = NULL;
3312 else
3314 /* set devmode to printer name */
3315 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3319 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3320 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3322 RegCloseKey(hkeyPrinter);
3323 RegCloseKey(hkeyPrinters);
3324 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3325 ERR("OpenPrinter failing\n");
3326 return 0;
3328 return retval;
3331 /*****************************************************************************
3332 * AddPrinterA [WINSPOOL.@]
3334 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3336 UNICODE_STRING pNameW;
3337 PWSTR pwstrNameW;
3338 PRINTER_INFO_2W *piW;
3339 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3340 HANDLE ret;
3342 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3343 if(Level != 2) {
3344 ERR("Level = %d, unsupported!\n", Level);
3345 SetLastError(ERROR_INVALID_LEVEL);
3346 return 0;
3348 pwstrNameW = asciitounicode(&pNameW,pName);
3349 piW = printer_info_AtoW( piA, Level );
3351 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3353 free_printer_info( piW, Level );
3354 RtlFreeUnicodeString(&pNameW);
3355 return ret;
3359 /*****************************************************************************
3360 * ClosePrinter [WINSPOOL.@]
3362 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3364 UINT_PTR i = (UINT_PTR)hPrinter;
3365 opened_printer_t *printer = NULL;
3367 TRACE("(%p)\n", hPrinter);
3369 EnterCriticalSection(&printer_handles_cs);
3371 if ((i > 0) && (i <= nb_printer_handles))
3372 printer = printer_handles[i - 1];
3375 if(printer)
3377 struct list *cursor, *cursor2;
3379 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3381 if(printer->doc)
3382 EndDocPrinter(hPrinter);
3384 if(InterlockedDecrement(&printer->queue->ref) == 0)
3386 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3388 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3389 ScheduleJob(hPrinter, job->job_id);
3391 HeapFree(GetProcessHeap(), 0, printer->queue);
3394 if (printer->backend_printer) {
3395 backend->fpClosePrinter(printer->backend_printer);
3398 free_printer_entry( printer );
3399 printer_handles[i - 1] = NULL;
3400 LeaveCriticalSection(&printer_handles_cs);
3401 return TRUE;
3404 LeaveCriticalSection(&printer_handles_cs);
3405 SetLastError(ERROR_INVALID_HANDLE);
3406 return FALSE;
3409 /*****************************************************************************
3410 * DeleteFormA [WINSPOOL.@]
3412 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3414 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3415 return TRUE;
3418 /*****************************************************************************
3419 * DeleteFormW [WINSPOOL.@]
3421 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3423 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3424 return TRUE;
3427 /*****************************************************************************
3428 * DeletePrinter [WINSPOOL.@]
3430 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3432 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3433 HKEY hkeyPrinters, hkey;
3434 WCHAR def[MAX_PATH];
3435 DWORD size = ARRAY_SIZE(def);
3437 if(!lpNameW) {
3438 SetLastError(ERROR_INVALID_HANDLE);
3439 return FALSE;
3441 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3442 RegDeleteTreeW(hkeyPrinters, lpNameW);
3443 RegCloseKey(hkeyPrinters);
3445 WriteProfileStringW(devicesW, lpNameW, NULL);
3446 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3448 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3449 RegDeleteValueW(hkey, lpNameW);
3450 RegCloseKey(hkey);
3453 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3454 RegDeleteValueW(hkey, lpNameW);
3455 RegCloseKey(hkey);
3458 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3460 WriteProfileStringW( windowsW, deviceW, NULL );
3461 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3463 RegDeleteValueW( hkey, deviceW );
3464 RegCloseKey( hkey );
3466 SetDefaultPrinterW( NULL );
3469 return TRUE;
3472 /*****************************************************************************
3473 * SetPrinterA [WINSPOOL.@]
3475 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3477 BYTE *dataW = data;
3478 BOOL ret;
3480 if (level != 0)
3482 dataW = printer_info_AtoW( data, level );
3483 if (!dataW) return FALSE;
3486 ret = SetPrinterW( printer, level, dataW, command );
3488 if (dataW != data) free_printer_info( dataW, level );
3490 return ret;
3493 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3495 set_reg_szW( key, NameW, pi->pPrinterName );
3496 set_reg_szW( key, Share_NameW, pi->pShareName );
3497 set_reg_szW( key, PortW, pi->pPortName );
3498 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3499 set_reg_szW( key, DescriptionW, pi->pComment );
3500 set_reg_szW( key, LocationW, pi->pLocation );
3502 if (pi->pDevMode)
3503 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3505 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3506 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3507 set_reg_szW( key, DatatypeW, pi->pDatatype );
3508 set_reg_szW( key, ParametersW, pi->pParameters );
3510 set_reg_DWORD( key, AttributesW, pi->Attributes );
3511 set_reg_DWORD( key, PriorityW, pi->Priority );
3512 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3513 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3514 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3517 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3519 if (!pi->pDevMode) return FALSE;
3521 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3522 return TRUE;
3525 /******************************************************************************
3526 * SetPrinterW [WINSPOOL.@]
3528 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3530 HKEY key;
3531 BOOL ret = FALSE;
3533 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3535 if (command != 0) FIXME( "Ignoring command %d\n", command );
3537 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3538 return FALSE;
3540 switch (level)
3542 case 2:
3544 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3545 set_printer_2( key, pi2 );
3546 ret = TRUE;
3547 break;
3550 case 8:
3551 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
3552 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3553 /* fall through */
3554 case 9:
3556 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3557 ret = set_printer_9( key, pi );
3558 break;
3561 default:
3562 FIXME( "Unimplemented level %d\n", level );
3563 SetLastError( ERROR_INVALID_LEVEL );
3566 RegCloseKey( key );
3567 return ret;
3570 /*****************************************************************************
3571 * SetJobA [WINSPOOL.@]
3573 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3574 LPBYTE pJob, DWORD Command)
3576 BOOL ret;
3577 LPBYTE JobW;
3578 UNICODE_STRING usBuffer;
3580 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3582 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3583 are all ignored by SetJob, so we don't bother copying them */
3584 switch(Level)
3586 case 0:
3587 JobW = NULL;
3588 break;
3589 case 1:
3591 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3592 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3594 JobW = (LPBYTE)info1W;
3595 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3596 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3597 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3598 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3599 info1W->Status = info1A->Status;
3600 info1W->Priority = info1A->Priority;
3601 info1W->Position = info1A->Position;
3602 info1W->PagesPrinted = info1A->PagesPrinted;
3603 break;
3605 case 2:
3607 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3608 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3610 JobW = (LPBYTE)info2W;
3611 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3612 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3613 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3614 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3615 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3616 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3617 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3618 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3619 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3620 info2W->Status = info2A->Status;
3621 info2W->Priority = info2A->Priority;
3622 info2W->Position = info2A->Position;
3623 info2W->StartTime = info2A->StartTime;
3624 info2W->UntilTime = info2A->UntilTime;
3625 info2W->PagesPrinted = info2A->PagesPrinted;
3626 break;
3628 case 3:
3629 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3630 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3631 break;
3632 default:
3633 SetLastError(ERROR_INVALID_LEVEL);
3634 return FALSE;
3637 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3639 switch(Level)
3641 case 1:
3643 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3644 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3645 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3646 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3647 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3648 break;
3650 case 2:
3652 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3653 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3654 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3655 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3656 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3657 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3658 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3659 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3660 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3661 break;
3664 HeapFree(GetProcessHeap(), 0, JobW);
3666 return ret;
3669 /*****************************************************************************
3670 * SetJobW [WINSPOOL.@]
3672 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3673 LPBYTE pJob, DWORD Command)
3675 BOOL ret = FALSE;
3676 job_t *job;
3678 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3679 FIXME("Ignoring everything other than document title\n");
3681 EnterCriticalSection(&printer_handles_cs);
3682 job = get_job(hPrinter, JobId);
3683 if(!job)
3684 goto end;
3686 switch(Level)
3688 case 0:
3689 break;
3690 case 1:
3692 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3693 HeapFree(GetProcessHeap(), 0, job->document_title);
3694 job->document_title = strdupW(info1->pDocument);
3695 break;
3697 case 2:
3699 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3700 HeapFree(GetProcessHeap(), 0, job->document_title);
3701 job->document_title = strdupW(info2->pDocument);
3702 HeapFree(GetProcessHeap(), 0, job->devmode);
3703 job->devmode = dup_devmode( info2->pDevMode );
3704 break;
3706 case 3:
3707 break;
3708 default:
3709 SetLastError(ERROR_INVALID_LEVEL);
3710 goto end;
3712 ret = TRUE;
3713 end:
3714 LeaveCriticalSection(&printer_handles_cs);
3715 return ret;
3718 /*****************************************************************************
3719 * EndDocPrinter [WINSPOOL.@]
3721 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3723 opened_printer_t *printer;
3724 BOOL ret = FALSE;
3725 TRACE("(%p)\n", hPrinter);
3727 EnterCriticalSection(&printer_handles_cs);
3729 printer = get_opened_printer(hPrinter);
3730 if(!printer)
3732 SetLastError(ERROR_INVALID_HANDLE);
3733 goto end;
3736 if(!printer->doc)
3738 SetLastError(ERROR_SPL_NO_STARTDOC);
3739 goto end;
3742 CloseHandle(printer->doc->hf);
3743 ScheduleJob(hPrinter, printer->doc->job_id);
3744 HeapFree(GetProcessHeap(), 0, printer->doc);
3745 printer->doc = NULL;
3746 ret = TRUE;
3747 end:
3748 LeaveCriticalSection(&printer_handles_cs);
3749 return ret;
3752 /*****************************************************************************
3753 * EndPagePrinter [WINSPOOL.@]
3755 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3757 FIXME("(%p): stub\n", hPrinter);
3758 return TRUE;
3761 /*****************************************************************************
3762 * StartDocPrinterA [WINSPOOL.@]
3764 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3766 UNICODE_STRING usBuffer;
3767 DOC_INFO_2W doc2W;
3768 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3769 DWORD ret;
3771 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3772 or one (DOC_INFO_3) extra DWORDs */
3774 switch(Level) {
3775 case 2:
3776 doc2W.JobId = doc2->JobId;
3777 /* fall through */
3778 case 3:
3779 doc2W.dwMode = doc2->dwMode;
3780 /* fall through */
3781 case 1:
3782 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3783 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3784 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3785 break;
3787 default:
3788 SetLastError(ERROR_INVALID_LEVEL);
3789 return FALSE;
3792 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3794 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3795 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3796 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3798 return ret;
3801 /*****************************************************************************
3802 * StartDocPrinterW [WINSPOOL.@]
3804 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3806 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3807 opened_printer_t *printer;
3808 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3809 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3810 JOB_INFO_1W job_info;
3811 DWORD needed, ret = 0;
3812 HANDLE hf;
3813 WCHAR *filename;
3814 job_t *job;
3816 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3817 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3818 debugstr_w(doc->pDatatype));
3820 if(Level < 1 || Level > 3)
3822 SetLastError(ERROR_INVALID_LEVEL);
3823 return 0;
3826 EnterCriticalSection(&printer_handles_cs);
3827 printer = get_opened_printer(hPrinter);
3828 if(!printer)
3830 SetLastError(ERROR_INVALID_HANDLE);
3831 goto end;
3834 if(printer->doc)
3836 SetLastError(ERROR_INVALID_PRINTER_STATE);
3837 goto end;
3840 /* Even if we're printing to a file we still add a print job, we'll
3841 just ignore the spool file name */
3843 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3845 ERR("AddJob failed gle %u\n", GetLastError());
3846 goto end;
3849 /* use pOutputFile only, when it is a real filename */
3850 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3851 filename = doc->pOutputFile;
3852 else
3853 filename = addjob->Path;
3855 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3856 if(hf == INVALID_HANDLE_VALUE)
3857 goto end;
3859 memset(&job_info, 0, sizeof(job_info));
3860 job_info.pDocument = doc->pDocName;
3861 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3863 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3864 printer->doc->hf = hf;
3865 ret = printer->doc->job_id = addjob->JobId;
3866 job = get_job(hPrinter, ret);
3867 job->portname = strdupW(doc->pOutputFile);
3869 end:
3870 LeaveCriticalSection(&printer_handles_cs);
3872 return ret;
3875 /*****************************************************************************
3876 * StartPagePrinter [WINSPOOL.@]
3878 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3880 FIXME("(%p): stub\n", hPrinter);
3881 return TRUE;
3884 /*****************************************************************************
3885 * GetFormA [WINSPOOL.@]
3887 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3888 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3890 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3891 Level,pForm,cbBuf,pcbNeeded);
3892 return FALSE;
3895 /*****************************************************************************
3896 * GetFormW [WINSPOOL.@]
3898 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3899 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3901 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3902 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3903 return FALSE;
3906 /*****************************************************************************
3907 * SetFormA [WINSPOOL.@]
3909 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3910 LPBYTE pForm)
3912 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3913 return FALSE;
3916 /*****************************************************************************
3917 * SetFormW [WINSPOOL.@]
3919 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3920 LPBYTE pForm)
3922 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3923 return FALSE;
3926 /*****************************************************************************
3927 * ReadPrinter [WINSPOOL.@]
3929 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3930 LPDWORD pNoBytesRead)
3932 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3933 return FALSE;
3936 /*****************************************************************************
3937 * ResetPrinterA [WINSPOOL.@]
3939 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3941 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3942 return FALSE;
3945 /*****************************************************************************
3946 * ResetPrinterW [WINSPOOL.@]
3948 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3950 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3951 return FALSE;
3954 /*****************************************************************************
3955 * get_filename_from_reg [internal]
3957 * Get ValueName from hkey storing result in out
3958 * when the Value in the registry has only a filename, use driverdir as prefix
3959 * outlen is space left in out
3960 * String is stored either as unicode or ascii
3964 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3965 LPBYTE out, DWORD outlen, LPDWORD needed)
3967 WCHAR filename[MAX_PATH];
3968 DWORD size;
3969 DWORD type;
3970 LONG ret;
3971 LPWSTR buffer = filename;
3972 LPWSTR ptr;
3974 *needed = 0;
3975 size = sizeof(filename);
3976 buffer[0] = '\0';
3977 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3978 if (ret == ERROR_MORE_DATA) {
3979 TRACE("need dynamic buffer: %u\n", size);
3980 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3981 if (!buffer) {
3982 /* No Memory is bad */
3983 return FALSE;
3985 buffer[0] = '\0';
3986 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3989 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3990 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3991 return FALSE;
3994 ptr = buffer;
3995 while (ptr) {
3996 /* do we have a full path ? */
3997 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3998 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
4000 if (!ret) {
4001 /* we must build the full Path */
4002 *needed += dirlen;
4003 if ((out) && (outlen > dirlen)) {
4004 lstrcpyW((LPWSTR)out, driverdir);
4005 out += dirlen;
4006 outlen -= dirlen;
4008 else
4009 out = NULL;
4012 /* write the filename */
4013 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
4014 if ((out) && (outlen >= size)) {
4015 lstrcpyW((LPWSTR)out, ptr);
4016 out += size;
4017 outlen -= size;
4019 else
4020 out = NULL;
4021 *needed += size;
4022 ptr += lstrlenW(ptr)+1;
4023 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
4026 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
4028 /* write the multisz-termination */
4029 if (type == REG_MULTI_SZ) {
4030 size = sizeof(WCHAR);
4032 *needed += size;
4033 if (out && (outlen >= size)) {
4034 memset (out, 0, size);
4037 return TRUE;
4040 /*****************************************************************************
4041 * WINSPOOL_GetStringFromReg
4043 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4044 * String is stored as unicode.
4046 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
4047 DWORD buflen, DWORD *needed)
4049 DWORD sz = buflen, type;
4050 LONG ret;
4052 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4053 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
4054 WARN("Got ret = %d\n", ret);
4055 *needed = 0;
4056 return FALSE;
4058 /* add space for terminating '\0' */
4059 sz += sizeof(WCHAR);
4060 *needed = sz;
4062 if (ptr)
4063 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
4065 return TRUE;
4068 /*****************************************************************************
4069 * WINSPOOL_GetDefaultDevMode
4071 * Get a default DevMode values for wineps.
4073 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr, DWORD buflen, DWORD *needed)
4075 static const WCHAR winepsW[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4077 if (buflen >= sizeof(DEVMODEW))
4079 DEVMODEW *dm = (DEVMODEW *)ptr;
4081 /* the driver will update registry with real values */
4082 memset(dm, 0, sizeof(*dm));
4083 dm->dmSize = sizeof(*dm);
4084 lstrcpyW(dm->dmDeviceName, winepsW);
4086 *needed = sizeof(DEVMODEW);
4089 /*****************************************************************************
4090 * WINSPOOL_GetDevModeFromReg
4092 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4093 * DevMode is stored either as unicode or ascii.
4095 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4096 LPBYTE ptr,
4097 DWORD buflen, DWORD *needed)
4099 DWORD sz = buflen, type;
4100 LONG ret;
4102 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4103 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4104 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4105 if (sz < sizeof(DEVMODEA))
4107 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4108 return FALSE;
4110 /* ensures that dmSize is not erratically bogus if registry is invalid */
4111 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4112 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4113 sz += (CCHDEVICENAME + CCHFORMNAME);
4114 if (ptr && (buflen >= sz)) {
4115 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4116 memcpy(ptr, dmW, sz);
4117 HeapFree(GetProcessHeap(),0,dmW);
4119 *needed = sz;
4120 return TRUE;
4123 /*********************************************************************
4124 * WINSPOOL_GetPrinter_1
4126 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4128 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4129 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4131 DWORD size, left = cbBuf;
4132 BOOL space = (cbBuf > 0);
4133 LPBYTE ptr = buf;
4135 *pcbNeeded = 0;
4137 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4138 if(space && size <= left) {
4139 pi1->pName = (LPWSTR)ptr;
4140 ptr += size;
4141 left -= size;
4142 } else
4143 space = FALSE;
4144 *pcbNeeded += size;
4147 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4148 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4149 if(space && size <= left) {
4150 pi1->pDescription = (LPWSTR)ptr;
4151 ptr += size;
4152 left -= size;
4153 } else
4154 space = FALSE;
4155 *pcbNeeded += size;
4158 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4159 if(space && size <= left) {
4160 pi1->pComment = (LPWSTR)ptr;
4161 ptr += size;
4162 left -= size;
4163 } else
4164 space = FALSE;
4165 *pcbNeeded += size;
4168 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4170 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4171 memset(pi1, 0, sizeof(*pi1));
4173 return space;
4175 /*********************************************************************
4176 * WINSPOOL_GetPrinter_2
4178 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4180 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4181 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4183 DWORD size, left = cbBuf;
4184 BOOL space = (cbBuf > 0);
4185 LPBYTE ptr = buf;
4187 *pcbNeeded = 0;
4189 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4190 if(space && size <= left) {
4191 pi2->pPrinterName = (LPWSTR)ptr;
4192 ptr += size;
4193 left -= size;
4194 } else
4195 space = FALSE;
4196 *pcbNeeded += size;
4198 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4199 if(space && size <= left) {
4200 pi2->pShareName = (LPWSTR)ptr;
4201 ptr += size;
4202 left -= size;
4203 } else
4204 space = FALSE;
4205 *pcbNeeded += size;
4207 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4208 if(space && size <= left) {
4209 pi2->pPortName = (LPWSTR)ptr;
4210 ptr += size;
4211 left -= size;
4212 } else
4213 space = FALSE;
4214 *pcbNeeded += size;
4216 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4217 if(space && size <= left) {
4218 pi2->pDriverName = (LPWSTR)ptr;
4219 ptr += size;
4220 left -= size;
4221 } else
4222 space = FALSE;
4223 *pcbNeeded += size;
4225 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4226 if(space && size <= left) {
4227 pi2->pComment = (LPWSTR)ptr;
4228 ptr += size;
4229 left -= size;
4230 } else
4231 space = FALSE;
4232 *pcbNeeded += size;
4234 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4235 if(space && size <= left) {
4236 pi2->pLocation = (LPWSTR)ptr;
4237 ptr += size;
4238 left -= size;
4239 } else
4240 space = FALSE;
4241 *pcbNeeded += size;
4243 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4244 if(space && size <= left) {
4245 pi2->pDevMode = (LPDEVMODEW)ptr;
4246 ptr += size;
4247 left -= size;
4248 } else
4249 space = FALSE;
4250 *pcbNeeded += size;
4252 else
4254 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4255 if(space && size <= left) {
4256 pi2->pDevMode = (LPDEVMODEW)ptr;
4257 ptr += size;
4258 left -= size;
4259 } else
4260 space = FALSE;
4261 *pcbNeeded += size;
4263 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4264 if(space && size <= left) {
4265 pi2->pSepFile = (LPWSTR)ptr;
4266 ptr += size;
4267 left -= size;
4268 } else
4269 space = FALSE;
4270 *pcbNeeded += size;
4272 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4273 if(space && size <= left) {
4274 pi2->pPrintProcessor = (LPWSTR)ptr;
4275 ptr += size;
4276 left -= size;
4277 } else
4278 space = FALSE;
4279 *pcbNeeded += size;
4281 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4282 if(space && size <= left) {
4283 pi2->pDatatype = (LPWSTR)ptr;
4284 ptr += size;
4285 left -= size;
4286 } else
4287 space = FALSE;
4288 *pcbNeeded += size;
4290 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4291 if(space && size <= left) {
4292 pi2->pParameters = (LPWSTR)ptr;
4293 ptr += size;
4294 left -= size;
4295 } else
4296 space = FALSE;
4297 *pcbNeeded += size;
4299 if(pi2) {
4300 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4301 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4302 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4303 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4304 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4307 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4308 memset(pi2, 0, sizeof(*pi2));
4310 return space;
4313 /*********************************************************************
4314 * WINSPOOL_GetPrinter_4
4316 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4318 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4319 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4321 DWORD size, left = cbBuf;
4322 BOOL space = (cbBuf > 0);
4323 LPBYTE ptr = buf;
4325 *pcbNeeded = 0;
4327 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4328 if(space && size <= left) {
4329 pi4->pPrinterName = (LPWSTR)ptr;
4330 ptr += size;
4331 left -= size;
4332 } else
4333 space = FALSE;
4334 *pcbNeeded += size;
4336 if(pi4) {
4337 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4340 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4341 memset(pi4, 0, sizeof(*pi4));
4343 return space;
4346 /*********************************************************************
4347 * WINSPOOL_GetPrinter_5
4349 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4351 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4352 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4354 DWORD size, left = cbBuf;
4355 BOOL space = (cbBuf > 0);
4356 LPBYTE ptr = buf;
4358 *pcbNeeded = 0;
4360 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4361 if(space && size <= left) {
4362 pi5->pPrinterName = (LPWSTR)ptr;
4363 ptr += size;
4364 left -= size;
4365 } else
4366 space = FALSE;
4367 *pcbNeeded += size;
4369 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4370 if(space && size <= left) {
4371 pi5->pPortName = (LPWSTR)ptr;
4372 ptr += size;
4373 left -= size;
4374 } else
4375 space = FALSE;
4376 *pcbNeeded += size;
4378 if(pi5) {
4379 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4380 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4381 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4384 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4385 memset(pi5, 0, sizeof(*pi5));
4387 return space;
4390 /*********************************************************************
4391 * WINSPOOL_GetPrinter_7
4393 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4395 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4396 DWORD cbBuf, LPDWORD pcbNeeded)
4398 DWORD size, left = cbBuf;
4399 BOOL space = (cbBuf > 0);
4400 LPBYTE ptr = buf;
4402 *pcbNeeded = 0;
4404 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4406 ptr = NULL;
4407 size = sizeof(pi7->pszObjectGUID);
4409 if (space && size <= left) {
4410 pi7->pszObjectGUID = (LPWSTR)ptr;
4411 ptr += size;
4412 left -= size;
4413 } else
4414 space = FALSE;
4415 *pcbNeeded += size;
4416 if (pi7) {
4417 /* We do not have a Directory Service */
4418 pi7->dwAction = DSPRINT_UNPUBLISH;
4421 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4422 memset(pi7, 0, sizeof(*pi7));
4424 return space;
4427 /*********************************************************************
4428 * WINSPOOL_GetPrinter_9
4430 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4432 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4433 DWORD cbBuf, LPDWORD pcbNeeded)
4435 DWORD size;
4436 BOOL space = (cbBuf > 0);
4438 *pcbNeeded = 0;
4440 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4441 if(space && size <= cbBuf) {
4442 pi9->pDevMode = (LPDEVMODEW)buf;
4443 } else
4444 space = FALSE;
4445 *pcbNeeded += size;
4447 else
4449 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4450 if(space && size <= cbBuf) {
4451 pi9->pDevMode = (LPDEVMODEW)buf;
4452 } else
4453 space = FALSE;
4454 *pcbNeeded += size;
4457 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4458 memset(pi9, 0, sizeof(*pi9));
4460 return space;
4463 /*****************************************************************************
4464 * GetPrinterW [WINSPOOL.@]
4466 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4467 DWORD cbBuf, LPDWORD pcbNeeded)
4469 DWORD size, needed = 0, err;
4470 LPBYTE ptr = NULL;
4471 HKEY hkeyPrinter;
4472 BOOL ret;
4474 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4476 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4477 if (err)
4479 SetLastError( err );
4480 return FALSE;
4483 switch(Level) {
4484 case 1:
4486 PRINTER_INFO_1W *pi1 = (PRINTER_INFO_1W *)pPrinter;
4488 size = sizeof(PRINTER_INFO_1W);
4489 if (size <= cbBuf) {
4490 ptr = pPrinter + size;
4491 cbBuf -= size;
4492 memset(pPrinter, 0, size);
4493 } else {
4494 pi1 = NULL;
4495 cbBuf = 0;
4497 ret = WINSPOOL_GetPrinter_1(hkeyPrinter, pi1, ptr, cbBuf, &needed);
4498 needed += size;
4499 break;
4502 case 2:
4504 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4506 size = sizeof(PRINTER_INFO_2W);
4507 if(size <= cbBuf) {
4508 ptr = pPrinter + size;
4509 cbBuf -= size;
4510 memset(pPrinter, 0, size);
4511 } else {
4512 pi2 = NULL;
4513 cbBuf = 0;
4515 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4516 needed += size;
4517 break;
4520 case 4:
4522 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4524 size = sizeof(PRINTER_INFO_4W);
4525 if(size <= cbBuf) {
4526 ptr = pPrinter + size;
4527 cbBuf -= size;
4528 memset(pPrinter, 0, size);
4529 } else {
4530 pi4 = NULL;
4531 cbBuf = 0;
4533 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4534 needed += size;
4535 break;
4539 case 5:
4541 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4543 size = sizeof(PRINTER_INFO_5W);
4544 if(size <= cbBuf) {
4545 ptr = pPrinter + size;
4546 cbBuf -= size;
4547 memset(pPrinter, 0, size);
4548 } else {
4549 pi5 = NULL;
4550 cbBuf = 0;
4553 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4554 needed += size;
4555 break;
4559 case 6:
4561 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4563 size = sizeof(PRINTER_INFO_6);
4564 if (size <= cbBuf) {
4565 /* FIXME: We do not update the status yet */
4566 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4567 ret = TRUE;
4568 } else {
4569 ret = FALSE;
4572 needed += size;
4573 break;
4576 case 7:
4578 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4580 size = sizeof(PRINTER_INFO_7W);
4581 if (size <= cbBuf) {
4582 ptr = pPrinter + size;
4583 cbBuf -= size;
4584 memset(pPrinter, 0, size);
4585 } else {
4586 pi7 = NULL;
4587 cbBuf = 0;
4590 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4591 needed += size;
4592 break;
4596 case 8:
4597 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4598 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4599 /* fall through */
4600 case 9:
4602 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4604 size = sizeof(PRINTER_INFO_9W);
4605 if(size <= cbBuf) {
4606 ptr = pPrinter + size;
4607 cbBuf -= size;
4608 memset(pPrinter, 0, size);
4609 } else {
4610 pi9 = NULL;
4611 cbBuf = 0;
4614 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4615 needed += size;
4616 break;
4620 default:
4621 FIXME("Unimplemented level %d\n", Level);
4622 SetLastError(ERROR_INVALID_LEVEL);
4623 RegCloseKey(hkeyPrinter);
4624 return FALSE;
4627 RegCloseKey(hkeyPrinter);
4629 TRACE("returning %d needed = %d\n", ret, needed);
4630 if(pcbNeeded) *pcbNeeded = needed;
4631 if(!ret)
4632 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4633 return ret;
4636 /*****************************************************************************
4637 * GetPrinterA [WINSPOOL.@]
4639 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4640 DWORD cbBuf, LPDWORD pcbNeeded)
4642 BOOL ret;
4643 LPBYTE buf = NULL;
4645 if (cbBuf)
4646 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4648 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4649 if (ret)
4650 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4651 HeapFree(GetProcessHeap(), 0, buf);
4653 return ret;
4656 /*****************************************************************************
4657 * WINSPOOL_EnumPrintersW
4659 * Implementation of EnumPrintersW
4661 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4662 DWORD dwLevel, LPBYTE lpbPrinters,
4663 DWORD cbBuf, LPDWORD lpdwNeeded,
4664 LPDWORD lpdwReturned)
4667 HKEY hkeyPrinters, hkeyPrinter;
4668 WCHAR PrinterName[255];
4669 DWORD needed = 0, number = 0;
4670 DWORD used, i, left;
4671 PBYTE pi, buf;
4673 if(lpbPrinters)
4674 memset(lpbPrinters, 0, cbBuf);
4675 if(lpdwReturned)
4676 *lpdwReturned = 0;
4677 if(lpdwNeeded)
4678 *lpdwNeeded = 0;
4680 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4681 if(dwType == PRINTER_ENUM_DEFAULT)
4682 return TRUE;
4684 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4685 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4686 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4687 if (!dwType) {
4688 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4689 return TRUE;
4694 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4695 FIXME("dwType = %08x\n", dwType);
4696 SetLastError(ERROR_INVALID_FLAGS);
4697 return FALSE;
4700 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4701 ERROR_SUCCESS) {
4702 ERR("Can't create Printers key\n");
4703 return FALSE;
4706 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4707 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4708 RegCloseKey(hkeyPrinters);
4709 ERR("Can't query Printers key\n");
4710 return FALSE;
4712 TRACE("Found %d printers\n", number);
4714 switch(dwLevel) {
4715 case 1:
4716 used = number * sizeof(PRINTER_INFO_1W);
4717 break;
4718 case 2:
4719 used = number * sizeof(PRINTER_INFO_2W);
4720 break;
4721 case 4:
4722 used = number * sizeof(PRINTER_INFO_4W);
4723 break;
4724 case 5:
4725 used = number * sizeof(PRINTER_INFO_5W);
4726 break;
4728 default:
4729 SetLastError(ERROR_INVALID_LEVEL);
4730 RegCloseKey(hkeyPrinters);
4731 return FALSE;
4733 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4735 for(i = 0; i < number; i++) {
4736 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, ARRAY_SIZE(PrinterName)) != ERROR_SUCCESS) {
4737 ERR("Can't enum key number %d\n", i);
4738 RegCloseKey(hkeyPrinters);
4739 return FALSE;
4741 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4742 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4743 ERROR_SUCCESS) {
4744 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4745 RegCloseKey(hkeyPrinters);
4746 return FALSE;
4749 if(cbBuf > used) {
4750 buf = lpbPrinters + used;
4751 left = cbBuf - used;
4752 } else {
4753 buf = NULL;
4754 left = 0;
4757 switch(dwLevel) {
4758 case 1:
4759 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4760 left, &needed);
4761 used += needed;
4762 if(pi) pi += sizeof(PRINTER_INFO_1W);
4763 break;
4764 case 2:
4765 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4766 left, &needed);
4767 used += needed;
4768 if(pi) pi += sizeof(PRINTER_INFO_2W);
4769 break;
4770 case 4:
4771 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4772 left, &needed);
4773 used += needed;
4774 if(pi) pi += sizeof(PRINTER_INFO_4W);
4775 break;
4776 case 5:
4777 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4778 left, &needed);
4779 used += needed;
4780 if(pi) pi += sizeof(PRINTER_INFO_5W);
4781 break;
4782 default:
4783 ERR("Shouldn't be here!\n");
4784 RegCloseKey(hkeyPrinter);
4785 RegCloseKey(hkeyPrinters);
4786 return FALSE;
4788 RegCloseKey(hkeyPrinter);
4790 RegCloseKey(hkeyPrinters);
4792 if(lpdwNeeded)
4793 *lpdwNeeded = used;
4795 if(used > cbBuf) {
4796 if(lpbPrinters)
4797 memset(lpbPrinters, 0, cbBuf);
4798 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4799 return FALSE;
4801 if(lpdwReturned)
4802 *lpdwReturned = number;
4803 SetLastError(ERROR_SUCCESS);
4804 return TRUE;
4808 /******************************************************************
4809 * EnumPrintersW [WINSPOOL.@]
4811 * Enumerates the available printers, print servers and print
4812 * providers, depending on the specified flags, name and level.
4814 * RETURNS:
4816 * If level is set to 1:
4817 * Returns an array of PRINTER_INFO_1 data structures in the
4818 * lpbPrinters buffer.
4820 * If level is set to 2:
4821 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4822 * Returns an array of PRINTER_INFO_2 data structures in the
4823 * lpbPrinters buffer. Note that according to MSDN also an
4824 * OpenPrinter should be performed on every remote printer.
4826 * If level is set to 4 (officially WinNT only):
4827 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4828 * Fast: Only the registry is queried to retrieve printer names,
4829 * no connection to the driver is made.
4830 * Returns an array of PRINTER_INFO_4 data structures in the
4831 * lpbPrinters buffer.
4833 * If level is set to 5 (officially WinNT4/Win9x only):
4834 * Fast: Only the registry is queried to retrieve printer names,
4835 * no connection to the driver is made.
4836 * Returns an array of PRINTER_INFO_5 data structures in the
4837 * lpbPrinters buffer.
4839 * If level set to 3 or 6+:
4840 * returns zero (failure!)
4842 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4843 * for information.
4845 * BUGS:
4846 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4847 * - Only levels 2, 4 and 5 are implemented at the moment.
4848 * - 16-bit printer drivers are not enumerated.
4849 * - Returned amount of bytes used/needed does not match the real Windoze
4850 * implementation (as in this implementation, all strings are part
4851 * of the buffer, whereas Win32 keeps them somewhere else)
4852 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4854 * NOTE:
4855 * - In a regular Wine installation, no registry settings for printers
4856 * exist, which makes this function return an empty list.
4858 BOOL WINAPI EnumPrintersW(
4859 DWORD dwType, /* [in] Types of print objects to enumerate */
4860 LPWSTR lpszName, /* [in] name of objects to enumerate */
4861 DWORD dwLevel, /* [in] type of printer info structure */
4862 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4863 DWORD cbBuf, /* [in] max size of buffer in bytes */
4864 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4865 LPDWORD lpdwReturned /* [out] number of entries returned */
4868 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4869 lpdwNeeded, lpdwReturned);
4872 /******************************************************************
4873 * EnumPrintersA [WINSPOOL.@]
4875 * See EnumPrintersW
4878 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4879 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4881 BOOL ret;
4882 UNICODE_STRING pNameU;
4883 LPWSTR pNameW;
4884 LPBYTE pPrintersW;
4886 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4887 pPrinters, cbBuf, pcbNeeded, pcReturned);
4889 pNameW = asciitounicode(&pNameU, pName);
4891 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4892 MS Office need this */
4893 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4895 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4897 RtlFreeUnicodeString(&pNameU);
4898 if (ret) {
4899 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4901 HeapFree(GetProcessHeap(), 0, pPrintersW);
4902 return ret;
4905 /*****************************************************************************
4906 * WINSPOOL_GetDriverInfoFromReg [internal]
4908 * Enters the information from the registry into the DRIVER_INFO struct
4910 * RETURNS
4911 * zero if the printer driver does not exist in the registry
4912 * (only if Level > 1) otherwise nonzero
4914 static BOOL WINSPOOL_GetDriverInfoFromReg(
4915 HKEY hkeyDrivers,
4916 LPWSTR DriverName,
4917 const printenv_t * env,
4918 DWORD Level,
4919 LPBYTE ptr, /* DRIVER_INFO */
4920 LPBYTE pDriverStrings, /* strings buffer */
4921 DWORD cbBuf, /* size of string buffer */
4922 LPDWORD pcbNeeded) /* space needed for str. */
4924 DWORD size, tmp;
4925 HKEY hkeyDriver;
4926 WCHAR driverdir[MAX_PATH];
4927 DWORD dirlen;
4928 LPBYTE strPtr = pDriverStrings;
4929 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4931 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4932 debugstr_w(DriverName), env,
4933 Level, di, pDriverStrings, cbBuf);
4935 if (di) ZeroMemory(di, di_sizeof[Level]);
4937 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4938 if (*pcbNeeded <= cbBuf)
4939 strcpyW((LPWSTR)strPtr, DriverName);
4941 /* pName for level 1 has a different offset! */
4942 if (Level == 1) {
4943 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4944 return TRUE;
4947 /* .cVersion and .pName for level > 1 */
4948 if (di) {
4949 di->cVersion = env->driverversion;
4950 di->pName = (LPWSTR) strPtr;
4951 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4954 /* Reserve Space for the largest subdir and a Backslash*/
4955 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4956 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4957 /* Should never Fail */
4958 return FALSE;
4960 lstrcatW(driverdir, env->versionsubdir);
4961 lstrcatW(driverdir, backslashW);
4963 /* dirlen must not include the terminating zero */
4964 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4966 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4967 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4968 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4969 return FALSE;
4972 /* pEnvironment */
4973 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4975 *pcbNeeded += size;
4976 if (*pcbNeeded <= cbBuf) {
4977 lstrcpyW((LPWSTR)strPtr, env->envname);
4978 if (di) di->pEnvironment = (LPWSTR)strPtr;
4979 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4982 /* .pDriverPath is the Graphics rendering engine.
4983 The full Path is required to avoid a crash in some apps */
4984 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4985 *pcbNeeded += size;
4986 if (*pcbNeeded <= cbBuf)
4987 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4989 if (di) di->pDriverPath = (LPWSTR)strPtr;
4990 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4993 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4994 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4995 *pcbNeeded += size;
4996 if (*pcbNeeded <= cbBuf)
4997 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4999 if (di) di->pDataFile = (LPWSTR)strPtr;
5000 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5003 /* .pConfigFile is the Driver user Interface */
5004 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
5005 *pcbNeeded += size;
5006 if (*pcbNeeded <= cbBuf)
5007 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
5009 if (di) di->pConfigFile = (LPWSTR)strPtr;
5010 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5013 if (Level == 2 ) {
5014 RegCloseKey(hkeyDriver);
5015 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5016 return TRUE;
5019 if (Level == 5 ) {
5020 RegCloseKey(hkeyDriver);
5021 FIXME("level 5: incomplete\n");
5022 return TRUE;
5025 /* .pHelpFile */
5026 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
5027 *pcbNeeded += size;
5028 if (*pcbNeeded <= cbBuf)
5029 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
5031 if (di) di->pHelpFile = (LPWSTR)strPtr;
5032 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5035 /* .pDependentFiles */
5036 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
5037 *pcbNeeded += size;
5038 if (*pcbNeeded <= cbBuf)
5039 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
5041 if (di) di->pDependentFiles = (LPWSTR)strPtr;
5042 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5044 else if (GetVersion() & 0x80000000) {
5045 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
5046 size = 2 * sizeof(WCHAR);
5047 *pcbNeeded += size;
5048 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
5050 if (di) di->pDependentFiles = (LPWSTR)strPtr;
5051 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5054 /* .pMonitorName is the optional Language Monitor */
5055 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
5056 *pcbNeeded += size;
5057 if (*pcbNeeded <= cbBuf)
5058 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
5060 if (di) di->pMonitorName = (LPWSTR)strPtr;
5061 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5064 /* .pDefaultDataType */
5065 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
5066 *pcbNeeded += size;
5067 if(*pcbNeeded <= cbBuf)
5068 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
5070 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
5071 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5074 if (Level == 3 ) {
5075 RegCloseKey(hkeyDriver);
5076 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5077 return TRUE;
5080 /* .pszzPreviousNames */
5081 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
5082 *pcbNeeded += size;
5083 if(*pcbNeeded <= cbBuf)
5084 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
5086 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
5087 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5090 if (Level == 4 ) {
5091 RegCloseKey(hkeyDriver);
5092 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5093 return TRUE;
5096 /* support is missing, but not important enough for a FIXME */
5097 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5099 /* .pszMfgName */
5100 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5101 *pcbNeeded += size;
5102 if(*pcbNeeded <= cbBuf)
5103 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5105 if (di) di->pszMfgName = (LPWSTR)strPtr;
5106 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5109 /* .pszOEMUrl */
5110 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5111 *pcbNeeded += size;
5112 if(*pcbNeeded <= cbBuf)
5113 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5115 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5116 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5119 /* .pszHardwareID */
5120 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5121 *pcbNeeded += size;
5122 if(*pcbNeeded <= cbBuf)
5123 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5125 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5126 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5129 /* .pszProvider */
5130 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5131 *pcbNeeded += size;
5132 if(*pcbNeeded <= cbBuf)
5133 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5135 if (di) di->pszProvider = (LPWSTR)strPtr;
5136 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5139 if (Level == 6 ) {
5140 RegCloseKey(hkeyDriver);
5141 return TRUE;
5144 /* support is missing, but not important enough for a FIXME */
5145 TRACE("level 8: incomplete\n");
5147 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5148 RegCloseKey(hkeyDriver);
5149 return TRUE;
5152 /*****************************************************************************
5153 * GetPrinterDriverW [WINSPOOL.@]
5155 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5156 DWORD Level, LPBYTE pDriverInfo,
5157 DWORD cbBuf, LPDWORD pcbNeeded)
5159 LPCWSTR name;
5160 WCHAR DriverName[100];
5161 DWORD ret, type, size, needed = 0;
5162 LPBYTE ptr = NULL;
5163 HKEY hkeyPrinter, hkeyDrivers;
5164 const printenv_t * env;
5166 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5167 Level,pDriverInfo,cbBuf, pcbNeeded);
5169 if (cbBuf > 0)
5170 ZeroMemory(pDriverInfo, cbBuf);
5172 if (!(name = get_opened_printer_name(hPrinter))) {
5173 SetLastError(ERROR_INVALID_HANDLE);
5174 return FALSE;
5177 if (Level < 1 || Level == 7 || Level > 8) {
5178 SetLastError(ERROR_INVALID_LEVEL);
5179 return FALSE;
5182 env = validate_envW(pEnvironment);
5183 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5185 ret = open_printer_reg_key( name, &hkeyPrinter );
5186 if (ret)
5188 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5189 SetLastError( ret );
5190 return FALSE;
5193 size = sizeof(DriverName);
5194 DriverName[0] = 0;
5195 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5196 (LPBYTE)DriverName, &size);
5197 RegCloseKey(hkeyPrinter);
5198 if(ret != ERROR_SUCCESS) {
5199 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5200 return FALSE;
5203 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5204 if(!hkeyDrivers) {
5205 ERR("Can't create Drivers key\n");
5206 return FALSE;
5209 size = di_sizeof[Level];
5210 if ((size <= cbBuf) && pDriverInfo)
5211 ptr = pDriverInfo + size;
5213 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5214 env, Level, pDriverInfo, ptr,
5215 (cbBuf < size) ? 0 : cbBuf - size,
5216 &needed)) {
5217 RegCloseKey(hkeyDrivers);
5218 return FALSE;
5221 RegCloseKey(hkeyDrivers);
5223 if(pcbNeeded) *pcbNeeded = size + needed;
5224 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5225 if(cbBuf >= size + needed) return TRUE;
5226 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5227 return FALSE;
5230 /*****************************************************************************
5231 * GetPrinterDriverA [WINSPOOL.@]
5233 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5234 DWORD Level, LPBYTE pDriverInfo,
5235 DWORD cbBuf, LPDWORD pcbNeeded)
5237 BOOL ret;
5238 UNICODE_STRING pEnvW;
5239 PWSTR pwstrEnvW;
5240 LPBYTE buf = NULL;
5242 if (cbBuf)
5244 ZeroMemory(pDriverInfo, cbBuf);
5245 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5248 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5249 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5250 cbBuf, pcbNeeded);
5251 if (ret)
5252 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5254 HeapFree(GetProcessHeap(), 0, buf);
5256 RtlFreeUnicodeString(&pEnvW);
5257 return ret;
5260 /*****************************************************************************
5261 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5263 * Return the PATH for the Printer-Drivers (UNICODE)
5265 * PARAMS
5266 * pName [I] Servername (NT only) or NULL (local Computer)
5267 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5268 * Level [I] Structure-Level (must be 1)
5269 * pDriverDirectory [O] PTR to Buffer that receives the Result
5270 * cbBuf [I] Size of Buffer at pDriverDirectory
5271 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5272 * required for pDriverDirectory
5274 * RETURNS
5275 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5276 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5277 * if cbBuf is too small
5279 * Native Values returned in pDriverDirectory on Success:
5280 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5281 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5282 *| win9x(Windows 4.0): "%winsysdir%"
5284 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5286 * FIXME
5287 *- Only NULL or "" is supported for pName
5290 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5291 DWORD Level, LPBYTE pDriverDirectory,
5292 DWORD cbBuf, LPDWORD pcbNeeded)
5294 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5295 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5297 if ((backend == NULL) && !load_backend()) return FALSE;
5299 if (Level != 1) {
5300 /* (Level != 1) is ignored in win9x */
5301 SetLastError(ERROR_INVALID_LEVEL);
5302 return FALSE;
5304 if (pcbNeeded == NULL) {
5305 /* (pcbNeeded == NULL) is ignored in win9x */
5306 SetLastError(RPC_X_NULL_REF_POINTER);
5307 return FALSE;
5310 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5311 pDriverDirectory, cbBuf, pcbNeeded);
5316 /*****************************************************************************
5317 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5319 * Return the PATH for the Printer-Drivers (ANSI)
5321 * See GetPrinterDriverDirectoryW.
5323 * NOTES
5324 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5327 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5328 DWORD Level, LPBYTE pDriverDirectory,
5329 DWORD cbBuf, LPDWORD pcbNeeded)
5331 UNICODE_STRING nameW, environmentW;
5332 BOOL ret;
5333 DWORD pcbNeededW;
5334 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5335 WCHAR *driverDirectoryW = NULL;
5337 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5338 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5340 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5342 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5343 else nameW.Buffer = NULL;
5344 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5345 else environmentW.Buffer = NULL;
5347 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5348 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5349 if (ret) {
5350 DWORD needed;
5351 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5352 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5353 if(pcbNeeded)
5354 *pcbNeeded = needed;
5355 ret = needed <= cbBuf;
5356 } else
5357 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5359 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5361 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5362 RtlFreeUnicodeString(&environmentW);
5363 RtlFreeUnicodeString(&nameW);
5365 return ret;
5368 /*****************************************************************************
5369 * AddPrinterDriverA [WINSPOOL.@]
5371 * See AddPrinterDriverW.
5374 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5376 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5377 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5380 /******************************************************************************
5381 * AddPrinterDriverW (WINSPOOL.@)
5383 * Install a Printer Driver
5385 * PARAMS
5386 * pName [I] Servername or NULL (local Computer)
5387 * level [I] Level for the supplied DRIVER_INFO_*W struct
5388 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5390 * RESULTS
5391 * Success: TRUE
5392 * Failure: FALSE
5395 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5397 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5398 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5401 /*****************************************************************************
5402 * AddPrintProcessorA [WINSPOOL.@]
5404 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5405 LPSTR pPrintProcessorName)
5407 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5408 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5409 return FALSE;
5412 /*****************************************************************************
5413 * AddPrintProcessorW [WINSPOOL.@]
5415 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5416 LPWSTR pPrintProcessorName)
5418 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5419 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5420 return TRUE;
5423 /*****************************************************************************
5424 * AddPrintProvidorA [WINSPOOL.@]
5426 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5428 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5429 return FALSE;
5432 /*****************************************************************************
5433 * AddPrintProvidorW [WINSPOOL.@]
5435 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5437 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5438 return FALSE;
5441 /*****************************************************************************
5442 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5444 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5445 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5447 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5448 pDevModeOutput, pDevModeInput);
5449 return 0;
5452 /*****************************************************************************
5453 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5455 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5456 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5458 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5459 pDevModeOutput, pDevModeInput);
5460 return 0;
5463 /*****************************************************************************
5464 * PrinterProperties [WINSPOOL.@]
5466 * Displays a dialog to set the properties of the printer.
5468 * RETURNS
5469 * nonzero on success or zero on failure
5471 * BUGS
5472 * implemented as stub only
5474 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5475 HANDLE hPrinter /* [in] handle to printer object */
5477 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5478 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5479 return FALSE;
5482 /*****************************************************************************
5483 * EnumJobsA [WINSPOOL.@]
5486 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5487 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5488 LPDWORD pcReturned)
5490 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5491 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5493 if(pcbNeeded) *pcbNeeded = 0;
5494 if(pcReturned) *pcReturned = 0;
5495 return FALSE;
5499 /*****************************************************************************
5500 * EnumJobsW [WINSPOOL.@]
5503 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5504 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5505 LPDWORD pcReturned)
5507 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5508 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5510 if(pcbNeeded) *pcbNeeded = 0;
5511 if(pcReturned) *pcReturned = 0;
5512 return FALSE;
5515 /*****************************************************************************
5516 * WINSPOOL_EnumPrinterDrivers [internal]
5518 * Delivers information about all printer drivers installed on the
5519 * localhost or a given server
5521 * RETURNS
5522 * nonzero on success or zero on failure. If the buffer for the returned
5523 * information is too small the function will return an error
5525 * BUGS
5526 * - only implemented for localhost, foreign hosts will return an error
5528 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5529 DWORD Level, LPBYTE pDriverInfo,
5530 DWORD driver_index,
5531 DWORD cbBuf, LPDWORD pcbNeeded,
5532 LPDWORD pcFound, DWORD data_offset)
5534 { HKEY hkeyDrivers;
5535 DWORD i, size = 0;
5536 const printenv_t * env;
5538 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5539 debugstr_w(pName), debugstr_w(pEnvironment),
5540 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5542 env = validate_envW(pEnvironment);
5543 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5545 *pcFound = 0;
5547 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5548 if(!hkeyDrivers) {
5549 ERR("Can't open Drivers key\n");
5550 return FALSE;
5553 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5554 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5555 RegCloseKey(hkeyDrivers);
5556 ERR("Can't query Drivers key\n");
5557 return FALSE;
5559 TRACE("Found %d Drivers\n", *pcFound);
5561 /* get size of single struct
5562 * unicode and ascii structure have the same size
5564 size = di_sizeof[Level];
5566 if (data_offset == 0)
5567 data_offset = size * (*pcFound);
5568 *pcbNeeded = data_offset;
5570 for( i = 0; i < *pcFound; i++) {
5571 WCHAR DriverNameW[255];
5572 PBYTE table_ptr = NULL;
5573 PBYTE data_ptr = NULL;
5574 DWORD needed = 0;
5576 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, ARRAY_SIZE(DriverNameW)) != ERROR_SUCCESS) {
5577 ERR("Can't enum key number %d\n", i);
5578 RegCloseKey(hkeyDrivers);
5579 return FALSE;
5582 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5583 table_ptr = pDriverInfo + (driver_index + i) * size;
5584 if (pDriverInfo && *pcbNeeded <= cbBuf)
5585 data_ptr = pDriverInfo + *pcbNeeded;
5587 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5588 env, Level, table_ptr, data_ptr,
5589 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5590 &needed)) {
5591 RegCloseKey(hkeyDrivers);
5592 return FALSE;
5595 *pcbNeeded += needed;
5598 RegCloseKey(hkeyDrivers);
5600 if(cbBuf < *pcbNeeded){
5601 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5602 return FALSE;
5605 return TRUE;
5608 /*****************************************************************************
5609 * EnumPrinterDriversW [WINSPOOL.@]
5611 * see function EnumPrinterDrivers for RETURNS, BUGS
5613 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5614 LPBYTE pDriverInfo, DWORD cbBuf,
5615 LPDWORD pcbNeeded, LPDWORD pcReturned)
5617 static const WCHAR allW[] = {'a','l','l',0};
5618 BOOL ret;
5619 DWORD found;
5621 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5623 SetLastError(RPC_X_NULL_REF_POINTER);
5624 return FALSE;
5627 /* check for local drivers */
5628 if((pName) && (pName[0])) {
5629 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5630 SetLastError(ERROR_ACCESS_DENIED);
5631 return FALSE;
5634 /* check input parameter */
5635 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5636 SetLastError(ERROR_INVALID_LEVEL);
5637 return FALSE;
5640 if(pDriverInfo && cbBuf > 0)
5641 memset( pDriverInfo, 0, cbBuf);
5643 /* Exception: pull all printers */
5644 if (pEnvironment && !strcmpW(pEnvironment, allW))
5646 DWORD i, needed, bufsize = cbBuf;
5647 DWORD total_found = 0;
5648 DWORD data_offset;
5650 /* Precompute the overall total; we need this to know
5651 where pointers end and data begins (i.e. data_offset) */
5652 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
5654 needed = found = 0;
5655 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5656 NULL, 0, 0, &needed, &found, 0);
5657 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5658 total_found += found;
5661 data_offset = di_sizeof[Level] * total_found;
5663 *pcReturned = 0;
5664 *pcbNeeded = 0;
5665 total_found = 0;
5666 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
5668 needed = found = 0;
5669 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5670 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5671 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5672 else if (ret)
5673 *pcReturned += found;
5674 *pcbNeeded = needed;
5675 data_offset = needed;
5676 total_found += found;
5678 return ret;
5681 /* Normal behavior */
5682 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5683 0, cbBuf, pcbNeeded, &found, 0);
5684 if (ret)
5685 *pcReturned = found;
5687 return ret;
5690 /*****************************************************************************
5691 * EnumPrinterDriversA [WINSPOOL.@]
5693 * see function EnumPrinterDrivers for RETURNS, BUGS
5695 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5696 LPBYTE pDriverInfo, DWORD cbBuf,
5697 LPDWORD pcbNeeded, LPDWORD pcReturned)
5699 BOOL ret;
5700 UNICODE_STRING pNameW, pEnvironmentW;
5701 PWSTR pwstrNameW, pwstrEnvironmentW;
5702 LPBYTE buf = NULL;
5704 if (cbBuf)
5705 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5707 pwstrNameW = asciitounicode(&pNameW, pName);
5708 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5710 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5711 buf, cbBuf, pcbNeeded, pcReturned);
5712 if (ret)
5713 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5715 HeapFree(GetProcessHeap(), 0, buf);
5717 RtlFreeUnicodeString(&pNameW);
5718 RtlFreeUnicodeString(&pEnvironmentW);
5720 return ret;
5723 /******************************************************************************
5724 * EnumPortsA (WINSPOOL.@)
5726 * See EnumPortsW.
5729 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5730 LPDWORD pcbNeeded, LPDWORD pcReturned)
5732 BOOL res;
5733 LPBYTE bufferW = NULL;
5734 LPWSTR nameW = NULL;
5735 DWORD needed = 0;
5736 DWORD numentries = 0;
5737 INT len;
5739 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5740 cbBuf, pcbNeeded, pcReturned);
5742 /* convert servername to unicode */
5743 if (pName) {
5744 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5745 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5746 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5748 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5749 needed = cbBuf * sizeof(WCHAR);
5750 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5751 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5753 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5754 if (pcbNeeded) needed = *pcbNeeded;
5755 /* HeapReAlloc return NULL, when bufferW was NULL */
5756 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5757 HeapAlloc(GetProcessHeap(), 0, needed);
5759 /* Try again with the large Buffer */
5760 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5762 needed = pcbNeeded ? *pcbNeeded : 0;
5763 numentries = pcReturned ? *pcReturned : 0;
5766 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5767 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5769 if (res) {
5770 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5771 DWORD entrysize = 0;
5772 DWORD index;
5773 LPSTR ptr;
5774 LPPORT_INFO_2W pi2w;
5775 LPPORT_INFO_2A pi2a;
5777 needed = 0;
5778 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5780 /* First pass: calculate the size for all Entries */
5781 pi2w = (LPPORT_INFO_2W) bufferW;
5782 pi2a = (LPPORT_INFO_2A) pPorts;
5783 index = 0;
5784 while (index < numentries) {
5785 index++;
5786 needed += entrysize; /* PORT_INFO_?A */
5787 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5789 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5790 NULL, 0, NULL, NULL);
5791 if (Level > 1) {
5792 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5793 NULL, 0, NULL, NULL);
5794 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5795 NULL, 0, NULL, NULL);
5797 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5798 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5799 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5802 /* check for errors and quit on failure */
5803 if (cbBuf < needed) {
5804 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5805 res = FALSE;
5806 goto cleanup;
5808 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5809 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5810 cbBuf -= len ; /* free Bytes in the user-Buffer */
5811 pi2w = (LPPORT_INFO_2W) bufferW;
5812 pi2a = (LPPORT_INFO_2A) pPorts;
5813 index = 0;
5814 /* Second Pass: Fill the User Buffer (if we have one) */
5815 while ((index < numentries) && pPorts) {
5816 index++;
5817 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5818 pi2a->pPortName = ptr;
5819 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5820 ptr, cbBuf , NULL, NULL);
5821 ptr += len;
5822 cbBuf -= len;
5823 if (Level > 1) {
5824 pi2a->pMonitorName = ptr;
5825 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5826 ptr, cbBuf, NULL, NULL);
5827 ptr += len;
5828 cbBuf -= len;
5830 pi2a->pDescription = ptr;
5831 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5832 ptr, cbBuf, NULL, NULL);
5833 ptr += len;
5834 cbBuf -= len;
5836 pi2a->fPortType = pi2w->fPortType;
5837 pi2a->Reserved = 0; /* documented: "must be zero" */
5840 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5841 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5842 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5846 cleanup:
5847 if (pcbNeeded) *pcbNeeded = needed;
5848 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5850 HeapFree(GetProcessHeap(), 0, nameW);
5851 HeapFree(GetProcessHeap(), 0, bufferW);
5853 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5854 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5856 return (res);
5860 /******************************************************************************
5861 * EnumPortsW (WINSPOOL.@)
5863 * Enumerate available Ports
5865 * PARAMS
5866 * pName [I] Servername or NULL (local Computer)
5867 * Level [I] Structure-Level (1 or 2)
5868 * pPorts [O] PTR to Buffer that receives the Result
5869 * cbBuf [I] Size of Buffer at pPorts
5870 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5871 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5873 * RETURNS
5874 * Success: TRUE
5875 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5878 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5881 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5882 cbBuf, pcbNeeded, pcReturned);
5884 if ((backend == NULL) && !load_backend()) return FALSE;
5886 /* Level is not checked in win9x */
5887 if (!Level || (Level > 2)) {
5888 WARN("level (%d) is ignored in win9x\n", Level);
5889 SetLastError(ERROR_INVALID_LEVEL);
5890 return FALSE;
5892 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5893 SetLastError(RPC_X_NULL_REF_POINTER);
5894 return FALSE;
5897 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5900 /******************************************************************************
5901 * GetDefaultPrinterW (WINSPOOL.@)
5903 * FIXME
5904 * This function must read the value from data 'device' of key
5905 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5907 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5909 BOOL retval = TRUE;
5910 DWORD insize, len;
5911 WCHAR *buffer, *ptr;
5913 if (!namesize)
5915 SetLastError(ERROR_INVALID_PARAMETER);
5916 return FALSE;
5919 /* make the buffer big enough for the stuff from the profile/registry,
5920 * the content must fit into the local buffer to compute the correct
5921 * size even if the extern buffer is too small or not given.
5922 * (20 for ,driver,port) */
5923 insize = *namesize;
5924 len = max(100, (insize + 20));
5925 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5927 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5929 SetLastError (ERROR_FILE_NOT_FOUND);
5930 retval = FALSE;
5931 goto end;
5933 TRACE("%s\n", debugstr_w(buffer));
5935 if ((ptr = strchrW(buffer, ',')) == NULL)
5937 SetLastError(ERROR_INVALID_NAME);
5938 retval = FALSE;
5939 goto end;
5942 *ptr = 0;
5943 *namesize = strlenW(buffer) + 1;
5944 if(!name || (*namesize > insize))
5946 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5947 retval = FALSE;
5948 goto end;
5950 strcpyW(name, buffer);
5952 end:
5953 HeapFree( GetProcessHeap(), 0, buffer);
5954 return retval;
5958 /******************************************************************************
5959 * GetDefaultPrinterA (WINSPOOL.@)
5961 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5963 BOOL retval = TRUE;
5964 DWORD insize = 0;
5965 WCHAR *bufferW = NULL;
5967 if (!namesize)
5969 SetLastError(ERROR_INVALID_PARAMETER);
5970 return FALSE;
5973 if(name && *namesize) {
5974 insize = *namesize;
5975 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5978 if(!GetDefaultPrinterW( bufferW, namesize)) {
5979 retval = FALSE;
5980 goto end;
5983 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5984 NULL, NULL);
5985 if (!*namesize)
5987 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5988 retval = FALSE;
5990 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5992 end:
5993 HeapFree( GetProcessHeap(), 0, bufferW);
5994 return retval;
5998 /******************************************************************************
5999 * SetDefaultPrinterW (WINSPOOL.204)
6001 * Set the Name of the Default Printer
6003 * PARAMS
6004 * pszPrinter [I] Name of the Printer or NULL
6006 * RETURNS
6007 * Success: True
6008 * Failure: FALSE
6010 * NOTES
6011 * When the Parameter is NULL or points to an Empty String and
6012 * a Default Printer was already present, then this Function changes nothing.
6013 * Without a Default Printer and NULL (or an Empty String) as Parameter,
6014 * the First enumerated local Printer is used.
6017 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
6019 WCHAR default_printer[MAX_PATH];
6020 LPWSTR buffer = NULL;
6021 HKEY hreg;
6022 DWORD size;
6023 DWORD namelen;
6024 LONG lres;
6026 TRACE("(%s)\n", debugstr_w(pszPrinter));
6027 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
6029 default_printer[0] = '\0';
6030 size = ARRAY_SIZE(default_printer);
6032 /* if we have a default Printer, do nothing. */
6033 if (GetDefaultPrinterW(default_printer, &size))
6034 return TRUE;
6036 pszPrinter = NULL;
6037 /* we have no default Printer: search local Printers and use the first */
6038 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
6040 default_printer[0] = '\0';
6041 size = ARRAY_SIZE(default_printer);
6042 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
6044 pszPrinter = default_printer;
6045 TRACE("using %s\n", debugstr_w(pszPrinter));
6047 RegCloseKey(hreg);
6050 if (pszPrinter == NULL) {
6051 TRACE("no local printer found\n");
6052 SetLastError(ERROR_FILE_NOT_FOUND);
6053 return FALSE;
6057 /* "pszPrinter" is never empty or NULL here. */
6058 namelen = lstrlenW(pszPrinter);
6059 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
6060 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
6061 if (!buffer ||
6062 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
6063 HeapFree(GetProcessHeap(), 0, buffer);
6064 SetLastError(ERROR_FILE_NOT_FOUND);
6065 return FALSE;
6068 /* read the devices entry for the printer (driver,port) to build the string for the
6069 default device entry (printer,driver,port) */
6070 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
6071 buffer[namelen] = ',';
6072 namelen++; /* move index to the start of the driver */
6074 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
6075 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
6076 if (!lres) {
6077 TRACE("set device to %s\n", debugstr_w(buffer));
6079 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
6080 TRACE("failed to set the device entry: %d\n", GetLastError());
6081 lres = ERROR_INVALID_PRINTER_NAME;
6084 /* remove the next section, when INIFileMapping is implemented */
6086 HKEY hdev;
6087 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
6088 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6089 RegCloseKey(hdev);
6093 else
6095 if (lres != ERROR_FILE_NOT_FOUND)
6096 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6098 SetLastError(ERROR_INVALID_PRINTER_NAME);
6101 RegCloseKey(hreg);
6102 HeapFree(GetProcessHeap(), 0, buffer);
6103 return (lres == ERROR_SUCCESS);
6106 /******************************************************************************
6107 * SetDefaultPrinterA (WINSPOOL.202)
6109 * See SetDefaultPrinterW.
6112 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6114 LPWSTR bufferW = NULL;
6115 BOOL res;
6117 TRACE("(%s)\n", debugstr_a(pszPrinter));
6118 if(pszPrinter) {
6119 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6120 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6121 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6123 res = SetDefaultPrinterW(bufferW);
6124 HeapFree(GetProcessHeap(), 0, bufferW);
6125 return res;
6128 /******************************************************************************
6129 * SetPrinterDataExA (WINSPOOL.@)
6131 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6132 LPCSTR pValueName, DWORD Type,
6133 LPBYTE pData, DWORD cbData)
6135 HKEY hkeyPrinter, hkeySubkey;
6136 DWORD ret;
6138 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6139 debugstr_a(pValueName), Type, pData, cbData);
6141 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6142 != ERROR_SUCCESS)
6143 return ret;
6145 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6146 != ERROR_SUCCESS) {
6147 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6148 RegCloseKey(hkeyPrinter);
6149 return ret;
6151 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6152 RegCloseKey(hkeySubkey);
6153 RegCloseKey(hkeyPrinter);
6154 return ret;
6157 /******************************************************************************
6158 * SetPrinterDataExW (WINSPOOL.@)
6160 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6161 LPCWSTR pValueName, DWORD Type,
6162 LPBYTE pData, DWORD cbData)
6164 HKEY hkeyPrinter, hkeySubkey;
6165 DWORD ret;
6167 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6168 debugstr_w(pValueName), Type, pData, cbData);
6170 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6171 != ERROR_SUCCESS)
6172 return ret;
6174 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6175 != ERROR_SUCCESS) {
6176 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6177 RegCloseKey(hkeyPrinter);
6178 return ret;
6180 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6181 RegCloseKey(hkeySubkey);
6182 RegCloseKey(hkeyPrinter);
6183 return ret;
6186 /******************************************************************************
6187 * SetPrinterDataA (WINSPOOL.@)
6189 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6190 LPBYTE pData, DWORD cbData)
6192 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6193 pData, cbData);
6196 /******************************************************************************
6197 * SetPrinterDataW (WINSPOOL.@)
6199 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6200 LPBYTE pData, DWORD cbData)
6202 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6203 pData, cbData);
6206 /******************************************************************************
6207 * GetPrinterDataExA (WINSPOOL.@)
6209 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6210 LPCSTR pValueName, LPDWORD pType,
6211 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6213 opened_printer_t *printer;
6214 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6215 DWORD ret;
6217 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6218 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6220 printer = get_opened_printer(hPrinter);
6221 if(!printer) return ERROR_INVALID_HANDLE;
6223 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6224 if (ret) return ret;
6226 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6228 if (printer->name) {
6230 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6231 if (ret) {
6232 RegCloseKey(hkeyPrinters);
6233 return ret;
6235 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6236 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6237 RegCloseKey(hkeyPrinter);
6238 RegCloseKey(hkeyPrinters);
6239 return ret;
6242 *pcbNeeded = nSize;
6243 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6244 0, pType, pData, pcbNeeded);
6246 if (!ret && !pData) ret = ERROR_MORE_DATA;
6248 RegCloseKey(hkeySubkey);
6249 RegCloseKey(hkeyPrinter);
6250 RegCloseKey(hkeyPrinters);
6252 TRACE("--> %d\n", ret);
6253 return ret;
6256 /******************************************************************************
6257 * GetPrinterDataExW (WINSPOOL.@)
6259 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6260 LPCWSTR pValueName, LPDWORD pType,
6261 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6263 opened_printer_t *printer;
6264 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6265 DWORD ret;
6267 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6268 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6270 printer = get_opened_printer(hPrinter);
6271 if(!printer) return ERROR_INVALID_HANDLE;
6273 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6274 if (ret) return ret;
6276 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6278 if (printer->name) {
6280 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6281 if (ret) {
6282 RegCloseKey(hkeyPrinters);
6283 return ret;
6285 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6286 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6287 RegCloseKey(hkeyPrinter);
6288 RegCloseKey(hkeyPrinters);
6289 return ret;
6292 *pcbNeeded = nSize;
6293 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6294 0, pType, pData, pcbNeeded);
6296 if (!ret && !pData) ret = ERROR_MORE_DATA;
6298 RegCloseKey(hkeySubkey);
6299 RegCloseKey(hkeyPrinter);
6300 RegCloseKey(hkeyPrinters);
6302 TRACE("--> %d\n", ret);
6303 return ret;
6306 /******************************************************************************
6307 * GetPrinterDataA (WINSPOOL.@)
6309 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6310 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6312 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6313 pData, nSize, pcbNeeded);
6316 /******************************************************************************
6317 * GetPrinterDataW (WINSPOOL.@)
6319 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6320 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6322 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6323 pData, nSize, pcbNeeded);
6326 /*******************************************************************************
6327 * EnumPrinterDataExW [WINSPOOL.@]
6329 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6330 LPBYTE pEnumValues, DWORD cbEnumValues,
6331 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6333 HKEY hkPrinter, hkSubKey;
6334 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6335 cbValueNameLen, cbMaxValueLen, cbValueLen,
6336 cbBufSize, dwType;
6337 LPWSTR lpValueName;
6338 HANDLE hHeap;
6339 PBYTE lpValue;
6340 PPRINTER_ENUM_VALUESW ppev;
6342 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6344 if (pKeyName == NULL || *pKeyName == 0)
6345 return ERROR_INVALID_PARAMETER;
6347 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6348 if (ret != ERROR_SUCCESS)
6350 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6351 hPrinter, ret);
6352 return ret;
6355 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6356 if (ret != ERROR_SUCCESS)
6358 r = RegCloseKey (hkPrinter);
6359 if (r != ERROR_SUCCESS)
6360 WARN ("RegCloseKey returned %i\n", r);
6361 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6362 debugstr_w (pKeyName), ret);
6363 return ret;
6366 ret = RegCloseKey (hkPrinter);
6367 if (ret != ERROR_SUCCESS)
6369 ERR ("RegCloseKey returned %i\n", ret);
6370 r = RegCloseKey (hkSubKey);
6371 if (r != ERROR_SUCCESS)
6372 WARN ("RegCloseKey returned %i\n", r);
6373 return ret;
6376 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6377 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6378 if (ret != ERROR_SUCCESS)
6380 r = RegCloseKey (hkSubKey);
6381 if (r != ERROR_SUCCESS)
6382 WARN ("RegCloseKey returned %i\n", r);
6383 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6384 return ret;
6387 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6388 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6390 if (cValues == 0) /* empty key */
6392 r = RegCloseKey (hkSubKey);
6393 if (r != ERROR_SUCCESS)
6394 WARN ("RegCloseKey returned %i\n", r);
6395 *pcbEnumValues = *pnEnumValues = 0;
6396 return ERROR_SUCCESS;
6399 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6401 hHeap = GetProcessHeap ();
6402 if (hHeap == NULL)
6404 ERR ("GetProcessHeap failed\n");
6405 r = RegCloseKey (hkSubKey);
6406 if (r != ERROR_SUCCESS)
6407 WARN ("RegCloseKey returned %i\n", r);
6408 return ERROR_OUTOFMEMORY;
6411 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6412 if (lpValueName == NULL)
6414 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6415 r = RegCloseKey (hkSubKey);
6416 if (r != ERROR_SUCCESS)
6417 WARN ("RegCloseKey returned %i\n", r);
6418 return ERROR_OUTOFMEMORY;
6421 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6422 if (lpValue == NULL)
6424 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6425 if (HeapFree (hHeap, 0, lpValueName) == 0)
6426 WARN ("HeapFree failed with code %i\n", GetLastError ());
6427 r = RegCloseKey (hkSubKey);
6428 if (r != ERROR_SUCCESS)
6429 WARN ("RegCloseKey returned %i\n", r);
6430 return ERROR_OUTOFMEMORY;
6433 TRACE ("pass 1: calculating buffer required for all names and values\n");
6435 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6437 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6439 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6441 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6442 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6443 NULL, NULL, lpValue, &cbValueLen);
6444 if (ret != ERROR_SUCCESS)
6446 if (HeapFree (hHeap, 0, lpValue) == 0)
6447 WARN ("HeapFree failed with code %i\n", GetLastError ());
6448 if (HeapFree (hHeap, 0, lpValueName) == 0)
6449 WARN ("HeapFree failed with code %i\n", GetLastError ());
6450 r = RegCloseKey (hkSubKey);
6451 if (r != ERROR_SUCCESS)
6452 WARN ("RegCloseKey returned %i\n", r);
6453 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6454 return ret;
6457 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6458 debugstr_w (lpValueName), dwIndex,
6459 cbValueNameLen + 1, cbValueLen);
6461 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6462 cbBufSize += cbValueLen;
6465 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6467 *pcbEnumValues = cbBufSize;
6468 *pnEnumValues = cValues;
6470 if (cbEnumValues < cbBufSize) /* buffer too small */
6472 if (HeapFree (hHeap, 0, lpValue) == 0)
6473 WARN ("HeapFree failed with code %i\n", GetLastError ());
6474 if (HeapFree (hHeap, 0, lpValueName) == 0)
6475 WARN ("HeapFree failed with code %i\n", GetLastError ());
6476 r = RegCloseKey (hkSubKey);
6477 if (r != ERROR_SUCCESS)
6478 WARN ("RegCloseKey returned %i\n", r);
6479 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6480 return ERROR_MORE_DATA;
6483 TRACE ("pass 2: copying all names and values to buffer\n");
6485 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6486 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6488 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6490 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6491 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6492 NULL, &dwType, lpValue, &cbValueLen);
6493 if (ret != ERROR_SUCCESS)
6495 if (HeapFree (hHeap, 0, lpValue) == 0)
6496 WARN ("HeapFree failed with code %i\n", GetLastError ());
6497 if (HeapFree (hHeap, 0, lpValueName) == 0)
6498 WARN ("HeapFree failed with code %i\n", GetLastError ());
6499 r = RegCloseKey (hkSubKey);
6500 if (r != ERROR_SUCCESS)
6501 WARN ("RegCloseKey returned %i\n", r);
6502 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6503 return ret;
6506 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6507 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6508 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6509 pEnumValues += cbValueNameLen;
6511 /* return # of *bytes* (including trailing \0), not # of chars */
6512 ppev[dwIndex].cbValueName = cbValueNameLen;
6514 ppev[dwIndex].dwType = dwType;
6516 memcpy (pEnumValues, lpValue, cbValueLen);
6517 ppev[dwIndex].pData = pEnumValues;
6518 pEnumValues += cbValueLen;
6520 ppev[dwIndex].cbData = cbValueLen;
6522 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6523 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6526 if (HeapFree (hHeap, 0, lpValue) == 0)
6528 ret = GetLastError ();
6529 ERR ("HeapFree failed with code %i\n", ret);
6530 if (HeapFree (hHeap, 0, lpValueName) == 0)
6531 WARN ("HeapFree failed with code %i\n", GetLastError ());
6532 r = RegCloseKey (hkSubKey);
6533 if (r != ERROR_SUCCESS)
6534 WARN ("RegCloseKey returned %i\n", r);
6535 return ret;
6538 if (HeapFree (hHeap, 0, lpValueName) == 0)
6540 ret = GetLastError ();
6541 ERR ("HeapFree failed with code %i\n", ret);
6542 r = RegCloseKey (hkSubKey);
6543 if (r != ERROR_SUCCESS)
6544 WARN ("RegCloseKey returned %i\n", r);
6545 return ret;
6548 ret = RegCloseKey (hkSubKey);
6549 if (ret != ERROR_SUCCESS)
6551 ERR ("RegCloseKey returned %i\n", ret);
6552 return ret;
6555 return ERROR_SUCCESS;
6558 /*******************************************************************************
6559 * EnumPrinterDataExA [WINSPOOL.@]
6561 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6562 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6563 * what Windows 2000 SP1 does.
6566 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6567 LPBYTE pEnumValues, DWORD cbEnumValues,
6568 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6570 INT len;
6571 LPWSTR pKeyNameW;
6572 DWORD ret, dwIndex, dwBufSize;
6573 HANDLE hHeap;
6574 LPSTR pBuffer;
6576 TRACE ("%p %s\n", hPrinter, pKeyName);
6578 if (pKeyName == NULL || *pKeyName == 0)
6579 return ERROR_INVALID_PARAMETER;
6581 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6582 if (len == 0)
6584 ret = GetLastError ();
6585 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6586 return ret;
6589 hHeap = GetProcessHeap ();
6590 if (hHeap == NULL)
6592 ERR ("GetProcessHeap failed\n");
6593 return ERROR_OUTOFMEMORY;
6596 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6597 if (pKeyNameW == NULL)
6599 ERR ("Failed to allocate %i bytes from process heap\n",
6600 (LONG)(len * sizeof (WCHAR)));
6601 return ERROR_OUTOFMEMORY;
6604 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6606 ret = GetLastError ();
6607 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6608 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6609 WARN ("HeapFree failed with code %i\n", GetLastError ());
6610 return ret;
6613 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6614 pcbEnumValues, pnEnumValues);
6615 if (ret != ERROR_SUCCESS)
6617 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6618 WARN ("HeapFree failed with code %i\n", GetLastError ());
6619 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6620 return ret;
6623 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6625 ret = GetLastError ();
6626 ERR ("HeapFree failed with code %i\n", ret);
6627 return ret;
6630 if (*pnEnumValues == 0) /* empty key */
6631 return ERROR_SUCCESS;
6633 dwBufSize = 0;
6634 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6636 PPRINTER_ENUM_VALUESW ppev =
6637 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6639 if (dwBufSize < ppev->cbValueName)
6640 dwBufSize = ppev->cbValueName;
6642 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6643 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6644 dwBufSize = ppev->cbData;
6647 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6649 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6650 if (pBuffer == NULL)
6652 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6653 return ERROR_OUTOFMEMORY;
6656 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6658 PPRINTER_ENUM_VALUESW ppev =
6659 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6661 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6662 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6663 NULL);
6664 if (len == 0)
6666 ret = GetLastError ();
6667 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6668 if (HeapFree (hHeap, 0, pBuffer) == 0)
6669 WARN ("HeapFree failed with code %i\n", GetLastError ());
6670 return ret;
6673 memcpy (ppev->pValueName, pBuffer, len);
6675 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6677 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6678 ppev->dwType != REG_MULTI_SZ)
6679 continue;
6681 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6682 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6683 if (len == 0)
6685 ret = GetLastError ();
6686 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6687 if (HeapFree (hHeap, 0, pBuffer) == 0)
6688 WARN ("HeapFree failed with code %i\n", GetLastError ());
6689 return ret;
6692 memcpy (ppev->pData, pBuffer, len);
6694 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6695 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6698 if (HeapFree (hHeap, 0, pBuffer) == 0)
6700 ret = GetLastError ();
6701 ERR ("HeapFree failed with code %i\n", ret);
6702 return ret;
6705 return ERROR_SUCCESS;
6708 /******************************************************************************
6709 * AbortPrinter (WINSPOOL.@)
6711 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6713 FIXME("(%p), stub!\n", hPrinter);
6714 return TRUE;
6717 /******************************************************************************
6718 * AddPortA (WINSPOOL.@)
6720 * See AddPortW.
6723 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6725 LPWSTR nameW = NULL;
6726 LPWSTR monitorW = NULL;
6727 DWORD len;
6728 BOOL res;
6730 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6732 if (pName) {
6733 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6734 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6735 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6738 if (pMonitorName) {
6739 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6740 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6741 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6743 res = AddPortW(nameW, hWnd, monitorW);
6744 HeapFree(GetProcessHeap(), 0, nameW);
6745 HeapFree(GetProcessHeap(), 0, monitorW);
6746 return res;
6749 /******************************************************************************
6750 * AddPortW (WINSPOOL.@)
6752 * Add a Port for a specific Monitor
6754 * PARAMS
6755 * pName [I] Servername or NULL (local Computer)
6756 * hWnd [I] Handle to parent Window for the Dialog-Box
6757 * pMonitorName [I] Name of the Monitor that manage the Port
6759 * RETURNS
6760 * Success: TRUE
6761 * Failure: FALSE
6764 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6766 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6768 if ((backend == NULL) && !load_backend()) return FALSE;
6770 if (!pMonitorName) {
6771 SetLastError(RPC_X_NULL_REF_POINTER);
6772 return FALSE;
6775 return backend->fpAddPort(pName, hWnd, pMonitorName);
6778 /******************************************************************************
6779 * AddPortExA (WINSPOOL.@)
6781 * See AddPortExW.
6784 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6786 PORT_INFO_2W pi2W;
6787 PORT_INFO_2A * pi2A;
6788 LPWSTR nameW = NULL;
6789 LPWSTR monitorW = NULL;
6790 DWORD len;
6791 BOOL res;
6793 pi2A = (PORT_INFO_2A *) pBuffer;
6795 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6796 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6798 if ((level < 1) || (level > 2)) {
6799 SetLastError(ERROR_INVALID_LEVEL);
6800 return FALSE;
6803 if (!pi2A) {
6804 SetLastError(ERROR_INVALID_PARAMETER);
6805 return FALSE;
6808 if (pName) {
6809 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6810 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6811 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6814 if (pMonitorName) {
6815 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6816 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6817 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6820 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6822 if (pi2A->pPortName) {
6823 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6824 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6825 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6828 if (level > 1) {
6829 if (pi2A->pMonitorName) {
6830 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6831 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6832 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6835 if (pi2A->pDescription) {
6836 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6837 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6838 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6840 pi2W.fPortType = pi2A->fPortType;
6841 pi2W.Reserved = pi2A->Reserved;
6844 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6846 HeapFree(GetProcessHeap(), 0, nameW);
6847 HeapFree(GetProcessHeap(), 0, monitorW);
6848 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6849 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6850 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6851 return res;
6855 /******************************************************************************
6856 * AddPortExW (WINSPOOL.@)
6858 * Add a Port for a specific Monitor, without presenting a user interface
6860 * PARAMS
6861 * pName [I] Servername or NULL (local Computer)
6862 * level [I] Structure-Level (1 or 2) for pBuffer
6863 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6864 * pMonitorName [I] Name of the Monitor that manage the Port
6866 * RETURNS
6867 * Success: TRUE
6868 * Failure: FALSE
6871 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6873 PORT_INFO_2W * pi2;
6875 pi2 = (PORT_INFO_2W *) pBuffer;
6877 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6878 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6879 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6880 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6882 if ((backend == NULL) && !load_backend()) return FALSE;
6884 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6885 SetLastError(ERROR_INVALID_PARAMETER);
6886 return FALSE;
6889 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6892 /******************************************************************************
6893 * AddPrinterConnectionA (WINSPOOL.@)
6895 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6897 FIXME("%s\n", debugstr_a(pName));
6898 return FALSE;
6901 /******************************************************************************
6902 * AddPrinterConnectionW (WINSPOOL.@)
6904 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6906 FIXME("%s\n", debugstr_w(pName));
6907 return FALSE;
6910 /******************************************************************************
6911 * AddPrinterDriverExW (WINSPOOL.@)
6913 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6915 * PARAMS
6916 * pName [I] Servername or NULL (local Computer)
6917 * level [I] Level for the supplied DRIVER_INFO_*W struct
6918 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6919 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6921 * RESULTS
6922 * Success: TRUE
6923 * Failure: FALSE
6926 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6928 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6930 if ((backend == NULL) && !load_backend()) return FALSE;
6932 if (level < 2 || level == 5 || level == 7 || level > 8) {
6933 SetLastError(ERROR_INVALID_LEVEL);
6934 return FALSE;
6937 if (!pDriverInfo) {
6938 SetLastError(ERROR_INVALID_PARAMETER);
6939 return FALSE;
6942 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6945 /******************************************************************************
6946 * AddPrinterDriverExA (WINSPOOL.@)
6948 * See AddPrinterDriverExW.
6951 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6953 DRIVER_INFO_8A *diA;
6954 DRIVER_INFO_8W diW;
6955 LPWSTR nameW = NULL;
6956 DWORD lenA;
6957 DWORD len;
6958 BOOL res = FALSE;
6960 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6962 diA = (DRIVER_INFO_8A *) pDriverInfo;
6963 ZeroMemory(&diW, sizeof(diW));
6965 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6966 SetLastError(ERROR_INVALID_LEVEL);
6967 return FALSE;
6970 if (diA == NULL) {
6971 SetLastError(ERROR_INVALID_PARAMETER);
6972 return FALSE;
6975 /* convert servername to unicode */
6976 if (pName) {
6977 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6978 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6979 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6982 /* common fields */
6983 diW.cVersion = diA->cVersion;
6985 if (diA->pName) {
6986 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6987 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6988 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6991 if (diA->pEnvironment) {
6992 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6993 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6994 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6997 if (diA->pDriverPath) {
6998 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6999 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7000 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
7003 if (diA->pDataFile) {
7004 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
7005 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7006 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
7009 if (diA->pConfigFile) {
7010 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
7011 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7012 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
7015 if ((Level > 2) && diA->pHelpFile) {
7016 len = MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, NULL, 0);
7017 diW.pHelpFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7018 MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, diW.pHelpFile, len);
7021 if ((Level > 2) && diA->pDependentFiles) {
7022 lenA = multi_sz_lenA(diA->pDependentFiles);
7023 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
7024 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7025 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
7028 if ((Level > 2) && diA->pMonitorName) {
7029 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
7030 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7031 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
7034 if ((Level > 2) && diA->pDefaultDataType) {
7035 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
7036 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7037 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
7040 if ((Level > 3) && diA->pszzPreviousNames) {
7041 lenA = multi_sz_lenA(diA->pszzPreviousNames);
7042 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
7043 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7044 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
7047 if (Level > 5) {
7048 diW.ftDriverDate = diA->ftDriverDate;
7049 diW.dwlDriverVersion = diA->dwlDriverVersion;
7052 if ((Level > 5) && diA->pszMfgName) {
7053 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
7054 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7055 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
7058 if ((Level > 5) && diA->pszOEMUrl) {
7059 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
7060 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7061 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
7064 if ((Level > 5) && diA->pszHardwareID) {
7065 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
7066 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7067 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
7070 if ((Level > 5) && diA->pszProvider) {
7071 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
7072 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7073 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
7076 if ((Level > 7) && diA->pszPrintProcessor) {
7077 len = MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, NULL, 0);
7078 diW.pszPrintProcessor = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7079 MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, diW.pszPrintProcessor, len);
7082 if ((Level > 7) && diA->pszVendorSetup) {
7083 len = MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, NULL, 0);
7084 diW.pszVendorSetup = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7085 MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, diW.pszVendorSetup, len);
7088 if ((Level > 7) && diA->pszzColorProfiles) {
7089 lenA = multi_sz_lenA(diA->pszzColorProfiles);
7090 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, NULL, 0);
7091 diW.pszzColorProfiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7092 MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, diW.pszzColorProfiles, len);
7095 if ((Level > 7) && diA->pszInfPath) {
7096 len = MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, NULL, 0);
7097 diW.pszInfPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7098 MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, diW.pszInfPath, len);
7101 if ((Level > 7) && diA->pszzCoreDriverDependencies) {
7102 lenA = multi_sz_lenA(diA->pszzCoreDriverDependencies);
7103 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, NULL, 0);
7104 diW.pszzCoreDriverDependencies = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7105 MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, diW.pszzCoreDriverDependencies, len);
7108 if (Level > 7) {
7109 diW.dwPrinterDriverAttributes = diA->dwPrinterDriverAttributes;
7110 diW.ftMinInboxDriverVerDate = diA->ftMinInboxDriverVerDate;
7111 diW.dwlMinInboxDriverVerVersion = diA->dwlMinInboxDriverVerVersion;
7114 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
7115 TRACE("got %u with %u\n", res, GetLastError());
7116 HeapFree(GetProcessHeap(), 0, nameW);
7117 HeapFree(GetProcessHeap(), 0, diW.pName);
7118 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
7119 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
7120 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
7121 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
7122 HeapFree(GetProcessHeap(), 0, diW.pHelpFile);
7123 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
7124 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
7125 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
7126 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
7127 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
7128 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
7129 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
7130 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
7131 HeapFree(GetProcessHeap(), 0, diW.pszPrintProcessor);
7132 HeapFree(GetProcessHeap(), 0, diW.pszVendorSetup);
7133 HeapFree(GetProcessHeap(), 0, diW.pszzColorProfiles);
7134 HeapFree(GetProcessHeap(), 0, diW.pszInfPath);
7135 HeapFree(GetProcessHeap(), 0, diW.pszzCoreDriverDependencies);
7137 TRACE("=> %u with %u\n", res, GetLastError());
7138 return res;
7141 /******************************************************************************
7142 * ConfigurePortA (WINSPOOL.@)
7144 * See ConfigurePortW.
7147 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7149 LPWSTR nameW = NULL;
7150 LPWSTR portW = NULL;
7151 INT len;
7152 DWORD res;
7154 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7156 /* convert servername to unicode */
7157 if (pName) {
7158 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7159 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7160 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7163 /* convert portname to unicode */
7164 if (pPortName) {
7165 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7166 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7167 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7170 res = ConfigurePortW(nameW, hWnd, portW);
7171 HeapFree(GetProcessHeap(), 0, nameW);
7172 HeapFree(GetProcessHeap(), 0, portW);
7173 return res;
7176 /******************************************************************************
7177 * ConfigurePortW (WINSPOOL.@)
7179 * Display the Configuration-Dialog for a specific Port
7181 * PARAMS
7182 * pName [I] Servername or NULL (local Computer)
7183 * hWnd [I] Handle to parent Window for the Dialog-Box
7184 * pPortName [I] Name of the Port, that should be configured
7186 * RETURNS
7187 * Success: TRUE
7188 * Failure: FALSE
7191 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7194 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7196 if ((backend == NULL) && !load_backend()) return FALSE;
7198 if (!pPortName) {
7199 SetLastError(RPC_X_NULL_REF_POINTER);
7200 return FALSE;
7203 return backend->fpConfigurePort(pName, hWnd, pPortName);
7206 /******************************************************************************
7207 * ConnectToPrinterDlg (WINSPOOL.@)
7209 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7211 FIXME("%p %x\n", hWnd, Flags);
7212 return NULL;
7215 /******************************************************************************
7216 * DeletePrinterConnectionA (WINSPOOL.@)
7218 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7220 FIXME("%s\n", debugstr_a(pName));
7221 return TRUE;
7224 /******************************************************************************
7225 * DeletePrinterConnectionW (WINSPOOL.@)
7227 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7229 FIXME("%s\n", debugstr_w(pName));
7230 return TRUE;
7233 /******************************************************************************
7234 * DeletePrinterDriverExW (WINSPOOL.@)
7236 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7237 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7239 HKEY hkey_drivers;
7240 BOOL ret = FALSE;
7242 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7243 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7245 if(pName && pName[0])
7247 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7248 SetLastError(ERROR_INVALID_PARAMETER);
7249 return FALSE;
7252 if(dwDeleteFlag)
7254 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7255 SetLastError(ERROR_INVALID_PARAMETER);
7256 return FALSE;
7259 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7261 if(!hkey_drivers)
7263 ERR("Can't open drivers key\n");
7264 return FALSE;
7267 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7268 ret = TRUE;
7270 RegCloseKey(hkey_drivers);
7272 return ret;
7275 /******************************************************************************
7276 * DeletePrinterDriverExA (WINSPOOL.@)
7278 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7279 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7281 UNICODE_STRING NameW, EnvW, DriverW;
7282 BOOL ret;
7284 asciitounicode(&NameW, pName);
7285 asciitounicode(&EnvW, pEnvironment);
7286 asciitounicode(&DriverW, pDriverName);
7288 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7290 RtlFreeUnicodeString(&DriverW);
7291 RtlFreeUnicodeString(&EnvW);
7292 RtlFreeUnicodeString(&NameW);
7294 return ret;
7297 /******************************************************************************
7298 * DeletePrinterDataExW (WINSPOOL.@)
7300 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7301 LPCWSTR pValueName)
7303 FIXME("%p %s %s\n", hPrinter,
7304 debugstr_w(pKeyName), debugstr_w(pValueName));
7305 return ERROR_INVALID_PARAMETER;
7308 /******************************************************************************
7309 * DeletePrinterDataExA (WINSPOOL.@)
7311 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7312 LPCSTR pValueName)
7314 FIXME("%p %s %s\n", hPrinter,
7315 debugstr_a(pKeyName), debugstr_a(pValueName));
7316 return ERROR_INVALID_PARAMETER;
7319 /******************************************************************************
7320 * DeletePrintProcessorA (WINSPOOL.@)
7322 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7324 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7325 debugstr_a(pPrintProcessorName));
7326 return TRUE;
7329 /******************************************************************************
7330 * DeletePrintProcessorW (WINSPOOL.@)
7332 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7334 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7335 debugstr_w(pPrintProcessorName));
7336 return TRUE;
7339 /******************************************************************************
7340 * DeletePrintProvidorA (WINSPOOL.@)
7342 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7344 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7345 debugstr_a(pPrintProviderName));
7346 return TRUE;
7349 /******************************************************************************
7350 * DeletePrintProvidorW (WINSPOOL.@)
7352 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7354 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7355 debugstr_w(pPrintProviderName));
7356 return TRUE;
7359 /******************************************************************************
7360 * EnumFormsA (WINSPOOL.@)
7362 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7363 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7365 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7366 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7367 return FALSE;
7370 /******************************************************************************
7371 * EnumFormsW (WINSPOOL.@)
7373 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7374 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7376 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7377 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7378 return FALSE;
7381 /*****************************************************************************
7382 * EnumMonitorsA [WINSPOOL.@]
7384 * See EnumMonitorsW.
7387 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7388 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7390 BOOL res;
7391 LPBYTE bufferW = NULL;
7392 LPWSTR nameW = NULL;
7393 DWORD needed = 0;
7394 DWORD numentries = 0;
7395 INT len;
7397 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7398 cbBuf, pcbNeeded, pcReturned);
7400 /* convert servername to unicode */
7401 if (pName) {
7402 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7403 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7404 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7406 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7407 needed = cbBuf * sizeof(WCHAR);
7408 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7409 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7411 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7412 if (pcbNeeded) needed = *pcbNeeded;
7413 /* HeapReAlloc return NULL, when bufferW was NULL */
7414 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7415 HeapAlloc(GetProcessHeap(), 0, needed);
7417 /* Try again with the large Buffer */
7418 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7420 numentries = pcReturned ? *pcReturned : 0;
7421 needed = 0;
7423 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7424 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7426 if (res) {
7427 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7428 DWORD entrysize = 0;
7429 DWORD index;
7430 LPSTR ptr;
7431 LPMONITOR_INFO_2W mi2w;
7432 LPMONITOR_INFO_2A mi2a;
7434 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7435 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7437 /* First pass: calculate the size for all Entries */
7438 mi2w = (LPMONITOR_INFO_2W) bufferW;
7439 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7440 index = 0;
7441 while (index < numentries) {
7442 index++;
7443 needed += entrysize; /* MONITOR_INFO_?A */
7444 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7446 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7447 NULL, 0, NULL, NULL);
7448 if (Level > 1) {
7449 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7450 NULL, 0, NULL, NULL);
7451 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7452 NULL, 0, NULL, NULL);
7454 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7455 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7456 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7459 /* check for errors and quit on failure */
7460 if (cbBuf < needed) {
7461 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7462 res = FALSE;
7463 goto emA_cleanup;
7465 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7466 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7467 cbBuf -= len ; /* free Bytes in the user-Buffer */
7468 mi2w = (LPMONITOR_INFO_2W) bufferW;
7469 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7470 index = 0;
7471 /* Second Pass: Fill the User Buffer (if we have one) */
7472 while ((index < numentries) && pMonitors) {
7473 index++;
7474 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7475 mi2a->pName = ptr;
7476 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7477 ptr, cbBuf , NULL, NULL);
7478 ptr += len;
7479 cbBuf -= len;
7480 if (Level > 1) {
7481 mi2a->pEnvironment = ptr;
7482 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7483 ptr, cbBuf, NULL, NULL);
7484 ptr += len;
7485 cbBuf -= len;
7487 mi2a->pDLLName = ptr;
7488 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7489 ptr, cbBuf, NULL, NULL);
7490 ptr += len;
7491 cbBuf -= len;
7493 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7494 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7495 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7498 emA_cleanup:
7499 if (pcbNeeded) *pcbNeeded = needed;
7500 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7502 HeapFree(GetProcessHeap(), 0, nameW);
7503 HeapFree(GetProcessHeap(), 0, bufferW);
7505 TRACE("returning %d with %d (%d byte for %d entries)\n",
7506 (res), GetLastError(), needed, numentries);
7508 return (res);
7512 /*****************************************************************************
7513 * EnumMonitorsW [WINSPOOL.@]
7515 * Enumerate available Port-Monitors
7517 * PARAMS
7518 * pName [I] Servername or NULL (local Computer)
7519 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7520 * pMonitors [O] PTR to Buffer that receives the Result
7521 * cbBuf [I] Size of Buffer at pMonitors
7522 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7523 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7525 * RETURNS
7526 * Success: TRUE
7527 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7530 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7531 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7534 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7535 cbBuf, pcbNeeded, pcReturned);
7537 if ((backend == NULL) && !load_backend()) return FALSE;
7539 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7540 SetLastError(RPC_X_NULL_REF_POINTER);
7541 return FALSE;
7544 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7547 /******************************************************************************
7548 * SpoolerInit (WINSPOOL.@)
7550 * Initialize the Spooler
7552 * RETURNS
7553 * Success: TRUE
7554 * Failure: FALSE
7556 * NOTES
7557 * The function fails on windows, when the spooler service is not running
7560 BOOL WINAPI SpoolerInit(void)
7563 if ((backend == NULL) && !load_backend()) return FALSE;
7564 return TRUE;
7567 /******************************************************************************
7568 * XcvDataW (WINSPOOL.@)
7570 * Execute commands in the Printmonitor DLL
7572 * PARAMS
7573 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7574 * pszDataName [i] Name of the command to execute
7575 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7576 * cbInputData [i] Size in Bytes of Buffer at pInputData
7577 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7578 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7579 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7580 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7582 * RETURNS
7583 * Success: TRUE
7584 * Failure: FALSE
7586 * NOTES
7587 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7588 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7590 * Minimal List of commands, that a Printmonitor DLL should support:
7592 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7593 *| "AddPort" : Add a Port
7594 *| "DeletePort": Delete a Port
7596 * Many Printmonitors support additional commands. Examples for localspl.dll:
7597 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7598 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7601 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7602 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7603 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7605 opened_printer_t *printer;
7607 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7608 pInputData, cbInputData, pOutputData,
7609 cbOutputData, pcbOutputNeeded, pdwStatus);
7611 if ((backend == NULL) && !load_backend()) return FALSE;
7613 printer = get_opened_printer(hXcv);
7614 if (!printer || (!printer->backend_printer)) {
7615 SetLastError(ERROR_INVALID_HANDLE);
7616 return FALSE;
7619 if (!pcbOutputNeeded) {
7620 SetLastError(ERROR_INVALID_PARAMETER);
7621 return FALSE;
7624 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7625 SetLastError(RPC_X_NULL_REF_POINTER);
7626 return FALSE;
7629 *pcbOutputNeeded = 0;
7631 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7632 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7636 /*****************************************************************************
7637 * EnumPrinterDataA [WINSPOOL.@]
7640 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7641 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7642 DWORD cbData, LPDWORD pcbData )
7644 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7645 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7646 return ERROR_NO_MORE_ITEMS;
7649 /*****************************************************************************
7650 * EnumPrinterDataW [WINSPOOL.@]
7653 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7654 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7655 DWORD cbData, LPDWORD pcbData )
7657 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7658 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7659 return ERROR_NO_MORE_ITEMS;
7662 /*****************************************************************************
7663 * EnumPrinterKeyA [WINSPOOL.@]
7666 DWORD WINAPI EnumPrinterKeyA(HANDLE printer, const CHAR *key, CHAR *subkey, DWORD size, DWORD *needed)
7668 FIXME("%p %s %p %x %p\n", printer, debugstr_a(key), subkey, size, needed);
7669 return ERROR_CALL_NOT_IMPLEMENTED;
7672 /*****************************************************************************
7673 * EnumPrinterKeyW [WINSPOOL.@]
7676 DWORD WINAPI EnumPrinterKeyW(HANDLE printer, const WCHAR *key, WCHAR *subkey, DWORD size, DWORD *needed)
7678 FIXME("%p %s %p %x %p\n", printer, debugstr_w(key), subkey, size, needed);
7679 return ERROR_CALL_NOT_IMPLEMENTED;
7682 /*****************************************************************************
7683 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7686 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7687 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7688 LPDWORD pcbNeeded, LPDWORD pcReturned)
7690 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7691 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7692 pcbNeeded, pcReturned);
7693 return FALSE;
7696 /*****************************************************************************
7697 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7700 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7701 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7702 LPDWORD pcbNeeded, LPDWORD pcReturned)
7704 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7705 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7706 pcbNeeded, pcReturned);
7707 return FALSE;
7710 /*****************************************************************************
7711 * EnumPrintProcessorsA [WINSPOOL.@]
7713 * See EnumPrintProcessorsW.
7716 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7717 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7719 BOOL res;
7720 LPBYTE bufferW = NULL;
7721 LPWSTR nameW = NULL;
7722 LPWSTR envW = NULL;
7723 DWORD needed = 0;
7724 DWORD numentries = 0;
7725 INT len;
7727 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7728 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7730 /* convert names to unicode */
7731 if (pName) {
7732 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7733 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7734 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7736 if (pEnvironment) {
7737 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7738 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7739 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7742 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7743 needed = cbBuf * sizeof(WCHAR);
7744 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7745 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7747 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7748 if (pcbNeeded) needed = *pcbNeeded;
7749 /* HeapReAlloc return NULL, when bufferW was NULL */
7750 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7751 HeapAlloc(GetProcessHeap(), 0, needed);
7753 /* Try again with the large Buffer */
7754 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7756 numentries = pcReturned ? *pcReturned : 0;
7757 needed = 0;
7759 if (res) {
7760 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7761 DWORD index;
7762 LPSTR ptr;
7763 PPRINTPROCESSOR_INFO_1W ppiw;
7764 PPRINTPROCESSOR_INFO_1A ppia;
7766 /* First pass: calculate the size for all Entries */
7767 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7768 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7769 index = 0;
7770 while (index < numentries) {
7771 index++;
7772 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7773 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7775 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7776 NULL, 0, NULL, NULL);
7778 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7779 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7782 /* check for errors and quit on failure */
7783 if (cbBuf < needed) {
7784 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7785 res = FALSE;
7786 goto epp_cleanup;
7789 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7790 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7791 cbBuf -= len ; /* free Bytes in the user-Buffer */
7792 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7793 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7794 index = 0;
7795 /* Second Pass: Fill the User Buffer (if we have one) */
7796 while ((index < numentries) && pPPInfo) {
7797 index++;
7798 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7799 ppia->pName = ptr;
7800 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7801 ptr, cbBuf , NULL, NULL);
7802 ptr += len;
7803 cbBuf -= len;
7805 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7806 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7810 epp_cleanup:
7811 if (pcbNeeded) *pcbNeeded = needed;
7812 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7814 HeapFree(GetProcessHeap(), 0, nameW);
7815 HeapFree(GetProcessHeap(), 0, envW);
7816 HeapFree(GetProcessHeap(), 0, bufferW);
7818 TRACE("returning %d with %d (%d byte for %d entries)\n",
7819 (res), GetLastError(), needed, numentries);
7821 return (res);
7824 /*****************************************************************************
7825 * EnumPrintProcessorsW [WINSPOOL.@]
7827 * Enumerate available Print Processors
7829 * PARAMS
7830 * pName [I] Servername or NULL (local Computer)
7831 * pEnvironment [I] Printing-Environment or NULL (Default)
7832 * Level [I] Structure-Level (Only 1 is allowed)
7833 * pPPInfo [O] PTR to Buffer that receives the Result
7834 * cbBuf [I] Size of Buffer at pPPInfo
7835 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7836 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7838 * RETURNS
7839 * Success: TRUE
7840 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7843 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7844 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7847 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7848 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7850 if ((backend == NULL) && !load_backend()) return FALSE;
7852 if (!pcbNeeded || !pcReturned) {
7853 SetLastError(RPC_X_NULL_REF_POINTER);
7854 return FALSE;
7857 if (!pPPInfo && (cbBuf > 0)) {
7858 SetLastError(ERROR_INVALID_USER_BUFFER);
7859 return FALSE;
7862 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7863 cbBuf, pcbNeeded, pcReturned);
7866 /*****************************************************************************
7867 * ExtDeviceMode [WINSPOOL.@]
7870 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7871 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7872 DWORD fMode)
7874 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7875 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7876 debugstr_a(pProfile), fMode);
7877 return -1;
7880 /*****************************************************************************
7881 * FindClosePrinterChangeNotification [WINSPOOL.@]
7884 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7886 FIXME("Stub: %p\n", hChange);
7887 return TRUE;
7890 /*****************************************************************************
7891 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7894 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7895 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7897 FIXME("Stub: %p %x %x %p\n",
7898 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7899 return INVALID_HANDLE_VALUE;
7902 /*****************************************************************************
7903 * FindNextPrinterChangeNotification [WINSPOOL.@]
7906 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7907 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7909 FIXME("Stub: %p %p %p %p\n",
7910 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7911 return FALSE;
7914 /*****************************************************************************
7915 * FreePrinterNotifyInfo [WINSPOOL.@]
7918 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7920 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7921 return TRUE;
7924 /*****************************************************************************
7925 * string_to_buf
7927 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7928 * ansi depending on the unicode parameter.
7930 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7932 if(!str)
7934 *size = 0;
7935 return TRUE;
7938 if(unicode)
7940 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7941 if(*size <= cb)
7943 memcpy(ptr, str, *size);
7944 return TRUE;
7946 return FALSE;
7948 else
7950 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7951 if(*size <= cb)
7953 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7954 return TRUE;
7956 return FALSE;
7960 /*****************************************************************************
7961 * get_job_info_1
7963 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7964 LPDWORD pcbNeeded, BOOL unicode)
7966 DWORD size, left = cbBuf;
7967 BOOL space = (cbBuf > 0);
7968 LPBYTE ptr = buf;
7970 *pcbNeeded = 0;
7972 if(space)
7974 ji1->JobId = job->job_id;
7977 string_to_buf(job->document_title, ptr, left, &size, unicode);
7978 if(space && size <= left)
7980 ji1->pDocument = (LPWSTR)ptr;
7981 ptr += size;
7982 left -= size;
7984 else
7985 space = FALSE;
7986 *pcbNeeded += size;
7988 if (job->printer_name)
7990 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7991 if(space && size <= left)
7993 ji1->pPrinterName = (LPWSTR)ptr;
7994 ptr += size;
7995 left -= size;
7997 else
7998 space = FALSE;
7999 *pcbNeeded += size;
8002 return space;
8005 /*****************************************************************************
8006 * get_job_info_2
8008 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
8009 LPDWORD pcbNeeded, BOOL unicode)
8011 DWORD size, left = cbBuf;
8012 DWORD shift;
8013 BOOL space = (cbBuf > 0);
8014 LPBYTE ptr = buf;
8015 LPDEVMODEA dmA = NULL;
8016 LPDEVMODEW devmode;
8018 *pcbNeeded = 0;
8020 if(space)
8022 ji2->JobId = job->job_id;
8025 string_to_buf(job->document_title, ptr, left, &size, unicode);
8026 if(space && size <= left)
8028 ji2->pDocument = (LPWSTR)ptr;
8029 ptr += size;
8030 left -= size;
8032 else
8033 space = FALSE;
8034 *pcbNeeded += size;
8036 if (job->printer_name)
8038 string_to_buf(job->printer_name, ptr, left, &size, unicode);
8039 if(space && size <= left)
8041 ji2->pPrinterName = (LPWSTR)ptr;
8042 ptr += size;
8043 left -= size;
8045 else
8046 space = FALSE;
8047 *pcbNeeded += size;
8050 if (job->devmode)
8052 if (!unicode)
8054 dmA = DEVMODEdupWtoA(job->devmode);
8055 devmode = (LPDEVMODEW) dmA;
8056 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
8058 else
8060 devmode = job->devmode;
8061 size = devmode->dmSize + devmode->dmDriverExtra;
8064 if (!devmode)
8065 FIXME("Can't convert DEVMODE W to A\n");
8066 else
8068 /* align DEVMODE to a DWORD boundary */
8069 shift = (4 - (*pcbNeeded & 3)) & 3;
8070 size += shift;
8072 if (size <= left)
8074 ptr += shift;
8075 memcpy(ptr, devmode, size-shift);
8076 ji2->pDevMode = (LPDEVMODEW)ptr;
8077 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
8078 ptr += size-shift;
8079 left -= size;
8081 else
8082 space = FALSE;
8083 *pcbNeeded +=size;
8087 return space;
8090 /*****************************************************************************
8091 * get_job_info
8093 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8094 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
8096 BOOL ret = FALSE;
8097 DWORD needed = 0, size;
8098 job_t *job;
8099 LPBYTE ptr = pJob;
8101 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
8103 EnterCriticalSection(&printer_handles_cs);
8104 job = get_job(hPrinter, JobId);
8105 if(!job)
8106 goto end;
8108 switch(Level)
8110 case 1:
8111 size = sizeof(JOB_INFO_1W);
8112 if(cbBuf >= size)
8114 cbBuf -= size;
8115 ptr += size;
8116 memset(pJob, 0, size);
8118 else
8119 cbBuf = 0;
8120 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
8121 needed += size;
8122 break;
8124 case 2:
8125 size = sizeof(JOB_INFO_2W);
8126 if(cbBuf >= size)
8128 cbBuf -= size;
8129 ptr += size;
8130 memset(pJob, 0, size);
8132 else
8133 cbBuf = 0;
8134 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
8135 needed += size;
8136 break;
8138 case 3:
8139 size = sizeof(JOB_INFO_3);
8140 if(cbBuf >= size)
8142 cbBuf -= size;
8143 memset(pJob, 0, size);
8144 ret = TRUE;
8146 else
8147 cbBuf = 0;
8148 needed = size;
8149 break;
8151 default:
8152 SetLastError(ERROR_INVALID_LEVEL);
8153 goto end;
8155 if(pcbNeeded)
8156 *pcbNeeded = needed;
8157 end:
8158 LeaveCriticalSection(&printer_handles_cs);
8159 return ret;
8162 /*****************************************************************************
8163 * GetJobA [WINSPOOL.@]
8166 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8167 DWORD cbBuf, LPDWORD pcbNeeded)
8169 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8172 /*****************************************************************************
8173 * GetJobW [WINSPOOL.@]
8176 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8177 DWORD cbBuf, LPDWORD pcbNeeded)
8179 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8182 /*****************************************************************************
8183 * schedule_pipe
8185 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8187 #ifdef HAVE_FORK
8188 char *unixname, *cmdA;
8189 DWORD len;
8190 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8191 BOOL ret = FALSE;
8192 char buf[1024];
8193 pid_t pid, wret;
8194 int status;
8196 if(!(unixname = wine_get_unix_file_name(filename)))
8197 return FALSE;
8199 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8200 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8201 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8203 TRACE("printing with: %s\n", cmdA);
8205 if((file_fd = open(unixname, O_RDONLY)) == -1)
8206 goto end;
8208 if (pipe(fds))
8210 ERR("pipe() failed!\n");
8211 goto end;
8214 if ((pid = fork()) == 0)
8216 close(0);
8217 dup2(fds[0], 0);
8218 close(fds[1]);
8220 /* reset signals that we previously set to SIG_IGN */
8221 signal(SIGPIPE, SIG_DFL);
8223 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8224 _exit(1);
8226 else if (pid == -1)
8228 ERR("fork() failed!\n");
8229 goto end;
8232 close(fds[0]);
8233 fds[0] = -1;
8234 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8235 write(fds[1], buf, no_read);
8237 close(fds[1]);
8238 fds[1] = -1;
8240 /* reap child */
8241 do {
8242 wret = waitpid(pid, &status, 0);
8243 } while (wret < 0 && errno == EINTR);
8244 if (wret < 0)
8246 ERR("waitpid() failed!\n");
8247 goto end;
8249 if (!WIFEXITED(status) || WEXITSTATUS(status))
8251 ERR("child process failed! %d\n", status);
8252 goto end;
8255 ret = TRUE;
8257 end:
8258 if(file_fd != -1) close(file_fd);
8259 if(fds[0] != -1) close(fds[0]);
8260 if(fds[1] != -1) close(fds[1]);
8262 HeapFree(GetProcessHeap(), 0, cmdA);
8263 HeapFree(GetProcessHeap(), 0, unixname);
8264 return ret;
8265 #else
8266 return FALSE;
8267 #endif
8270 /*****************************************************************************
8271 * schedule_lpr
8273 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8275 static const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8276 WCHAR *cmd;
8277 BOOL r;
8279 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8280 sprintfW(cmd, fmtW, printer_name);
8282 r = schedule_pipe(cmd, filename);
8284 HeapFree(GetProcessHeap(), 0, cmd);
8285 return r;
8288 #ifdef SONAME_LIBCUPS
8289 /*****************************************************************************
8290 * get_cups_jobs_ticket_options
8292 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8293 * The CUPS scheduler only looks for these in Print-File requests, and since
8294 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8295 * parsed.
8297 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8299 FILE *fp = fopen( file, "r" );
8300 char buf[257]; /* DSC max of 256 + '\0' */
8301 const char *ps_adobe = "%!PS-Adobe-";
8302 const char *cups_job = "%cupsJobTicket:";
8304 if (!fp) return num_options;
8305 if (!fgets( buf, sizeof(buf), fp )) goto end;
8306 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8307 while (fgets( buf, sizeof(buf), fp ))
8309 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8310 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8313 end:
8314 fclose( fp );
8315 return num_options;
8318 static int get_cups_default_options( const char *printer, int num_options, cups_option_t **options )
8320 cups_dest_t *dest;
8321 int i;
8323 if (!pcupsGetNamedDest) return num_options;
8325 dest = pcupsGetNamedDest( NULL, printer, NULL );
8326 if (!dest) return num_options;
8328 for (i = 0; i < dest->num_options; i++)
8330 if (!pcupsGetOption( dest->options[i].name, num_options, *options ))
8331 num_options = pcupsAddOption( dest->options[i].name, dest->options[i].value,
8332 num_options, options );
8335 pcupsFreeDests( 1, dest );
8336 return num_options;
8338 #endif
8340 /*****************************************************************************
8341 * schedule_cups
8343 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8345 #ifdef SONAME_LIBCUPS
8346 if(pcupsPrintFile)
8348 char *unixname, *queue, *unix_doc_title;
8349 DWORD len;
8350 BOOL ret;
8351 int num_options = 0, i;
8352 cups_option_t *options = NULL;
8354 if(!(unixname = wine_get_unix_file_name(filename)))
8355 return FALSE;
8357 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8358 queue = HeapAlloc(GetProcessHeap(), 0, len);
8359 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8361 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8362 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8363 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8365 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8366 num_options = get_cups_default_options( queue, num_options, &options );
8368 TRACE( "printing via cups with options:\n" );
8369 for (i = 0; i < num_options; i++)
8370 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8372 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8373 if (ret == 0 && pcupsLastErrorString)
8374 WARN("cupsPrintFile failed with error %s\n", debugstr_a(pcupsLastErrorString()));
8376 pcupsFreeOptions( num_options, options );
8378 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8379 HeapFree(GetProcessHeap(), 0, queue);
8380 HeapFree(GetProcessHeap(), 0, unixname);
8381 return ret;
8383 else
8384 #endif
8386 return schedule_lpr(printer_name, filename);
8390 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8392 LPWSTR filename;
8394 switch(msg)
8396 case WM_INITDIALOG:
8397 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8398 return TRUE;
8400 case WM_COMMAND:
8401 if(HIWORD(wparam) == BN_CLICKED)
8403 if(LOWORD(wparam) == IDOK)
8405 HANDLE hf;
8406 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8407 LPWSTR *output;
8409 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8410 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8412 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8414 WCHAR caption[200], message[200];
8415 int mb_ret;
8417 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, ARRAY_SIZE(caption));
8418 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, ARRAY_SIZE(message));
8419 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8420 if(mb_ret == IDCANCEL)
8422 HeapFree(GetProcessHeap(), 0, filename);
8423 return TRUE;
8426 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8427 if(hf == INVALID_HANDLE_VALUE)
8429 WCHAR caption[200], message[200];
8431 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, ARRAY_SIZE(caption));
8432 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, ARRAY_SIZE(message));
8433 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8434 HeapFree(GetProcessHeap(), 0, filename);
8435 return TRUE;
8437 CloseHandle(hf);
8438 DeleteFileW(filename);
8439 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8440 *output = filename;
8441 EndDialog(hwnd, IDOK);
8442 return TRUE;
8444 if(LOWORD(wparam) == IDCANCEL)
8446 EndDialog(hwnd, IDCANCEL);
8447 return TRUE;
8450 return FALSE;
8452 return FALSE;
8455 /*****************************************************************************
8456 * get_filename
8458 static BOOL get_filename(LPWSTR *filename)
8460 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8461 file_dlg_proc, (LPARAM)filename) == IDOK;
8464 /*****************************************************************************
8465 * schedule_file
8467 static BOOL schedule_file(LPCWSTR filename)
8469 LPWSTR output = NULL;
8471 if(get_filename(&output))
8473 BOOL r;
8474 TRACE("copy to %s\n", debugstr_w(output));
8475 r = CopyFileW(filename, output, FALSE);
8476 HeapFree(GetProcessHeap(), 0, output);
8477 return r;
8479 return FALSE;
8482 /*****************************************************************************
8483 * schedule_unixfile
8485 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8487 int in_fd, out_fd, no_read;
8488 char buf[1024];
8489 BOOL ret = FALSE;
8490 char *unixname, *outputA;
8491 DWORD len;
8493 if(!(unixname = wine_get_unix_file_name(filename)))
8494 return FALSE;
8496 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8497 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8498 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8500 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8501 in_fd = open(unixname, O_RDONLY);
8502 if(out_fd == -1 || in_fd == -1)
8503 goto end;
8505 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8506 write(out_fd, buf, no_read);
8508 ret = TRUE;
8509 end:
8510 if(in_fd != -1) close(in_fd);
8511 if(out_fd != -1) close(out_fd);
8512 HeapFree(GetProcessHeap(), 0, outputA);
8513 HeapFree(GetProcessHeap(), 0, unixname);
8514 return ret;
8517 /*****************************************************************************
8518 * ScheduleJob [WINSPOOL.@]
8521 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8523 opened_printer_t *printer;
8524 BOOL ret = FALSE;
8525 struct list *cursor, *cursor2;
8527 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8528 EnterCriticalSection(&printer_handles_cs);
8529 printer = get_opened_printer(hPrinter);
8530 if(!printer)
8531 goto end;
8533 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8535 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8536 HANDLE hf;
8538 if(job->job_id != dwJobID) continue;
8540 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8541 if(hf != INVALID_HANDLE_VALUE)
8543 PRINTER_INFO_5W *pi5 = NULL;
8544 LPWSTR portname = job->portname;
8545 DWORD needed;
8546 HKEY hkey;
8547 WCHAR output[1024];
8548 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8549 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8551 if (!portname)
8553 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8554 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8555 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8556 portname = pi5->pPortName;
8558 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8559 debugstr_w(portname));
8561 output[0] = 0;
8563 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8564 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8566 DWORD type, count = sizeof(output);
8567 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8568 RegCloseKey(hkey);
8570 if(output[0] == '|')
8572 ret = schedule_pipe(output + 1, job->filename);
8574 else if(output[0])
8576 ret = schedule_unixfile(output, job->filename);
8578 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8580 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8582 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8584 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8586 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8588 ret = schedule_file(job->filename);
8590 else if(isalpha(portname[0]) && portname[1] == ':')
8592 TRACE("copying to %s\n", debugstr_w(portname));
8593 ret = CopyFileW(job->filename, portname, FALSE);
8595 else
8597 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8599 HeapFree(GetProcessHeap(), 0, pi5);
8600 CloseHandle(hf);
8601 DeleteFileW(job->filename);
8603 list_remove(cursor);
8604 HeapFree(GetProcessHeap(), 0, job->document_title);
8605 HeapFree(GetProcessHeap(), 0, job->printer_name);
8606 HeapFree(GetProcessHeap(), 0, job->portname);
8607 HeapFree(GetProcessHeap(), 0, job->filename);
8608 HeapFree(GetProcessHeap(), 0, job->devmode);
8609 HeapFree(GetProcessHeap(), 0, job);
8610 break;
8612 end:
8613 LeaveCriticalSection(&printer_handles_cs);
8614 return ret;
8617 /*****************************************************************************
8618 * StartDocDlgA [WINSPOOL.@]
8620 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8622 UNICODE_STRING usBuffer;
8623 DOCINFOW docW = { 0 };
8624 LPWSTR retW;
8625 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8626 LPSTR ret = NULL;
8628 docW.cbSize = sizeof(docW);
8629 if (doc->lpszDocName)
8631 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8632 if (!(docW.lpszDocName = docnameW)) goto failed;
8634 if (doc->lpszOutput)
8636 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8637 if (!(docW.lpszOutput = outputW)) goto failed;
8639 if (doc->lpszDatatype)
8641 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8642 if (!(docW.lpszDatatype = datatypeW)) goto failed;
8644 docW.fwType = doc->fwType;
8646 retW = StartDocDlgW(hPrinter, &docW);
8648 if(retW)
8650 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8651 ret = HeapAlloc(GetProcessHeap(), 0, len);
8652 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8653 HeapFree(GetProcessHeap(), 0, retW);
8656 failed:
8657 HeapFree(GetProcessHeap(), 0, datatypeW);
8658 HeapFree(GetProcessHeap(), 0, outputW);
8659 HeapFree(GetProcessHeap(), 0, docnameW);
8661 return ret;
8664 /*****************************************************************************
8665 * StartDocDlgW [WINSPOOL.@]
8667 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8668 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8669 * port is "FILE:". Also returns the full path if passed a relative path.
8671 * The caller should free the returned string from the process heap.
8673 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8675 LPWSTR ret = NULL;
8676 DWORD len, attr;
8678 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8680 PRINTER_INFO_5W *pi5;
8681 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8682 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8683 return NULL;
8684 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8685 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8686 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8688 HeapFree(GetProcessHeap(), 0, pi5);
8689 return NULL;
8691 HeapFree(GetProcessHeap(), 0, pi5);
8694 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8696 LPWSTR name;
8698 if (get_filename(&name))
8700 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8702 HeapFree(GetProcessHeap(), 0, name);
8703 return NULL;
8705 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8706 GetFullPathNameW(name, len, ret, NULL);
8707 HeapFree(GetProcessHeap(), 0, name);
8709 return ret;
8712 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8713 return NULL;
8715 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8716 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8718 attr = GetFileAttributesW(ret);
8719 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8721 HeapFree(GetProcessHeap(), 0, ret);
8722 ret = NULL;
8724 return ret;
8727 /*****************************************************************************
8728 * UploadPrinterDriverPackageA [WINSPOOL.@]
8730 HRESULT WINAPI UploadPrinterDriverPackageA( LPCSTR server, LPCSTR path, LPCSTR env,
8731 DWORD flags, HWND hwnd, LPSTR dst, PULONG dstlen )
8733 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server), debugstr_a(path), debugstr_a(env),
8734 flags, hwnd, dst, dstlen);
8735 return E_NOTIMPL;
8738 /*****************************************************************************
8739 * UploadPrinterDriverPackageW [WINSPOOL.@]
8741 HRESULT WINAPI UploadPrinterDriverPackageW( LPCWSTR server, LPCWSTR path, LPCWSTR env,
8742 DWORD flags, HWND hwnd, LPWSTR dst, PULONG dstlen )
8744 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server), debugstr_w(path), debugstr_w(env),
8745 flags, hwnd, dst, dstlen);
8746 return E_NOTIMPL;
8749 /*****************************************************************************
8750 * PerfOpen [WINSPOOL.@]
8752 DWORD WINAPI PerfOpen(LPWSTR context)
8754 FIXME("%s: stub\n", debugstr_w(context));
8755 return ERROR_SUCCESS;
8758 /*****************************************************************************
8759 * PerfClose [WINSPOOL.@]
8761 DWORD WINAPI PerfClose(void)
8763 FIXME("stub\n");
8764 return ERROR_SUCCESS;
8767 /*****************************************************************************
8768 * PerfCollect [WINSPOOL.@]
8770 DWORD WINAPI PerfCollect(LPWSTR query, LPVOID *data, LPDWORD size, LPDWORD obj_count)
8772 FIXME("%s, %p, %p, %p: stub\n", debugstr_w(query), data, size, obj_count);
8773 *size = 0;
8774 *obj_count = 0;
8775 return ERROR_SUCCESS;