server: Use server_get_file_info for all info classes not implemented on client side.
[wine.git] / dlls / winspool.drv / info.c
blob7c4ee9a26f2254ba2f74e50bda9bb50b4e26c9c8
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 #undef DPRINTF
106 #endif
108 #include "wine/library.h"
109 #include "windef.h"
110 #include "winbase.h"
111 #include "winuser.h"
112 #include "winerror.h"
113 #include "winreg.h"
114 #include "wingdi.h"
115 #include "winspool.h"
116 #include "winternl.h"
117 #include "wine/windef16.h"
118 #include "wine/unicode.h"
119 #include "wine/debug.h"
120 #include "wine/list.h"
121 #include "winnls.h"
123 #include "ddk/winsplp.h"
124 #include "wspool.h"
126 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
128 /* ############################### */
130 static CRITICAL_SECTION printer_handles_cs;
131 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
133 0, 0, &printer_handles_cs,
134 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
135 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
137 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
139 /* ############################### */
141 typedef struct {
142 DWORD job_id;
143 HANDLE hf;
144 } started_doc_t;
146 typedef struct {
147 struct list jobs;
148 LONG ref;
149 } jobqueue_t;
151 typedef struct {
152 LPWSTR name;
153 LPWSTR printername;
154 HANDLE backend_printer;
155 jobqueue_t *queue;
156 started_doc_t *doc;
157 DEVMODEW *devmode;
158 } opened_printer_t;
160 typedef struct {
161 struct list entry;
162 DWORD job_id;
163 WCHAR *filename;
164 WCHAR *portname;
165 WCHAR *document_title;
166 WCHAR *printer_name;
167 LPDEVMODEW devmode;
168 } job_t;
171 typedef struct {
172 LPCWSTR envname;
173 LPCWSTR subdir;
174 DWORD driverversion;
175 LPCWSTR versionregpath;
176 LPCWSTR versionsubdir;
177 } printenv_t;
179 /* ############################### */
181 static opened_printer_t **printer_handles;
182 static UINT nb_printer_handles;
183 static LONG next_job_id = 1;
185 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
186 WORD fwCapability, LPSTR lpszOutput,
187 LPDEVMODEA lpdm );
188 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
189 LPSTR lpszDevice, LPSTR lpszPort,
190 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
191 DWORD fwMode );
193 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
194 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
195 'c','o','n','t','r','o','l','\\',
196 'P','r','i','n','t','\\',
197 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
198 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
200 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
201 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
202 'C','o','n','t','r','o','l','\\',
203 'P','r','i','n','t','\\',
204 'P','r','i','n','t','e','r','s',0};
206 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
207 'M','i','c','r','o','s','o','f','t','\\',
208 'W','i','n','d','o','w','s',' ','N','T','\\',
209 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
210 'W','i','n','d','o','w','s',0};
212 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
213 'M','i','c','r','o','s','o','f','t','\\',
214 'W','i','n','d','o','w','s',' ','N','T','\\',
215 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
216 'D','e','v','i','c','e','s',0};
218 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
219 'M','i','c','r','o','s','o','f','t','\\',
220 'W','i','n','d','o','w','s',' ','N','T','\\',
221 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
222 'P','r','i','n','t','e','r','P','o','r','t','s',0};
224 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
225 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
226 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
227 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
228 static const WCHAR subdir_x64W[] = {'x','6','4',0};
229 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
230 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
231 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
232 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
233 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
235 static const WCHAR AttributesW[] = {'A','t','t','r','i','b','u','t','e','s',0};
236 static const WCHAR backslashW[] = {'\\',0};
237 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
238 'i','o','n',' ','F','i','l','e',0};
239 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
240 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
241 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
242 static const WCHAR Default_PriorityW[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
243 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
244 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
245 static const WCHAR dnsTimeoutW[] = {'d','n','s','T','i','m','e','o','u','t',0};
246 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
247 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
248 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
249 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
250 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
251 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
252 static const WCHAR NameW[] = {'N','a','m','e',0};
253 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
254 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
255 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
256 static const WCHAR PortW[] = {'P','o','r','t',0};
257 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
258 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
259 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
260 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
261 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
262 static const WCHAR PriorityW[] = {'P','r','i','o','r','i','t','y',0};
263 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
264 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
265 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
266 static const WCHAR StartTimeW[] = {'S','t','a','r','t','T','i','m','e',0};
267 static const WCHAR StatusW[] = {'S','t','a','t','u','s',0};
268 static const WCHAR txTimeoutW[] = {'t','x','T','i','m','e','o','u','t',0};
269 static const WCHAR UntilTimeW[] = {'U','n','t','i','l','T','i','m','e',0};
270 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
271 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
272 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
273 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
274 static WCHAR rawW[] = {'R','A','W',0};
275 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
276 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
277 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
278 static const WCHAR commaW[] = {',',0};
279 static WCHAR emptyStringW[] = {0};
281 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
283 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
284 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
285 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
287 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
288 'D','o','c','u','m','e','n','t',0};
290 static const WCHAR PPD_Overrides[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
291 static const WCHAR DefaultPageSize[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
293 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
294 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
295 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
296 0, sizeof(DRIVER_INFO_8W)};
299 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
300 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
301 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
302 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
303 sizeof(PRINTER_INFO_9W)};
305 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
306 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
307 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
309 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
311 /******************************************************************
312 * validate the user-supplied printing-environment [internal]
314 * PARAMS
315 * env [I] PTR to Environment-String or NULL
317 * RETURNS
318 * Failure: NULL
319 * Success: PTR to printenv_t
321 * NOTES
322 * An empty string is handled the same way as NULL.
323 * SetLastError(ERROR_INVALID_ENVIRONMENT) is called on Failure
327 static const printenv_t * validate_envW(LPCWSTR env)
329 const printenv_t *result = NULL;
330 unsigned int i;
332 TRACE("testing %s\n", debugstr_w(env));
333 if (env && env[0])
335 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
337 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
339 result = all_printenv[i];
340 break;
344 if (result == NULL) {
345 FIXME("unsupported Environment: %s\n", debugstr_w(env));
346 SetLastError(ERROR_INVALID_ENVIRONMENT);
348 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
350 else
352 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
354 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
356 return result;
360 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
361 if passed a NULL string. This returns NULLs to the result.
363 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
365 if ( (src) )
367 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
368 return usBufferPtr->Buffer;
370 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
371 return NULL;
374 static LPWSTR strdupW(LPCWSTR p)
376 LPWSTR ret;
377 DWORD len;
379 if(!p) return NULL;
380 len = (strlenW(p) + 1) * sizeof(WCHAR);
381 ret = HeapAlloc(GetProcessHeap(), 0, len);
382 memcpy(ret, p, len);
383 return ret;
386 static LPSTR strdupWtoA( LPCWSTR str )
388 LPSTR ret;
389 INT len;
391 if (!str) return NULL;
392 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
393 ret = HeapAlloc( GetProcessHeap(), 0, len );
394 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
395 return ret;
398 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
400 DEVMODEW *ret;
402 if (!dm) return NULL;
403 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
404 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
405 return ret;
408 /***********************************************************
409 * DEVMODEdupWtoA
410 * Creates an ansi copy of supplied devmode
412 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
414 LPDEVMODEA dmA;
415 DWORD size;
417 if (!dmW) return NULL;
418 size = dmW->dmSize - CCHDEVICENAME -
419 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
421 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
422 if (!dmA) return NULL;
424 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
425 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
427 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
429 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
430 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
432 else
434 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
435 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
436 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
437 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
439 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
442 dmA->dmSize = size;
443 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
444 return dmA;
448 /******************************************************************
449 * verify, that the filename is a local file
452 static inline BOOL is_local_file(LPWSTR name)
454 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
457 /* ################################ */
459 static int multi_sz_lenA(const char *str)
461 const char *ptr = str;
462 if(!str) return 0;
465 ptr += lstrlenA(ptr) + 1;
466 } while(*ptr);
468 return ptr - str + 1;
471 /*****************************************************************************
472 * get_dword_from_reg
474 * Return DWORD associated with name from hkey.
476 static DWORD get_dword_from_reg( HKEY hkey, const WCHAR *name )
478 DWORD sz = sizeof(DWORD), type, value = 0;
479 LONG ret;
481 ret = RegQueryValueExW( hkey, name, 0, &type, (LPBYTE)&value, &sz );
483 if (ret != ERROR_SUCCESS)
485 WARN( "Got ret = %d on name %s\n", ret, debugstr_w(name) );
486 return 0;
488 if (type != REG_DWORD)
490 ERR( "Got type %d\n", type );
491 return 0;
493 return value;
496 static inline DWORD set_reg_DWORD( HKEY hkey, const WCHAR *keyname, const DWORD value )
498 return RegSetValueExW( hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value) );
501 /******************************************************************
502 * get_opened_printer
503 * Get the pointer to the opened printer referred by the handle
505 static opened_printer_t *get_opened_printer(HANDLE hprn)
507 UINT_PTR idx = (UINT_PTR)hprn;
508 opened_printer_t *ret = NULL;
510 EnterCriticalSection(&printer_handles_cs);
512 if ((idx > 0) && (idx <= nb_printer_handles)) {
513 ret = printer_handles[idx - 1];
515 LeaveCriticalSection(&printer_handles_cs);
516 return ret;
519 /******************************************************************
520 * get_opened_printer_name
521 * Get the pointer to the opened printer name referred by the handle
523 static LPCWSTR get_opened_printer_name(HANDLE hprn)
525 opened_printer_t *printer = get_opened_printer(hprn);
526 if(!printer) return NULL;
527 return printer->name;
530 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
532 HKEY printers;
533 DWORD err;
535 *key = NULL;
536 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
537 if (err) return err;
539 err = RegOpenKeyW( printers, name, key );
540 if (err) err = ERROR_INVALID_PRINTER_NAME;
541 RegCloseKey( printers );
542 return err;
545 /******************************************************************
546 * WINSPOOL_GetOpenedPrinterRegKey
549 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
551 LPCWSTR name = get_opened_printer_name(hPrinter);
553 if(!name) return ERROR_INVALID_HANDLE;
554 return open_printer_reg_key( name, phkey );
557 static void
558 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
559 char qbuf[200];
561 /* If forcing, or no profile string entry for device yet, set the entry
563 * The always change entry if not WINEPS yet is discussable.
565 if (force ||
566 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
567 !strcmp(qbuf,"*") ||
568 !strstr(qbuf,"WINEPS.DRV")
570 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
571 HKEY hkey;
573 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
574 WriteProfileStringA("windows","device",buf);
575 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
576 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
577 RegCloseKey(hkey);
579 HeapFree(GetProcessHeap(),0,buf);
583 static BOOL add_printer_driver(const WCHAR *name, WCHAR *ppd)
585 DRIVER_INFO_3W di3;
586 unsigned int i;
587 BOOL res;
589 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
590 di3.cVersion = 3;
591 di3.pName = (WCHAR*)name;
592 di3.pDriverPath = driver_nt;
593 di3.pDataFile = ppd;
594 di3.pConfigFile = driver_nt;
595 di3.pDefaultDataType = rawW;
597 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
599 di3.pEnvironment = (WCHAR *) all_printenv[i]->envname;
600 if (all_printenv[i]->envname == envname_win40W)
602 /* We use wineps16.drv as driver for 16 bit */
603 di3.pDriverPath = driver_9x;
604 di3.pConfigFile = driver_9x;
606 res = AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY );
607 TRACE("got %d and %d for %s (%s)\n", res, GetLastError(), debugstr_w(name), debugstr_w(di3.pEnvironment));
609 if (!res && (GetLastError() != ERROR_PRINTER_DRIVER_ALREADY_INSTALLED))
611 ERR("failed with %u for %s (%s) %s\n", GetLastError(), debugstr_w(name),
612 debugstr_w(di3.pEnvironment), debugstr_w(di3.pDriverPath));
613 return FALSE;
617 return TRUE;
620 static inline char *expand_env_string( char *str, DWORD type )
622 if (type == REG_EXPAND_SZ)
624 char *tmp;
625 DWORD needed = ExpandEnvironmentStringsA( str, NULL, 0 );
626 tmp = HeapAlloc( GetProcessHeap(), 0, needed );
627 if (tmp)
629 ExpandEnvironmentStringsA( str, tmp, needed );
630 HeapFree( GetProcessHeap(), 0, str );
631 return tmp;
634 return str;
637 static char *get_fallback_ppd_name( const char *printer_name )
639 static const WCHAR ppds_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
640 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
641 HKEY hkey;
642 DWORD needed, type;
643 char *ret = NULL;
645 if (RegOpenKeyW( HKEY_CURRENT_USER, ppds_key, &hkey ) == ERROR_SUCCESS )
647 const char *value_name = NULL;
649 if (RegQueryValueExA( hkey, printer_name, 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
650 value_name = printer_name;
651 else if (RegQueryValueExA( hkey, "generic", 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
652 value_name = "generic";
654 if (value_name)
656 ret = HeapAlloc( GetProcessHeap(), 0, needed );
657 if (!ret) return NULL;
658 RegQueryValueExA( hkey, value_name, 0, &type, (BYTE *)ret, &needed );
660 RegCloseKey( hkey );
661 if (ret) return expand_env_string( ret, type );
663 return NULL;
666 static BOOL copy_file( const char *src, const char *dst )
668 int fds[2] = {-1, -1}, num;
669 char buf[1024];
670 BOOL ret = FALSE;
672 fds[0] = open( src, O_RDONLY );
673 fds[1] = open( dst, O_CREAT | O_TRUNC | O_WRONLY, 0666 );
674 if (fds[0] == -1 || fds[1] == -1) goto fail;
676 while ((num = read( fds[0], buf, sizeof(buf) )) != 0)
678 if (num == -1) goto fail;
679 if (write( fds[1], buf, num ) != num) goto fail;
681 ret = TRUE;
683 fail:
684 if (fds[1] != -1) close( fds[1] );
685 if (fds[0] != -1) close( fds[0] );
686 return ret;
689 static BOOL get_internal_fallback_ppd( const WCHAR *ppd )
691 static const WCHAR typeW[] = {'P','P','D','F','I','L','E',0};
693 char *ptr, *end;
694 DWORD size, written;
695 HANDLE file;
696 BOOL ret;
697 HRSRC res = FindResourceW( WINSPOOL_hInstance, MAKEINTRESOURCEW(1), typeW );
699 if (!res || !(ptr = LoadResource( WINSPOOL_hInstance, res ))) return FALSE;
700 size = SizeofResource( WINSPOOL_hInstance, res );
701 end = memchr( ptr, 0, size ); /* resource file may contain additional nulls */
702 if (end) size = end - ptr;
703 file = CreateFileW( ppd, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0 );
704 if (file == INVALID_HANDLE_VALUE) return FALSE;
705 ret = WriteFile( file, ptr, size, &written, NULL ) && written == size;
706 CloseHandle( file );
707 if (ret) TRACE( "using internal fallback for %s\n", debugstr_w( ppd ));
708 else DeleteFileW( ppd );
709 return ret;
712 static BOOL get_fallback_ppd( const char *printer_name, const WCHAR *ppd )
714 char *dst, *src = get_fallback_ppd_name( printer_name );
715 BOOL ret = FALSE;
717 if (!src) return get_internal_fallback_ppd( ppd );
719 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name), debugstr_w(ppd), debugstr_a(src) );
721 if (!(dst = wine_get_unix_file_name( ppd ))) goto fail;
723 if (symlink( src, dst ) == -1)
724 if (errno != ENOSYS || !copy_file( src, dst ))
725 goto fail;
727 ret = TRUE;
728 fail:
729 HeapFree( GetProcessHeap(), 0, dst );
730 HeapFree( GetProcessHeap(), 0, src );
731 return ret;
734 static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
736 static const WCHAR dot_ppd[] = {'.','p','p','d',0};
737 int len = (strlenW( dir ) + strlenW( file_name )) * sizeof(WCHAR) + sizeof(dot_ppd);
738 WCHAR *ppd = HeapAlloc( GetProcessHeap(), 0, len );
740 if (!ppd) return NULL;
741 strcpyW( ppd, dir );
742 strcatW( ppd, file_name );
743 strcatW( ppd, dot_ppd );
745 return ppd;
748 static WCHAR *get_ppd_dir( void )
750 static const WCHAR wine_ppds[] = {'w','i','n','e','_','p','p','d','s','\\',0};
751 DWORD len;
752 WCHAR *dir, tmp_path[MAX_PATH];
753 BOOL res;
755 len = GetTempPathW( ARRAY_SIZE( tmp_path ), tmp_path );
756 if (!len) return NULL;
757 dir = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
758 if (!dir) return NULL;
760 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
761 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
762 res = CreateDirectoryW( dir, NULL );
763 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
765 HeapFree( GetProcessHeap(), 0, dir );
766 dir = NULL;
768 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
769 return dir;
772 static void unlink_ppd( const WCHAR *ppd )
774 char *unix_name = wine_get_unix_file_name( ppd );
775 unlink( unix_name );
776 HeapFree( GetProcessHeap(), 0, unix_name );
779 #ifdef SONAME_LIBCUPS
781 static void *cupshandle;
783 #define CUPS_FUNCS \
784 DO_FUNC(cupsAddOption); \
785 DO_FUNC(cupsFreeDests); \
786 DO_FUNC(cupsFreeOptions); \
787 DO_FUNC(cupsGetDests); \
788 DO_FUNC(cupsGetOption); \
789 DO_FUNC(cupsGetPPD); \
790 DO_FUNC(cupsParseOptions); \
791 DO_FUNC(cupsPrintFile)
792 #define CUPS_OPT_FUNCS \
793 DO_FUNC(cupsGetNamedDest); \
794 DO_FUNC(cupsGetPPD3); \
795 DO_FUNC(cupsLastErrorString)
797 #define DO_FUNC(f) static typeof(f) *p##f
798 CUPS_FUNCS;
799 #undef DO_FUNC
800 static cups_dest_t * (*pcupsGetNamedDest)(http_t *, const char *, const char *);
801 static http_status_t (*pcupsGetPPD3)(http_t *, const char *, time_t *, char *, size_t);
802 static const char * (*pcupsLastErrorString)(void);
804 static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name,
805 time_t *modtime, char *buffer,
806 size_t bufsize )
808 const char *ppd;
810 if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
812 if (!pcupsGetPPD) return HTTP_NOT_FOUND;
814 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
816 *modtime = 0;
817 ppd = pcupsGetPPD( name );
819 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
821 if (!ppd) return HTTP_NOT_FOUND;
823 if (rename( ppd, buffer ) == -1)
825 BOOL res = copy_file( ppd, buffer );
826 unlink( ppd );
827 if (!res) return HTTP_NOT_FOUND;
829 return HTTP_OK;
832 static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
834 time_t modtime = 0;
835 http_status_t http_status;
836 char *unix_name = wine_get_unix_file_name( ppd );
838 TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
840 if (!unix_name) return FALSE;
842 http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
843 unix_name, strlen( unix_name ) + 1 );
845 if (http_status != HTTP_OK) unlink( unix_name );
846 HeapFree( GetProcessHeap(), 0, unix_name );
848 if (http_status == HTTP_OK) return TRUE;
850 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
851 debugstr_a(printer_name), http_status );
852 return get_fallback_ppd( printer_name, ppd );
855 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
857 const char *value;
858 WCHAR *ret;
859 int len;
861 value = pcupsGetOption( name, num_options, options );
862 if (!value) return NULL;
864 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
865 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
866 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
868 return ret;
871 static cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
873 WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
874 cups_ptype_t ret = 0;
876 if (type && *type)
878 ret = (cups_ptype_t)strtoulW( type, &end, 10 );
879 if (*end) ret = 0;
881 HeapFree( GetProcessHeap(), 0, type );
882 return ret;
885 static void load_cups(void)
887 cupshandle = wine_dlopen( SONAME_LIBCUPS, RTLD_NOW, NULL, 0 );
888 if (!cupshandle) return;
890 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
892 #define DO_FUNC(x) \
893 p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); \
894 if (!p##x) \
896 ERR("failed to load symbol %s\n", #x); \
897 cupshandle = NULL; \
898 return; \
900 CUPS_FUNCS;
901 #undef DO_FUNC
902 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 )
903 CUPS_OPT_FUNCS;
904 #undef DO_FUNC
907 static BOOL CUPS_LoadPrinters(void)
909 int i, nrofdests;
910 BOOL hadprinter = FALSE, haddefault = FALSE;
911 cups_dest_t *dests;
912 PRINTER_INFO_2W pi2;
913 WCHAR *port, *ppd_dir = NULL, *ppd;
914 HKEY hkeyPrinter, hkeyPrinters;
915 WCHAR nameW[MAX_PATH];
916 HANDLE added_printer;
917 cups_ptype_t printer_type;
919 if (!cupshandle) return FALSE;
921 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
922 ERROR_SUCCESS) {
923 ERR("Can't create Printers key\n");
924 return FALSE;
927 nrofdests = pcupsGetDests(&dests);
928 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
929 for (i=0;i<nrofdests;i++) {
930 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, ARRAY_SIZE(nameW));
931 printer_type = get_cups_printer_type( dests + i );
933 TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
935 if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
937 TRACE( "skipping scanner-only device\n" );
938 continue;
941 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
942 lstrcpyW(port, CUPS_Port);
943 lstrcatW(port, nameW);
945 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
946 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
947 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
948 and continue */
949 TRACE("Printer already exists\n");
950 /* overwrite old LPR:* port */
951 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
952 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
953 /* flag that the PPD file should be checked for an update */
954 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
955 RegCloseKey(hkeyPrinter);
956 } else {
957 BOOL added_driver = FALSE;
959 if (!ppd_dir && !(ppd_dir = get_ppd_dir()))
961 HeapFree( GetProcessHeap(), 0, port );
962 break;
964 ppd = get_ppd_filename( ppd_dir, nameW );
965 if (get_cups_ppd( dests[i].name, ppd ))
967 added_driver = add_printer_driver( nameW, ppd );
968 unlink_ppd( ppd );
970 HeapFree( GetProcessHeap(), 0, ppd );
971 if (!added_driver)
973 HeapFree( GetProcessHeap(), 0, port );
974 continue;
977 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
978 pi2.pPrinterName = nameW;
979 pi2.pDatatype = rawW;
980 pi2.pPrintProcessor = WinPrintW;
981 pi2.pDriverName = nameW;
982 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
983 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
984 pi2.pPortName = port;
985 pi2.pParameters = emptyStringW;
986 pi2.pShareName = emptyStringW;
987 pi2.pSepFile = emptyStringW;
989 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
990 if (added_printer) ClosePrinter( added_printer );
991 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
992 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
994 HeapFree( GetProcessHeap(), 0, pi2.pComment );
995 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
997 HeapFree( GetProcessHeap(), 0, port );
999 hadprinter = TRUE;
1000 if (dests[i].is_default) {
1001 SetDefaultPrinterW(nameW);
1002 haddefault = TRUE;
1006 if (ppd_dir)
1008 RemoveDirectoryW( ppd_dir );
1009 HeapFree( GetProcessHeap(), 0, ppd_dir );
1012 if (hadprinter && !haddefault) {
1013 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, ARRAY_SIZE(nameW));
1014 SetDefaultPrinterW(nameW);
1016 pcupsFreeDests(nrofdests, dests);
1017 RegCloseKey(hkeyPrinters);
1018 return TRUE;
1021 #endif
1023 static char *get_queue_name( HANDLE printer, BOOL *cups )
1025 WCHAR *port, *name = NULL;
1026 DWORD err, needed, type;
1027 char *ret = NULL;
1028 HKEY key;
1030 *cups = FALSE;
1032 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1033 if (err) return NULL;
1034 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1035 if (err) goto end;
1036 port = HeapAlloc( GetProcessHeap(), 0, needed );
1037 if (!port) goto end;
1038 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1040 if (!strncmpW( port, CUPS_Port, ARRAY_SIZE( CUPS_Port ) -1 ))
1042 name = port + ARRAY_SIZE( CUPS_Port ) - 1;
1043 *cups = TRUE;
1045 else if (!strncmpW( port, LPR_Port, ARRAY_SIZE( LPR_Port ) -1 ))
1046 name = port + ARRAY_SIZE( LPR_Port ) - 1;
1047 if (name)
1049 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1050 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1051 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1053 HeapFree( GetProcessHeap(), 0, port );
1054 end:
1055 RegCloseKey( key );
1056 return ret;
1060 static void set_ppd_overrides( HANDLE printer )
1062 WCHAR *wstr = NULL;
1063 int size = 0;
1064 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1065 OSStatus status;
1066 PMPrintSession session = NULL;
1067 PMPageFormat format = NULL;
1068 PMPaper paper;
1069 CFStringRef paper_name;
1070 CFRange range;
1072 status = PMCreateSession( &session );
1073 if (status) goto end;
1075 status = PMCreatePageFormat( &format );
1076 if (status) goto end;
1078 status = PMSessionDefaultPageFormat( session, format );
1079 if (status) goto end;
1081 status = PMGetPageFormatPaper( format, &paper );
1082 if (status) goto end;
1084 status = PMPaperGetPPDPaperName( paper, &paper_name );
1085 if (status) goto end;
1087 range.location = 0;
1088 range.length = CFStringGetLength( paper_name );
1089 size = (range.length + 1) * sizeof(WCHAR);
1091 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1092 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1093 wstr[range.length] = 0;
1095 end:
1096 if (format) PMRelease( format );
1097 if (session) PMRelease( session );
1098 #endif
1100 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1101 HeapFree( GetProcessHeap(), 0, wstr );
1104 static BOOL update_driver( HANDLE printer )
1106 BOOL ret, is_cups;
1107 const WCHAR *name = get_opened_printer_name( printer );
1108 WCHAR *ppd_dir, *ppd;
1109 char *queue_name;
1111 if (!name) return FALSE;
1112 queue_name = get_queue_name( printer, &is_cups );
1113 if (!queue_name) return FALSE;
1115 if (!(ppd_dir = get_ppd_dir()))
1117 HeapFree( GetProcessHeap(), 0, queue_name );
1118 return FALSE;
1120 ppd = get_ppd_filename( ppd_dir, name );
1122 #ifdef SONAME_LIBCUPS
1123 if (is_cups)
1124 ret = get_cups_ppd( queue_name, ppd );
1125 else
1126 #endif
1127 ret = get_fallback_ppd( queue_name, ppd );
1129 if (ret)
1131 TRACE( "updating driver %s\n", debugstr_w( name ) );
1132 ret = add_printer_driver( name, ppd );
1133 unlink_ppd( ppd );
1135 HeapFree( GetProcessHeap(), 0, ppd_dir );
1136 HeapFree( GetProcessHeap(), 0, ppd );
1137 HeapFree( GetProcessHeap(), 0, queue_name );
1139 set_ppd_overrides( printer );
1141 /* call into the driver to update the devmode */
1142 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1144 return ret;
1147 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1149 PRINTER_INFO_2A pinfo2a;
1150 const char *r;
1151 size_t name_len;
1152 char *e,*s,*name,*prettyname,*devname;
1153 BOOL ret = FALSE, set_default = FALSE;
1154 char *port = NULL, *env_default;
1155 HKEY hkeyPrinter, hkeyPrinters = NULL;
1156 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1157 HANDLE added_printer;
1159 while (isspace(*pent)) pent++;
1160 r = strchr(pent,':');
1161 if (r)
1162 name_len = r - pent;
1163 else
1164 name_len = strlen(pent);
1165 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1166 memcpy(name, pent, name_len);
1167 name[name_len] = '\0';
1168 if (r)
1169 pent = r;
1170 else
1171 pent = "";
1173 TRACE("name=%s entry=%s\n",name, pent);
1175 if(ispunct(*name)) { /* a tc entry, not a real printer */
1176 TRACE("skipping tc entry\n");
1177 goto end;
1180 if(strstr(pent,":server")) { /* server only version so skip */
1181 TRACE("skipping server entry\n");
1182 goto end;
1185 /* Determine whether this is a postscript printer. */
1187 ret = TRUE;
1188 env_default = getenv("PRINTER");
1189 prettyname = name;
1190 /* Get longest name, usually the one at the right for later display. */
1191 while((s=strchr(prettyname,'|'))) {
1192 *s = '\0';
1193 e = s;
1194 while(isspace(*--e)) *e = '\0';
1195 TRACE("\t%s\n", debugstr_a(prettyname));
1196 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1197 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1200 e = prettyname + strlen(prettyname);
1201 while(isspace(*--e)) *e = '\0';
1202 TRACE("\t%s\n", debugstr_a(prettyname));
1203 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1205 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1206 * if it is too long, we use it as comment below. */
1207 devname = prettyname;
1208 if (strlen(devname)>=CCHDEVICENAME-1)
1209 devname = name;
1210 if (strlen(devname)>=CCHDEVICENAME-1) {
1211 ret = FALSE;
1212 goto end;
1215 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1216 sprintf(port,"LPR:%s",name);
1218 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1219 ERROR_SUCCESS) {
1220 ERR("Can't create Printers key\n");
1221 ret = FALSE;
1222 goto end;
1225 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, ARRAY_SIZE(devnameW));
1227 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1228 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1229 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1230 and continue */
1231 TRACE("Printer already exists\n");
1232 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1233 /* flag that the PPD file should be checked for an update */
1234 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1235 RegCloseKey(hkeyPrinter);
1236 } else {
1237 static CHAR data_type[] = "RAW",
1238 print_proc[] = "WinPrint",
1239 comment[] = "WINEPS Printer using LPR",
1240 params[] = "<parameters?>",
1241 share_name[] = "<share name?>",
1242 sep_file[] = "<sep file?>";
1243 BOOL added_driver = FALSE;
1245 if (!ppd_dir && !(ppd_dir = get_ppd_dir())) goto end;
1246 ppd = get_ppd_filename( ppd_dir, devnameW );
1247 if (get_fallback_ppd( devname, ppd ))
1249 added_driver = add_printer_driver( devnameW, ppd );
1250 unlink_ppd( ppd );
1252 HeapFree( GetProcessHeap(), 0, ppd );
1253 if (!added_driver) goto end;
1255 memset(&pinfo2a,0,sizeof(pinfo2a));
1256 pinfo2a.pPrinterName = devname;
1257 pinfo2a.pDatatype = data_type;
1258 pinfo2a.pPrintProcessor = print_proc;
1259 pinfo2a.pDriverName = devname;
1260 pinfo2a.pComment = comment;
1261 pinfo2a.pLocation = prettyname;
1262 pinfo2a.pPortName = port;
1263 pinfo2a.pParameters = params;
1264 pinfo2a.pShareName = share_name;
1265 pinfo2a.pSepFile = sep_file;
1267 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1268 if (added_printer) ClosePrinter( added_printer );
1269 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1270 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1273 if (isfirst || set_default)
1274 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1276 end:
1277 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1278 if (ppd_dir)
1280 RemoveDirectoryW( ppd_dir );
1281 HeapFree( GetProcessHeap(), 0, ppd_dir );
1283 HeapFree(GetProcessHeap(), 0, port);
1284 HeapFree(GetProcessHeap(), 0, name);
1285 return ret;
1288 static BOOL
1289 PRINTCAP_LoadPrinters(void) {
1290 BOOL hadprinter = FALSE;
1291 char buf[200];
1292 FILE *f;
1293 char *pent = NULL;
1294 BOOL had_bash = FALSE;
1296 f = fopen("/etc/printcap","r");
1297 if (!f)
1298 return FALSE;
1300 while(fgets(buf,sizeof(buf),f)) {
1301 char *start, *end;
1303 end=strchr(buf,'\n');
1304 if (end) *end='\0';
1306 start = buf;
1307 while(isspace(*start)) start++;
1308 if(*start == '#' || *start == '\0')
1309 continue;
1311 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1312 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1313 HeapFree(GetProcessHeap(),0,pent);
1314 pent = NULL;
1317 if (end && *--end == '\\') {
1318 *end = '\0';
1319 had_bash = TRUE;
1320 } else
1321 had_bash = FALSE;
1323 if (pent) {
1324 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1325 strcat(pent,start);
1326 } else {
1327 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1328 strcpy(pent,start);
1332 if(pent) {
1333 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1334 HeapFree(GetProcessHeap(),0,pent);
1336 fclose(f);
1337 return hadprinter;
1340 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1342 if (value)
1343 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1344 (lstrlenW(value) + 1) * sizeof(WCHAR));
1345 else
1346 return ERROR_FILE_NOT_FOUND;
1349 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1351 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1352 DWORD ret = ERROR_FILE_NOT_FOUND;
1354 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1355 and we support these drivers. NT writes DEVMODEW so somehow
1356 we'll need to distinguish between these when we support NT
1357 drivers */
1359 if (dmA)
1361 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1362 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1363 HeapFree( GetProcessHeap(), 0, dmA );
1366 return ret;
1369 /******************************************************************
1370 * get_servername_from_name (internal)
1372 * for an external server, a copy of the serverpart from the full name is returned
1375 static LPWSTR get_servername_from_name(LPCWSTR name)
1377 LPWSTR server;
1378 LPWSTR ptr;
1379 WCHAR buffer[MAX_PATH];
1380 DWORD len;
1382 if (name == NULL) return NULL;
1383 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1385 server = strdupW(&name[2]); /* skip over both backslash */
1386 if (server == NULL) return NULL;
1388 /* strip '\' and the printername */
1389 ptr = strchrW(server, '\\');
1390 if (ptr) ptr[0] = '\0';
1392 TRACE("found %s\n", debugstr_w(server));
1394 len = ARRAY_SIZE(buffer);
1395 if (GetComputerNameW(buffer, &len)) {
1396 if (lstrcmpW(buffer, server) == 0) {
1397 /* The requested Servername is our computername */
1398 HeapFree(GetProcessHeap(), 0, server);
1399 return NULL;
1402 return server;
1405 /******************************************************************
1406 * get_basename_from_name (internal)
1408 * skip over the serverpart from the full name
1411 static LPCWSTR get_basename_from_name(LPCWSTR name)
1413 if (name == NULL) return NULL;
1414 if ((name[0] == '\\') && (name[1] == '\\')) {
1415 /* skip over the servername and search for the following '\' */
1416 name = strchrW(&name[2], '\\');
1417 if ((name) && (name[1])) {
1418 /* found a separator ('\') followed by a name:
1419 skip over the separator and return the rest */
1420 name++;
1422 else
1424 /* no basename present (we found only a servername) */
1425 return NULL;
1428 return name;
1431 static void free_printer_entry( opened_printer_t *printer )
1433 /* the queue is shared, so don't free that here */
1434 HeapFree( GetProcessHeap(), 0, printer->printername );
1435 HeapFree( GetProcessHeap(), 0, printer->name );
1436 HeapFree( GetProcessHeap(), 0, printer->devmode );
1437 HeapFree( GetProcessHeap(), 0, printer );
1440 /******************************************************************
1441 * get_opened_printer_entry
1442 * Get the first place empty in the opened printer table
1444 * ToDo:
1445 * - pDefault is ignored
1447 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1449 UINT_PTR handle = nb_printer_handles, i;
1450 jobqueue_t *queue = NULL;
1451 opened_printer_t *printer = NULL;
1452 LPWSTR servername;
1453 LPCWSTR printername;
1455 if ((backend == NULL) && !load_backend()) return NULL;
1457 servername = get_servername_from_name(name);
1458 if (servername) {
1459 FIXME("server %s not supported\n", debugstr_w(servername));
1460 HeapFree(GetProcessHeap(), 0, servername);
1461 SetLastError(ERROR_INVALID_PRINTER_NAME);
1462 return NULL;
1465 printername = get_basename_from_name(name);
1466 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1468 /* an empty printername is invalid */
1469 if (printername && (!printername[0])) {
1470 SetLastError(ERROR_INVALID_PARAMETER);
1471 return NULL;
1474 EnterCriticalSection(&printer_handles_cs);
1476 for (i = 0; i < nb_printer_handles; i++)
1478 if (!printer_handles[i])
1480 if(handle == nb_printer_handles)
1481 handle = i;
1483 else
1485 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1486 queue = printer_handles[i]->queue;
1490 if (handle >= nb_printer_handles)
1492 opened_printer_t **new_array;
1493 if (printer_handles)
1494 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1495 (nb_printer_handles + 16) * sizeof(*new_array) );
1496 else
1497 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1498 (nb_printer_handles + 16) * sizeof(*new_array) );
1500 if (!new_array)
1502 handle = 0;
1503 goto end;
1505 printer_handles = new_array;
1506 nb_printer_handles += 16;
1509 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1511 handle = 0;
1512 goto end;
1515 /* get a printer handle from the backend */
1516 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1517 handle = 0;
1518 goto end;
1521 /* clone the base name. This is NULL for the printserver */
1522 printer->printername = strdupW(printername);
1524 /* clone the full name */
1525 printer->name = strdupW(name);
1526 if (name && (!printer->name)) {
1527 handle = 0;
1528 goto end;
1531 if (pDefault && pDefault->pDevMode)
1532 printer->devmode = dup_devmode( pDefault->pDevMode );
1534 if(queue)
1535 printer->queue = queue;
1536 else
1538 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1539 if (!printer->queue) {
1540 handle = 0;
1541 goto end;
1543 list_init(&printer->queue->jobs);
1544 printer->queue->ref = 0;
1546 InterlockedIncrement(&printer->queue->ref);
1548 printer_handles[handle] = printer;
1549 handle++;
1550 end:
1551 LeaveCriticalSection(&printer_handles_cs);
1552 if (!handle && printer) {
1553 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1554 free_printer_entry( printer );
1557 return (HANDLE)handle;
1560 static void old_printer_check( BOOL delete_phase )
1562 PRINTER_INFO_5W* pi;
1563 DWORD needed, type, num, delete, i, size;
1564 const DWORD one = 1;
1565 HKEY key;
1566 HANDLE hprn;
1568 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1569 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1571 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1572 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1573 for (i = 0; i < num; i++)
1575 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1576 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1577 continue;
1579 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1581 if (!delete_phase)
1583 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1584 RegCloseKey( key );
1586 else
1588 delete = 0;
1589 size = sizeof( delete );
1590 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1591 RegCloseKey( key );
1592 if (delete)
1594 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1595 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1597 DeletePrinter( hprn );
1598 ClosePrinter( hprn );
1600 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1604 HeapFree(GetProcessHeap(), 0, pi);
1607 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1608 'M','U','T','E','X','_','_','\0'};
1609 static HANDLE init_mutex;
1611 void WINSPOOL_LoadSystemPrinters(void)
1613 HKEY hkey, hkeyPrinters;
1614 DWORD needed, num, i;
1615 WCHAR PrinterName[256];
1616 BOOL done = FALSE;
1618 #ifdef SONAME_LIBCUPS
1619 load_cups();
1620 #endif
1622 /* FIXME: The init code should be moved to spoolsv.exe */
1623 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1624 if (!init_mutex)
1626 ERR( "Failed to create mutex\n" );
1627 return;
1629 if (GetLastError() == ERROR_ALREADY_EXISTS)
1631 WaitForSingleObject( init_mutex, INFINITE );
1632 ReleaseMutex( init_mutex );
1633 TRACE( "Init already done\n" );
1634 return;
1637 /* This ensures that all printer entries have a valid Name value. If causes
1638 problems later if they don't. If one is found to be missed we create one
1639 and set it equal to the name of the key */
1640 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1641 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1642 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1643 for(i = 0; i < num; i++) {
1644 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, ARRAY_SIZE(PrinterName)) == ERROR_SUCCESS) {
1645 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1646 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1647 set_reg_szW(hkey, NameW, PrinterName);
1649 RegCloseKey(hkey);
1654 RegCloseKey(hkeyPrinters);
1657 old_printer_check( FALSE );
1659 #ifdef SONAME_LIBCUPS
1660 done = CUPS_LoadPrinters();
1661 #endif
1663 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1664 PRINTCAP_LoadPrinters();
1666 old_printer_check( TRUE );
1668 ReleaseMutex( init_mutex );
1669 return;
1672 /******************************************************************
1673 * get_job
1675 * Get the pointer to the specified job.
1676 * Should hold the printer_handles_cs before calling.
1678 static job_t *get_job(HANDLE hprn, DWORD JobId)
1680 opened_printer_t *printer = get_opened_printer(hprn);
1681 job_t *job;
1683 if(!printer) return NULL;
1684 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1686 if(job->job_id == JobId)
1687 return job;
1689 return NULL;
1692 /***********************************************************
1693 * DEVMODEcpyAtoW
1695 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1697 BOOL Formname;
1698 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1699 DWORD size;
1701 Formname = (dmA->dmSize > off_formname);
1702 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1703 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1704 dmW->dmDeviceName, CCHDEVICENAME);
1705 if(!Formname) {
1706 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1707 dmA->dmSize - CCHDEVICENAME);
1708 } else {
1709 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1710 off_formname - CCHDEVICENAME);
1711 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1712 dmW->dmFormName, CCHFORMNAME);
1713 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1714 (off_formname + CCHFORMNAME));
1716 dmW->dmSize = size;
1717 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1718 dmA->dmDriverExtra);
1719 return dmW;
1722 /******************************************************************
1723 * convert_printerinfo_W_to_A [internal]
1726 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1727 DWORD level, DWORD outlen, DWORD numentries)
1729 DWORD id = 0;
1730 LPSTR ptr;
1731 INT len;
1733 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1735 len = pi_sizeof[level] * numentries;
1736 ptr = (LPSTR) out + len;
1737 outlen -= len;
1739 /* copy the numbers of all PRINTER_INFO_* first */
1740 memcpy(out, pPrintersW, len);
1742 while (id < numentries) {
1743 switch (level) {
1744 case 1:
1746 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1747 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1749 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1750 if (piW->pDescription) {
1751 piA->pDescription = ptr;
1752 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1753 ptr, outlen, NULL, NULL);
1754 ptr += len;
1755 outlen -= len;
1757 if (piW->pName) {
1758 piA->pName = ptr;
1759 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1760 ptr, outlen, NULL, NULL);
1761 ptr += len;
1762 outlen -= len;
1764 if (piW->pComment) {
1765 piA->pComment = ptr;
1766 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1767 ptr, outlen, NULL, NULL);
1768 ptr += len;
1769 outlen -= len;
1771 break;
1774 case 2:
1776 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1777 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1778 LPDEVMODEA dmA;
1780 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1781 if (piW->pServerName) {
1782 piA->pServerName = ptr;
1783 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1784 ptr, outlen, NULL, NULL);
1785 ptr += len;
1786 outlen -= len;
1788 if (piW->pPrinterName) {
1789 piA->pPrinterName = ptr;
1790 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1791 ptr, outlen, NULL, NULL);
1792 ptr += len;
1793 outlen -= len;
1795 if (piW->pShareName) {
1796 piA->pShareName = ptr;
1797 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1798 ptr, outlen, NULL, NULL);
1799 ptr += len;
1800 outlen -= len;
1802 if (piW->pPortName) {
1803 piA->pPortName = ptr;
1804 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1805 ptr, outlen, NULL, NULL);
1806 ptr += len;
1807 outlen -= len;
1809 if (piW->pDriverName) {
1810 piA->pDriverName = ptr;
1811 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1812 ptr, outlen, NULL, NULL);
1813 ptr += len;
1814 outlen -= len;
1816 if (piW->pComment) {
1817 piA->pComment = ptr;
1818 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1819 ptr, outlen, NULL, NULL);
1820 ptr += len;
1821 outlen -= len;
1823 if (piW->pLocation) {
1824 piA->pLocation = ptr;
1825 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1826 ptr, outlen, NULL, NULL);
1827 ptr += len;
1828 outlen -= len;
1831 dmA = DEVMODEdupWtoA(piW->pDevMode);
1832 if (dmA) {
1833 /* align DEVMODEA to a DWORD boundary */
1834 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1835 ptr += len;
1836 outlen -= len;
1838 piA->pDevMode = (LPDEVMODEA) ptr;
1839 len = dmA->dmSize + dmA->dmDriverExtra;
1840 memcpy(ptr, dmA, len);
1841 HeapFree(GetProcessHeap(), 0, dmA);
1843 ptr += len;
1844 outlen -= len;
1847 if (piW->pSepFile) {
1848 piA->pSepFile = ptr;
1849 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1850 ptr, outlen, NULL, NULL);
1851 ptr += len;
1852 outlen -= len;
1854 if (piW->pPrintProcessor) {
1855 piA->pPrintProcessor = ptr;
1856 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1857 ptr, outlen, NULL, NULL);
1858 ptr += len;
1859 outlen -= len;
1861 if (piW->pDatatype) {
1862 piA->pDatatype = ptr;
1863 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1864 ptr, outlen, NULL, NULL);
1865 ptr += len;
1866 outlen -= len;
1868 if (piW->pParameters) {
1869 piA->pParameters = ptr;
1870 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1871 ptr, outlen, NULL, NULL);
1872 ptr += len;
1873 outlen -= len;
1875 if (piW->pSecurityDescriptor) {
1876 piA->pSecurityDescriptor = NULL;
1877 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1879 break;
1882 case 4:
1884 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1885 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1887 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1889 if (piW->pPrinterName) {
1890 piA->pPrinterName = ptr;
1891 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1892 ptr, outlen, NULL, NULL);
1893 ptr += len;
1894 outlen -= len;
1896 if (piW->pServerName) {
1897 piA->pServerName = ptr;
1898 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1899 ptr, outlen, NULL, NULL);
1900 ptr += len;
1901 outlen -= len;
1903 break;
1906 case 5:
1908 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1909 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1911 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1913 if (piW->pPrinterName) {
1914 piA->pPrinterName = ptr;
1915 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1916 ptr, outlen, NULL, NULL);
1917 ptr += len;
1918 outlen -= len;
1920 if (piW->pPortName) {
1921 piA->pPortName = ptr;
1922 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1923 ptr, outlen, NULL, NULL);
1924 ptr += len;
1925 outlen -= len;
1927 break;
1930 case 6: /* 6A and 6W are the same structure */
1931 break;
1933 case 7:
1935 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1936 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1938 TRACE("(%u) #%u\n", level, id);
1939 if (piW->pszObjectGUID) {
1940 piA->pszObjectGUID = ptr;
1941 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1942 ptr, outlen, NULL, NULL);
1943 ptr += len;
1944 outlen -= len;
1946 break;
1949 case 8:
1950 case 9:
1952 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1953 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1954 LPDEVMODEA dmA;
1956 TRACE("(%u) #%u\n", level, id);
1957 dmA = DEVMODEdupWtoA(piW->pDevMode);
1958 if (dmA) {
1959 /* align DEVMODEA to a DWORD boundary */
1960 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1961 ptr += len;
1962 outlen -= len;
1964 piA->pDevMode = (LPDEVMODEA) ptr;
1965 len = dmA->dmSize + dmA->dmDriverExtra;
1966 memcpy(ptr, dmA, len);
1967 HeapFree(GetProcessHeap(), 0, dmA);
1969 ptr += len;
1970 outlen -= len;
1973 break;
1976 default:
1977 FIXME("for level %u\n", level);
1979 pPrintersW += pi_sizeof[level];
1980 out += pi_sizeof[level];
1981 id++;
1985 /******************************************************************
1986 * convert_driverinfo_W_to_A [internal]
1989 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1990 DWORD level, DWORD outlen, DWORD numentries)
1992 DWORD id = 0;
1993 LPSTR ptr;
1994 INT len;
1996 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1998 len = di_sizeof[level] * numentries;
1999 ptr = (LPSTR) out + len;
2000 outlen -= len;
2002 /* copy the numbers of all PRINTER_INFO_* first */
2003 memcpy(out, pDriversW, len);
2005 #define COPY_STRING(fld) \
2006 { if (diW->fld){ \
2007 diA->fld = ptr; \
2008 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
2009 ptr += len; outlen -= len;\
2011 #define COPY_MULTIZ_STRING(fld) \
2012 { LPWSTR p = diW->fld; if (p){ \
2013 diA->fld = ptr; \
2014 do {\
2015 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2016 ptr += len; outlen -= len; p += len;\
2018 while(len > 1 && outlen > 0); \
2021 while (id < numentries)
2023 switch (level)
2025 case 1:
2027 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
2028 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
2030 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2032 COPY_STRING(pName);
2033 break;
2035 case 2:
2037 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2038 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2040 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2042 COPY_STRING(pName);
2043 COPY_STRING(pEnvironment);
2044 COPY_STRING(pDriverPath);
2045 COPY_STRING(pDataFile);
2046 COPY_STRING(pConfigFile);
2047 break;
2049 case 3:
2051 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2052 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2054 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2056 COPY_STRING(pName);
2057 COPY_STRING(pEnvironment);
2058 COPY_STRING(pDriverPath);
2059 COPY_STRING(pDataFile);
2060 COPY_STRING(pConfigFile);
2061 COPY_STRING(pHelpFile);
2062 COPY_MULTIZ_STRING(pDependentFiles);
2063 COPY_STRING(pMonitorName);
2064 COPY_STRING(pDefaultDataType);
2065 break;
2067 case 4:
2069 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2070 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2072 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2074 COPY_STRING(pName);
2075 COPY_STRING(pEnvironment);
2076 COPY_STRING(pDriverPath);
2077 COPY_STRING(pDataFile);
2078 COPY_STRING(pConfigFile);
2079 COPY_STRING(pHelpFile);
2080 COPY_MULTIZ_STRING(pDependentFiles);
2081 COPY_STRING(pMonitorName);
2082 COPY_STRING(pDefaultDataType);
2083 COPY_MULTIZ_STRING(pszzPreviousNames);
2084 break;
2086 case 5:
2088 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2089 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2091 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2093 COPY_STRING(pName);
2094 COPY_STRING(pEnvironment);
2095 COPY_STRING(pDriverPath);
2096 COPY_STRING(pDataFile);
2097 COPY_STRING(pConfigFile);
2098 break;
2100 case 6:
2102 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2103 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2105 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2107 COPY_STRING(pName);
2108 COPY_STRING(pEnvironment);
2109 COPY_STRING(pDriverPath);
2110 COPY_STRING(pDataFile);
2111 COPY_STRING(pConfigFile);
2112 COPY_STRING(pHelpFile);
2113 COPY_MULTIZ_STRING(pDependentFiles);
2114 COPY_STRING(pMonitorName);
2115 COPY_STRING(pDefaultDataType);
2116 COPY_MULTIZ_STRING(pszzPreviousNames);
2117 COPY_STRING(pszMfgName);
2118 COPY_STRING(pszOEMUrl);
2119 COPY_STRING(pszHardwareID);
2120 COPY_STRING(pszProvider);
2121 break;
2123 case 8:
2125 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2126 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2128 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2130 COPY_STRING(pName);
2131 COPY_STRING(pEnvironment);
2132 COPY_STRING(pDriverPath);
2133 COPY_STRING(pDataFile);
2134 COPY_STRING(pConfigFile);
2135 COPY_STRING(pHelpFile);
2136 COPY_MULTIZ_STRING(pDependentFiles);
2137 COPY_STRING(pMonitorName);
2138 COPY_STRING(pDefaultDataType);
2139 COPY_MULTIZ_STRING(pszzPreviousNames);
2140 COPY_STRING(pszMfgName);
2141 COPY_STRING(pszOEMUrl);
2142 COPY_STRING(pszHardwareID);
2143 COPY_STRING(pszProvider);
2144 COPY_STRING(pszPrintProcessor);
2145 COPY_STRING(pszVendorSetup);
2146 COPY_MULTIZ_STRING(pszzColorProfiles);
2147 COPY_STRING(pszInfPath);
2148 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2149 break;
2153 default:
2154 FIXME("for level %u\n", level);
2157 pDriversW += di_sizeof[level];
2158 out += di_sizeof[level];
2159 id++;
2162 #undef COPY_STRING
2163 #undef COPY_MULTIZ_STRING
2167 /***********************************************************
2168 * printer_info_AtoW
2170 static void *printer_info_AtoW( const void *data, DWORD level )
2172 void *ret;
2173 UNICODE_STRING usBuffer;
2175 if (!data) return NULL;
2177 if (level < 1 || level > 9) return NULL;
2179 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2180 if (!ret) return NULL;
2182 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2184 switch (level)
2186 case 2:
2188 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2189 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2191 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2192 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2193 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2194 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2195 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2196 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2197 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2198 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2199 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2200 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2201 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2202 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2203 break;
2206 case 8:
2207 case 9:
2209 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2210 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2212 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2213 break;
2216 default:
2217 FIXME( "Unhandled level %d\n", level );
2218 HeapFree( GetProcessHeap(), 0, ret );
2219 return NULL;
2222 return ret;
2225 /***********************************************************
2226 * free_printer_info
2228 static void free_printer_info( void *data, DWORD level )
2230 if (!data) return;
2232 switch (level)
2234 case 2:
2236 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2238 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2239 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2240 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2241 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2242 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2243 HeapFree( GetProcessHeap(), 0, piW->pComment );
2244 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2245 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2246 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2247 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2248 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2249 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2250 break;
2253 case 8:
2254 case 9:
2256 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2258 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2259 break;
2262 default:
2263 FIXME( "Unhandled level %d\n", level );
2266 HeapFree( GetProcessHeap(), 0, data );
2267 return;
2270 /******************************************************************
2271 * DeviceCapabilities [WINSPOOL.@]
2272 * DeviceCapabilitiesA [WINSPOOL.@]
2275 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2276 LPSTR pOutput, LPDEVMODEA lpdm)
2278 INT ret;
2280 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice), debugstr_a(pPort), cap, pOutput, lpdm);
2282 if (!GDI_CallDeviceCapabilities16)
2284 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2285 (LPCSTR)104 );
2286 if (!GDI_CallDeviceCapabilities16) return -1;
2288 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2290 /* If DC_PAPERSIZE map POINT16s to POINTs */
2291 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2292 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2293 POINT *pt = (POINT *)pOutput;
2294 INT i;
2295 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2296 for(i = 0; i < ret; i++, pt++)
2298 pt->x = tmp[i].x;
2299 pt->y = tmp[i].y;
2301 HeapFree( GetProcessHeap(), 0, tmp );
2303 return ret;
2307 /*****************************************************************************
2308 * DeviceCapabilitiesW [WINSPOOL.@]
2310 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2313 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2314 WORD fwCapability, LPWSTR pOutput,
2315 const DEVMODEW *pDevMode)
2317 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2318 LPSTR pDeviceA = strdupWtoA(pDevice);
2319 LPSTR pPortA = strdupWtoA(pPort);
2320 INT ret;
2322 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability, pOutput, pDevMode);
2324 if(pOutput && (fwCapability == DC_BINNAMES ||
2325 fwCapability == DC_FILEDEPENDENCIES ||
2326 fwCapability == DC_PAPERNAMES)) {
2327 /* These need A -> W translation */
2328 INT size = 0, i;
2329 LPSTR pOutputA;
2330 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2331 dmA);
2332 if(ret == -1)
2333 return ret;
2334 switch(fwCapability) {
2335 case DC_BINNAMES:
2336 size = 24;
2337 break;
2338 case DC_PAPERNAMES:
2339 case DC_FILEDEPENDENCIES:
2340 size = 64;
2341 break;
2343 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2344 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2345 dmA);
2346 for(i = 0; i < ret; i++)
2347 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2348 pOutput + (i * size), size);
2349 HeapFree(GetProcessHeap(), 0, pOutputA);
2350 } else {
2351 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2352 (LPSTR)pOutput, dmA);
2354 HeapFree(GetProcessHeap(),0,pPortA);
2355 HeapFree(GetProcessHeap(),0,pDeviceA);
2356 HeapFree(GetProcessHeap(),0,dmA);
2357 return ret;
2360 /******************************************************************
2361 * DocumentPropertiesA [WINSPOOL.@]
2363 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2365 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2366 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2367 LPDEVMODEA pDevModeInput,DWORD fMode )
2369 LPSTR lpName = pDeviceName, dupname = NULL;
2370 static CHAR port[] = "LPT1:";
2371 LONG ret;
2373 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2374 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2377 if(!pDeviceName || !*pDeviceName) {
2378 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2379 if(!lpNameW) {
2380 ERR("no name from hPrinter?\n");
2381 SetLastError(ERROR_INVALID_HANDLE);
2382 return -1;
2384 lpName = dupname = strdupWtoA(lpNameW);
2387 if (!GDI_CallExtDeviceMode16)
2389 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2390 (LPCSTR)102 );
2391 if (!GDI_CallExtDeviceMode16) {
2392 ERR("No CallExtDeviceMode16?\n");
2393 ret = -1;
2394 goto end;
2397 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2398 pDevModeInput, NULL, fMode);
2400 end:
2401 HeapFree(GetProcessHeap(), 0, dupname);
2402 return ret;
2406 /*****************************************************************************
2407 * DocumentPropertiesW (WINSPOOL.@)
2409 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2411 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2412 LPWSTR pDeviceName,
2413 LPDEVMODEW pDevModeOutput,
2414 LPDEVMODEW pDevModeInput, DWORD fMode)
2417 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2418 LPDEVMODEA pDevModeInputA;
2419 LPDEVMODEA pDevModeOutputA = NULL;
2420 LONG ret;
2422 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2423 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2424 fMode);
2425 if(pDevModeOutput) {
2426 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2427 if(ret < 0) return ret;
2428 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2430 pDevModeInputA = (fMode & DM_IN_BUFFER) ? DEVMODEdupWtoA(pDevModeInput) : NULL;
2431 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2432 pDevModeInputA, fMode);
2433 if(pDevModeOutput) {
2434 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2435 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2437 if(fMode == 0 && ret > 0)
2438 ret += (CCHDEVICENAME + CCHFORMNAME);
2439 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2440 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2441 return ret;
2444 /*****************************************************************************
2445 * IsValidDevmodeA [WINSPOOL.@]
2447 * Validate a DEVMODE structure and fix errors if possible.
2450 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2452 FIXME("(%p,%ld): stub\n", pDevMode, size);
2454 if(!pDevMode)
2455 return FALSE;
2457 return TRUE;
2460 /*****************************************************************************
2461 * IsValidDevmodeW [WINSPOOL.@]
2463 * Validate a DEVMODE structure and fix errors if possible.
2466 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2468 FIXME("(%p,%ld): stub\n", pDevMode, size);
2470 if(!pDevMode)
2471 return FALSE;
2473 return TRUE;
2476 /******************************************************************
2477 * OpenPrinterA [WINSPOOL.@]
2479 * See OpenPrinterW.
2482 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2483 LPPRINTER_DEFAULTSA pDefault)
2485 UNICODE_STRING lpPrinterNameW;
2486 UNICODE_STRING usBuffer;
2487 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2488 PWSTR pwstrPrinterNameW;
2489 BOOL ret;
2491 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName), phPrinter, pDefault);
2493 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2495 if(pDefault) {
2496 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2497 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2498 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2499 pDefaultW = &DefaultW;
2501 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2502 if(pDefault) {
2503 RtlFreeUnicodeString(&usBuffer);
2504 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2506 RtlFreeUnicodeString(&lpPrinterNameW);
2507 return ret;
2510 /******************************************************************
2511 * OpenPrinterW [WINSPOOL.@]
2513 * Open a Printer / Printserver or a Printer-Object
2515 * PARAMS
2516 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2517 * phPrinter [O] The resulting Handle is stored here
2518 * pDefault [I] PTR to Default Printer Settings or NULL
2520 * RETURNS
2521 * Success: TRUE
2522 * Failure: FALSE
2524 * NOTES
2525 * lpPrinterName is one of:
2526 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2527 *| Printer: "PrinterName"
2528 *| Printer-Object: "PrinterName,Job xxx"
2529 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2530 *| XcvPort: "Servername,XcvPort PortName"
2532 * BUGS
2533 *| Printer-Object not supported
2534 *| pDefaults is ignored
2537 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2539 HKEY key;
2541 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2543 if(!phPrinter) {
2544 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2545 SetLastError(ERROR_INVALID_PARAMETER);
2546 return FALSE;
2549 /* Get the unique handle of the printer or Printserver */
2550 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2552 if (*phPrinter && WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key ) == ERROR_SUCCESS)
2554 DWORD deleting = 0, size = sizeof( deleting ), type;
2555 DWORD status;
2556 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2557 WaitForSingleObject( init_mutex, INFINITE );
2558 status = get_dword_from_reg( key, StatusW );
2559 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2560 ReleaseMutex( init_mutex );
2561 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2562 update_driver( *phPrinter );
2563 RegCloseKey( key );
2566 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2567 return (*phPrinter != 0);
2570 /******************************************************************
2571 * AddMonitorA [WINSPOOL.@]
2573 * See AddMonitorW.
2576 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2578 LPWSTR nameW = NULL;
2579 INT len;
2580 BOOL res;
2581 LPMONITOR_INFO_2A mi2a;
2582 MONITOR_INFO_2W mi2w;
2584 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2585 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2586 debugstr_a(mi2a ? mi2a->pName : NULL),
2587 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2588 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2590 if (Level != 2) {
2591 SetLastError(ERROR_INVALID_LEVEL);
2592 return FALSE;
2595 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2596 if (mi2a == NULL) {
2597 return FALSE;
2600 if (pName) {
2601 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2602 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2603 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2606 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2607 if (mi2a->pName) {
2608 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2609 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2610 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2612 if (mi2a->pEnvironment) {
2613 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2614 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2615 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2617 if (mi2a->pDLLName) {
2618 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2619 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2620 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2623 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2625 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2626 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2627 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2629 HeapFree(GetProcessHeap(), 0, nameW);
2630 return (res);
2633 /******************************************************************************
2634 * AddMonitorW [WINSPOOL.@]
2636 * Install a Printmonitor
2638 * PARAMS
2639 * pName [I] Servername or NULL (local Computer)
2640 * Level [I] Structure-Level (Must be 2)
2641 * pMonitors [I] PTR to MONITOR_INFO_2
2643 * RETURNS
2644 * Success: TRUE
2645 * Failure: FALSE
2647 * NOTES
2648 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2651 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2653 LPMONITOR_INFO_2W mi2w;
2655 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2656 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2657 debugstr_w(mi2w ? mi2w->pName : NULL),
2658 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2659 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2661 if ((backend == NULL) && !load_backend()) return FALSE;
2663 if (Level != 2) {
2664 SetLastError(ERROR_INVALID_LEVEL);
2665 return FALSE;
2668 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2669 if (mi2w == NULL) {
2670 return FALSE;
2673 return backend->fpAddMonitor(pName, Level, pMonitors);
2676 /******************************************************************
2677 * DeletePrinterDriverA [WINSPOOL.@]
2680 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2682 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2685 /******************************************************************
2686 * DeletePrinterDriverW [WINSPOOL.@]
2689 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2691 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2694 /******************************************************************
2695 * DeleteMonitorA [WINSPOOL.@]
2697 * See DeleteMonitorW.
2700 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2702 LPWSTR nameW = NULL;
2703 LPWSTR EnvironmentW = NULL;
2704 LPWSTR MonitorNameW = NULL;
2705 BOOL res;
2706 INT len;
2708 if (pName) {
2709 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2710 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2711 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2714 if (pEnvironment) {
2715 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2716 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2717 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2719 if (pMonitorName) {
2720 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2721 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2722 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2725 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2727 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2728 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2729 HeapFree(GetProcessHeap(), 0, nameW);
2730 return (res);
2733 /******************************************************************
2734 * DeleteMonitorW [WINSPOOL.@]
2736 * Delete a specific Printmonitor from a Printing-Environment
2738 * PARAMS
2739 * pName [I] Servername or NULL (local Computer)
2740 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2741 * pMonitorName [I] Name of the Monitor, that should be deleted
2743 * RETURNS
2744 * Success: TRUE
2745 * Failure: FALSE
2747 * NOTES
2748 * pEnvironment is ignored in Windows for the local Computer.
2751 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2754 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2755 debugstr_w(pMonitorName));
2757 if ((backend == NULL) && !load_backend()) return FALSE;
2759 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2763 /******************************************************************
2764 * DeletePortA [WINSPOOL.@]
2766 * See DeletePortW.
2769 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2771 LPWSTR nameW = NULL;
2772 LPWSTR portW = NULL;
2773 INT len;
2774 DWORD res;
2776 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2778 /* convert servername to unicode */
2779 if (pName) {
2780 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2781 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2782 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2785 /* convert portname to unicode */
2786 if (pPortName) {
2787 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2788 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2789 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2792 res = DeletePortW(nameW, hWnd, portW);
2793 HeapFree(GetProcessHeap(), 0, nameW);
2794 HeapFree(GetProcessHeap(), 0, portW);
2795 return res;
2798 /******************************************************************
2799 * DeletePortW [WINSPOOL.@]
2801 * Delete a specific Port
2803 * PARAMS
2804 * pName [I] Servername or NULL (local Computer)
2805 * hWnd [I] Handle to parent Window for the Dialog-Box
2806 * pPortName [I] Name of the Port, that should be deleted
2808 * RETURNS
2809 * Success: TRUE
2810 * Failure: FALSE
2813 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2815 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2817 if ((backend == NULL) && !load_backend()) return FALSE;
2819 if (!pPortName) {
2820 SetLastError(RPC_X_NULL_REF_POINTER);
2821 return FALSE;
2824 return backend->fpDeletePort(pName, hWnd, pPortName);
2827 /******************************************************************************
2828 * WritePrinter [WINSPOOL.@]
2830 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2832 opened_printer_t *printer;
2833 BOOL ret = FALSE;
2835 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2837 EnterCriticalSection(&printer_handles_cs);
2838 printer = get_opened_printer(hPrinter);
2839 if(!printer)
2841 SetLastError(ERROR_INVALID_HANDLE);
2842 goto end;
2845 if(!printer->doc)
2847 SetLastError(ERROR_SPL_NO_STARTDOC);
2848 goto end;
2851 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2852 end:
2853 LeaveCriticalSection(&printer_handles_cs);
2854 return ret;
2857 /*****************************************************************************
2858 * AddFormA [WINSPOOL.@]
2860 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2862 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2863 return TRUE;
2866 /*****************************************************************************
2867 * AddFormW [WINSPOOL.@]
2869 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2871 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2872 return TRUE;
2875 /*****************************************************************************
2876 * AddJobA [WINSPOOL.@]
2878 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2880 BOOL ret;
2881 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2882 DWORD needed;
2884 if(Level != 1) {
2885 SetLastError(ERROR_INVALID_LEVEL);
2886 return FALSE;
2889 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2891 if(ret) {
2892 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2893 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2894 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2895 if(*pcbNeeded > cbBuf) {
2896 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2897 ret = FALSE;
2898 } else {
2899 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2900 addjobA->JobId = addjobW->JobId;
2901 addjobA->Path = (char *)(addjobA + 1);
2902 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2905 return ret;
2908 /*****************************************************************************
2909 * AddJobW [WINSPOOL.@]
2911 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2913 opened_printer_t *printer;
2914 job_t *job;
2915 BOOL ret = FALSE;
2916 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2917 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2918 WCHAR path[MAX_PATH], filename[MAX_PATH];
2919 DWORD len;
2920 ADDJOB_INFO_1W *addjob;
2922 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2924 EnterCriticalSection(&printer_handles_cs);
2926 printer = get_opened_printer(hPrinter);
2928 if(!printer) {
2929 SetLastError(ERROR_INVALID_HANDLE);
2930 goto end;
2933 if(Level != 1) {
2934 SetLastError(ERROR_INVALID_LEVEL);
2935 goto end;
2938 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2939 if(!job)
2940 goto end;
2942 job->job_id = InterlockedIncrement(&next_job_id);
2944 len = GetSystemDirectoryW(path, ARRAY_SIZE(path));
2945 if(path[len - 1] != '\\')
2946 path[len++] = '\\';
2947 memcpy(path + len, spool_path, sizeof(spool_path));
2948 sprintfW(filename, fmtW, path, job->job_id);
2950 len = strlenW(filename);
2951 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2952 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2953 job->portname = NULL;
2954 job->document_title = strdupW(default_doc_title);
2955 job->printer_name = strdupW(printer->name);
2956 job->devmode = dup_devmode( printer->devmode );
2957 list_add_tail(&printer->queue->jobs, &job->entry);
2959 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2960 if(*pcbNeeded <= cbBuf) {
2961 addjob = (ADDJOB_INFO_1W*)pData;
2962 addjob->JobId = job->job_id;
2963 addjob->Path = (WCHAR *)(addjob + 1);
2964 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2965 ret = TRUE;
2966 } else
2967 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2969 end:
2970 LeaveCriticalSection(&printer_handles_cs);
2971 return ret;
2974 /*****************************************************************************
2975 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2977 * Return the PATH for the Print-Processors
2979 * See GetPrintProcessorDirectoryW.
2983 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2984 DWORD level, LPBYTE Info,
2985 DWORD cbBuf, LPDWORD pcbNeeded)
2987 LPWSTR serverW = NULL;
2988 LPWSTR envW = NULL;
2989 BOOL ret;
2990 INT len;
2992 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2993 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2996 if (server) {
2997 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2998 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2999 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
3002 if (env) {
3003 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
3004 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3005 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
3008 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
3009 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
3011 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
3012 cbBuf, pcbNeeded);
3014 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
3015 cbBuf, NULL, NULL) > 0;
3018 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3019 HeapFree(GetProcessHeap(), 0, envW);
3020 HeapFree(GetProcessHeap(), 0, serverW);
3021 return ret;
3024 /*****************************************************************************
3025 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3027 * Return the PATH for the Print-Processors
3029 * PARAMS
3030 * server [I] Servername (NT only) or NULL (local Computer)
3031 * env [I] Printing-Environment (see below) or NULL (Default)
3032 * level [I] Structure-Level (must be 1)
3033 * Info [O] PTR to Buffer that receives the Result
3034 * cbBuf [I] Size of Buffer at "Info"
3035 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3036 * required for the Buffer at "Info"
3038 * RETURNS
3039 * Success: TRUE and in pcbNeeded the Bytes used in Info
3040 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3041 * if cbBuf is too small
3043 * Native Values returned in Info on Success:
3044 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3045 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3046 *| win9x(Windows 4.0): "%winsysdir%"
3048 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3050 * BUGS
3051 * Only NULL or "" is supported for server
3054 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3055 DWORD level, LPBYTE Info,
3056 DWORD cbBuf, LPDWORD pcbNeeded)
3059 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3060 Info, cbBuf, pcbNeeded);
3062 if ((backend == NULL) && !load_backend()) return FALSE;
3064 if (level != 1) {
3065 /* (Level != 1) is ignored in win9x */
3066 SetLastError(ERROR_INVALID_LEVEL);
3067 return FALSE;
3070 if (pcbNeeded == NULL) {
3071 /* (pcbNeeded == NULL) is ignored in win9x */
3072 SetLastError(RPC_X_NULL_REF_POINTER);
3073 return FALSE;
3076 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3079 /*****************************************************************************
3080 * WINSPOOL_OpenDriverReg [internal]
3082 * opens the registry for the printer drivers depending on the given input
3083 * variable pEnvironment
3085 * RETURNS:
3086 * the opened hkey on success
3087 * NULL on error
3089 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3091 HKEY retval = NULL;
3092 LPWSTR buffer;
3093 const printenv_t * env;
3095 TRACE("(%s)\n", debugstr_w(pEnvironment));
3097 env = validate_envW(pEnvironment);
3098 if (!env) return NULL;
3100 buffer = HeapAlloc( GetProcessHeap(), 0,
3101 (strlenW(DriversW) + strlenW(env->envname) +
3102 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3103 if(buffer) {
3104 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3105 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3106 HeapFree(GetProcessHeap(), 0, buffer);
3108 return retval;
3111 /*****************************************************************************
3112 * set_devices_and_printerports [internal]
3114 * set the [Devices] and [PrinterPorts] entries for a printer.
3117 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3119 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3120 WCHAR *devline;
3121 HKEY hkey;
3123 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3125 /* FIXME: the driver must change to "winspool" */
3126 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3127 if (devline) {
3128 lstrcpyW(devline, driver_nt);
3129 lstrcatW(devline, commaW);
3130 lstrcatW(devline, pi->pPortName);
3132 TRACE("using %s\n", debugstr_w(devline));
3133 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
3134 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3135 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3136 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3137 RegCloseKey(hkey);
3140 lstrcatW(devline, timeout_15_45);
3141 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
3142 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3143 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3144 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3145 RegCloseKey(hkey);
3147 HeapFree(GetProcessHeap(), 0, devline);
3151 /*****************************************************************************
3152 * AddPrinterW [WINSPOOL.@]
3154 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3156 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3157 LPDEVMODEW dm;
3158 HANDLE retval;
3159 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3160 LONG size;
3162 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3164 if(pName && *pName) {
3165 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3166 SetLastError(ERROR_INVALID_PARAMETER);
3167 return 0;
3169 if(Level != 2) {
3170 ERR("Level = %d, unsupported!\n", Level);
3171 SetLastError(ERROR_INVALID_LEVEL);
3172 return 0;
3174 if(!pPrinter) {
3175 SetLastError(ERROR_INVALID_PARAMETER);
3176 return 0;
3178 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3179 ERROR_SUCCESS) {
3180 ERR("Can't create Printers key\n");
3181 return 0;
3183 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3184 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3185 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3186 RegCloseKey(hkeyPrinter);
3187 RegCloseKey(hkeyPrinters);
3188 return 0;
3190 RegCloseKey(hkeyPrinter);
3192 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3193 if(!hkeyDrivers) {
3194 ERR("Can't create Drivers key\n");
3195 RegCloseKey(hkeyPrinters);
3196 return 0;
3198 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3199 ERROR_SUCCESS) {
3200 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3201 RegCloseKey(hkeyPrinters);
3202 RegCloseKey(hkeyDrivers);
3203 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3204 return 0;
3206 RegCloseKey(hkeyDriver);
3207 RegCloseKey(hkeyDrivers);
3209 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3210 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3211 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3212 RegCloseKey(hkeyPrinters);
3213 return 0;
3216 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3217 ERROR_SUCCESS) {
3218 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3219 SetLastError(ERROR_INVALID_PRINTER_NAME);
3220 RegCloseKey(hkeyPrinters);
3221 return 0;
3224 set_devices_and_printerports(pi);
3226 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3227 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3228 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3229 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3230 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3231 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3232 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3233 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3234 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3235 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3236 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3237 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3238 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3239 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3240 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3241 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3242 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3243 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3245 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3247 if (size < 0)
3249 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3250 size = sizeof(DEVMODEW);
3252 if(pi->pDevMode)
3253 dm = pi->pDevMode;
3254 else
3256 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3257 dm->dmSize = size;
3258 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3260 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3261 HeapFree( GetProcessHeap(), 0, dm );
3262 dm = NULL;
3264 else
3266 /* set devmode to printer name */
3267 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3271 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3272 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3274 RegCloseKey(hkeyPrinter);
3275 RegCloseKey(hkeyPrinters);
3276 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3277 ERR("OpenPrinter failing\n");
3278 return 0;
3280 return retval;
3283 /*****************************************************************************
3284 * AddPrinterA [WINSPOOL.@]
3286 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3288 UNICODE_STRING pNameW;
3289 PWSTR pwstrNameW;
3290 PRINTER_INFO_2W *piW;
3291 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3292 HANDLE ret;
3294 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3295 if(Level != 2) {
3296 ERR("Level = %d, unsupported!\n", Level);
3297 SetLastError(ERROR_INVALID_LEVEL);
3298 return 0;
3300 pwstrNameW = asciitounicode(&pNameW,pName);
3301 piW = printer_info_AtoW( piA, Level );
3303 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3305 free_printer_info( piW, Level );
3306 RtlFreeUnicodeString(&pNameW);
3307 return ret;
3311 /*****************************************************************************
3312 * ClosePrinter [WINSPOOL.@]
3314 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3316 UINT_PTR i = (UINT_PTR)hPrinter;
3317 opened_printer_t *printer = NULL;
3319 TRACE("(%p)\n", hPrinter);
3321 EnterCriticalSection(&printer_handles_cs);
3323 if ((i > 0) && (i <= nb_printer_handles))
3324 printer = printer_handles[i - 1];
3327 if(printer)
3329 struct list *cursor, *cursor2;
3331 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3333 if(printer->doc)
3334 EndDocPrinter(hPrinter);
3336 if(InterlockedDecrement(&printer->queue->ref) == 0)
3338 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3340 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3341 ScheduleJob(hPrinter, job->job_id);
3343 HeapFree(GetProcessHeap(), 0, printer->queue);
3346 if (printer->backend_printer) {
3347 backend->fpClosePrinter(printer->backend_printer);
3350 free_printer_entry( printer );
3351 printer_handles[i - 1] = NULL;
3352 LeaveCriticalSection(&printer_handles_cs);
3353 return TRUE;
3356 LeaveCriticalSection(&printer_handles_cs);
3357 SetLastError(ERROR_INVALID_HANDLE);
3358 return FALSE;
3361 /*****************************************************************************
3362 * DeleteFormA [WINSPOOL.@]
3364 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3366 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3367 return TRUE;
3370 /*****************************************************************************
3371 * DeleteFormW [WINSPOOL.@]
3373 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3375 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3376 return TRUE;
3379 /*****************************************************************************
3380 * DeletePrinter [WINSPOOL.@]
3382 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3384 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3385 HKEY hkeyPrinters, hkey;
3386 WCHAR def[MAX_PATH];
3387 DWORD size = ARRAY_SIZE(def);
3389 if(!lpNameW) {
3390 SetLastError(ERROR_INVALID_HANDLE);
3391 return FALSE;
3393 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3394 RegDeleteTreeW(hkeyPrinters, lpNameW);
3395 RegCloseKey(hkeyPrinters);
3397 WriteProfileStringW(devicesW, lpNameW, NULL);
3398 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3400 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3401 RegDeleteValueW(hkey, lpNameW);
3402 RegCloseKey(hkey);
3405 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3406 RegDeleteValueW(hkey, lpNameW);
3407 RegCloseKey(hkey);
3410 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3412 WriteProfileStringW( windowsW, deviceW, NULL );
3413 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3415 RegDeleteValueW( hkey, deviceW );
3416 RegCloseKey( hkey );
3418 SetDefaultPrinterW( NULL );
3421 return TRUE;
3424 /*****************************************************************************
3425 * SetPrinterA [WINSPOOL.@]
3427 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3429 BYTE *dataW = data;
3430 BOOL ret;
3432 if (level != 0)
3434 dataW = printer_info_AtoW( data, level );
3435 if (!dataW) return FALSE;
3438 ret = SetPrinterW( printer, level, dataW, command );
3440 if (dataW != data) free_printer_info( dataW, level );
3442 return ret;
3445 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3447 set_reg_szW( key, NameW, pi->pPrinterName );
3448 set_reg_szW( key, Share_NameW, pi->pShareName );
3449 set_reg_szW( key, PortW, pi->pPortName );
3450 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3451 set_reg_szW( key, DescriptionW, pi->pComment );
3452 set_reg_szW( key, LocationW, pi->pLocation );
3454 if (pi->pDevMode)
3455 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3457 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3458 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3459 set_reg_szW( key, DatatypeW, pi->pDatatype );
3460 set_reg_szW( key, ParametersW, pi->pParameters );
3462 set_reg_DWORD( key, AttributesW, pi->Attributes );
3463 set_reg_DWORD( key, PriorityW, pi->Priority );
3464 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3465 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3466 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3469 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3471 if (!pi->pDevMode) return FALSE;
3473 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3474 return TRUE;
3477 /******************************************************************************
3478 * SetPrinterW [WINSPOOL.@]
3480 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3482 HKEY key;
3483 BOOL ret = FALSE;
3485 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3487 if (command != 0) FIXME( "Ignoring command %d\n", command );
3489 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3490 return FALSE;
3492 switch (level)
3494 case 2:
3496 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3497 set_printer_2( key, pi2 );
3498 ret = TRUE;
3499 break;
3502 case 8:
3503 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
3504 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3505 /* fall through */
3506 case 9:
3508 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3509 ret = set_printer_9( key, pi );
3510 break;
3513 default:
3514 FIXME( "Unimplemented level %d\n", level );
3515 SetLastError( ERROR_INVALID_LEVEL );
3518 RegCloseKey( key );
3519 return ret;
3522 /*****************************************************************************
3523 * SetJobA [WINSPOOL.@]
3525 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3526 LPBYTE pJob, DWORD Command)
3528 BOOL ret;
3529 LPBYTE JobW;
3530 UNICODE_STRING usBuffer;
3532 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3534 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3535 are all ignored by SetJob, so we don't bother copying them */
3536 switch(Level)
3538 case 0:
3539 JobW = NULL;
3540 break;
3541 case 1:
3543 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3544 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3546 JobW = (LPBYTE)info1W;
3547 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3548 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3549 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3550 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3551 info1W->Status = info1A->Status;
3552 info1W->Priority = info1A->Priority;
3553 info1W->Position = info1A->Position;
3554 info1W->PagesPrinted = info1A->PagesPrinted;
3555 break;
3557 case 2:
3559 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3560 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3562 JobW = (LPBYTE)info2W;
3563 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3564 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3565 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3566 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3567 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3568 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3569 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3570 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3571 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3572 info2W->Status = info2A->Status;
3573 info2W->Priority = info2A->Priority;
3574 info2W->Position = info2A->Position;
3575 info2W->StartTime = info2A->StartTime;
3576 info2W->UntilTime = info2A->UntilTime;
3577 info2W->PagesPrinted = info2A->PagesPrinted;
3578 break;
3580 case 3:
3581 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3582 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3583 break;
3584 default:
3585 SetLastError(ERROR_INVALID_LEVEL);
3586 return FALSE;
3589 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3591 switch(Level)
3593 case 1:
3595 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3596 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3597 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3598 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3599 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3600 break;
3602 case 2:
3604 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3605 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3606 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3607 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3608 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3609 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3610 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3611 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3612 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3613 break;
3616 HeapFree(GetProcessHeap(), 0, JobW);
3618 return ret;
3621 /*****************************************************************************
3622 * SetJobW [WINSPOOL.@]
3624 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3625 LPBYTE pJob, DWORD Command)
3627 BOOL ret = FALSE;
3628 job_t *job;
3630 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3631 FIXME("Ignoring everything other than document title\n");
3633 EnterCriticalSection(&printer_handles_cs);
3634 job = get_job(hPrinter, JobId);
3635 if(!job)
3636 goto end;
3638 switch(Level)
3640 case 0:
3641 break;
3642 case 1:
3644 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3645 HeapFree(GetProcessHeap(), 0, job->document_title);
3646 job->document_title = strdupW(info1->pDocument);
3647 break;
3649 case 2:
3651 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3652 HeapFree(GetProcessHeap(), 0, job->document_title);
3653 job->document_title = strdupW(info2->pDocument);
3654 HeapFree(GetProcessHeap(), 0, job->devmode);
3655 job->devmode = dup_devmode( info2->pDevMode );
3656 break;
3658 case 3:
3659 break;
3660 default:
3661 SetLastError(ERROR_INVALID_LEVEL);
3662 goto end;
3664 ret = TRUE;
3665 end:
3666 LeaveCriticalSection(&printer_handles_cs);
3667 return ret;
3670 /*****************************************************************************
3671 * EndDocPrinter [WINSPOOL.@]
3673 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3675 opened_printer_t *printer;
3676 BOOL ret = FALSE;
3677 TRACE("(%p)\n", hPrinter);
3679 EnterCriticalSection(&printer_handles_cs);
3681 printer = get_opened_printer(hPrinter);
3682 if(!printer)
3684 SetLastError(ERROR_INVALID_HANDLE);
3685 goto end;
3688 if(!printer->doc)
3690 SetLastError(ERROR_SPL_NO_STARTDOC);
3691 goto end;
3694 CloseHandle(printer->doc->hf);
3695 ScheduleJob(hPrinter, printer->doc->job_id);
3696 HeapFree(GetProcessHeap(), 0, printer->doc);
3697 printer->doc = NULL;
3698 ret = TRUE;
3699 end:
3700 LeaveCriticalSection(&printer_handles_cs);
3701 return ret;
3704 /*****************************************************************************
3705 * EndPagePrinter [WINSPOOL.@]
3707 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3709 FIXME("(%p): stub\n", hPrinter);
3710 return TRUE;
3713 /*****************************************************************************
3714 * StartDocPrinterA [WINSPOOL.@]
3716 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3718 UNICODE_STRING usBuffer;
3719 DOC_INFO_2W doc2W;
3720 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3721 DWORD ret;
3723 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3724 or one (DOC_INFO_3) extra DWORDs */
3726 switch(Level) {
3727 case 2:
3728 doc2W.JobId = doc2->JobId;
3729 /* fall through */
3730 case 3:
3731 doc2W.dwMode = doc2->dwMode;
3732 /* fall through */
3733 case 1:
3734 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3735 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3736 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3737 break;
3739 default:
3740 SetLastError(ERROR_INVALID_LEVEL);
3741 return FALSE;
3744 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3746 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3747 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3748 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3750 return ret;
3753 /*****************************************************************************
3754 * StartDocPrinterW [WINSPOOL.@]
3756 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3758 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3759 opened_printer_t *printer;
3760 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3761 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3762 JOB_INFO_1W job_info;
3763 DWORD needed, ret = 0;
3764 HANDLE hf;
3765 WCHAR *filename;
3766 job_t *job;
3768 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3769 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3770 debugstr_w(doc->pDatatype));
3772 if(Level < 1 || Level > 3)
3774 SetLastError(ERROR_INVALID_LEVEL);
3775 return 0;
3778 EnterCriticalSection(&printer_handles_cs);
3779 printer = get_opened_printer(hPrinter);
3780 if(!printer)
3782 SetLastError(ERROR_INVALID_HANDLE);
3783 goto end;
3786 if(printer->doc)
3788 SetLastError(ERROR_INVALID_PRINTER_STATE);
3789 goto end;
3792 /* Even if we're printing to a file we still add a print job, we'll
3793 just ignore the spool file name */
3795 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3797 ERR("AddJob failed gle %u\n", GetLastError());
3798 goto end;
3801 /* use pOutputFile only, when it is a real filename */
3802 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3803 filename = doc->pOutputFile;
3804 else
3805 filename = addjob->Path;
3807 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3808 if(hf == INVALID_HANDLE_VALUE)
3809 goto end;
3811 memset(&job_info, 0, sizeof(job_info));
3812 job_info.pDocument = doc->pDocName;
3813 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3815 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3816 printer->doc->hf = hf;
3817 ret = printer->doc->job_id = addjob->JobId;
3818 job = get_job(hPrinter, ret);
3819 job->portname = strdupW(doc->pOutputFile);
3821 end:
3822 LeaveCriticalSection(&printer_handles_cs);
3824 return ret;
3827 /*****************************************************************************
3828 * StartPagePrinter [WINSPOOL.@]
3830 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3832 FIXME("(%p): stub\n", hPrinter);
3833 return TRUE;
3836 /*****************************************************************************
3837 * GetFormA [WINSPOOL.@]
3839 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3840 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3842 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3843 Level,pForm,cbBuf,pcbNeeded);
3844 return FALSE;
3847 /*****************************************************************************
3848 * GetFormW [WINSPOOL.@]
3850 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3851 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3853 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3854 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3855 return FALSE;
3858 /*****************************************************************************
3859 * SetFormA [WINSPOOL.@]
3861 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3862 LPBYTE pForm)
3864 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3865 return FALSE;
3868 /*****************************************************************************
3869 * SetFormW [WINSPOOL.@]
3871 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3872 LPBYTE pForm)
3874 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3875 return FALSE;
3878 /*****************************************************************************
3879 * ReadPrinter [WINSPOOL.@]
3881 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3882 LPDWORD pNoBytesRead)
3884 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3885 return FALSE;
3888 /*****************************************************************************
3889 * ResetPrinterA [WINSPOOL.@]
3891 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3893 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3894 return FALSE;
3897 /*****************************************************************************
3898 * ResetPrinterW [WINSPOOL.@]
3900 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3902 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3903 return FALSE;
3906 /*****************************************************************************
3907 * get_filename_from_reg [internal]
3909 * Get ValueName from hkey storing result in out
3910 * when the Value in the registry has only a filename, use driverdir as prefix
3911 * outlen is space left in out
3912 * String is stored either as unicode or ascii
3916 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3917 LPBYTE out, DWORD outlen, LPDWORD needed)
3919 WCHAR filename[MAX_PATH];
3920 DWORD size;
3921 DWORD type;
3922 LONG ret;
3923 LPWSTR buffer = filename;
3924 LPWSTR ptr;
3926 *needed = 0;
3927 size = sizeof(filename);
3928 buffer[0] = '\0';
3929 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3930 if (ret == ERROR_MORE_DATA) {
3931 TRACE("need dynamic buffer: %u\n", size);
3932 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3933 if (!buffer) {
3934 /* No Memory is bad */
3935 return FALSE;
3937 buffer[0] = '\0';
3938 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3941 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3942 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3943 return FALSE;
3946 ptr = buffer;
3947 while (ptr) {
3948 /* do we have a full path ? */
3949 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3950 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3952 if (!ret) {
3953 /* we must build the full Path */
3954 *needed += dirlen;
3955 if ((out) && (outlen > dirlen)) {
3956 lstrcpyW((LPWSTR)out, driverdir);
3957 out += dirlen;
3958 outlen -= dirlen;
3960 else
3961 out = NULL;
3964 /* write the filename */
3965 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3966 if ((out) && (outlen >= size)) {
3967 lstrcpyW((LPWSTR)out, ptr);
3968 out += size;
3969 outlen -= size;
3971 else
3972 out = NULL;
3973 *needed += size;
3974 ptr += lstrlenW(ptr)+1;
3975 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3978 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3980 /* write the multisz-termination */
3981 if (type == REG_MULTI_SZ) {
3982 size = sizeof(WCHAR);
3984 *needed += size;
3985 if (out && (outlen >= size)) {
3986 memset (out, 0, size);
3989 return TRUE;
3992 /*****************************************************************************
3993 * WINSPOOL_GetStringFromReg
3995 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3996 * String is stored as unicode.
3998 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3999 DWORD buflen, DWORD *needed)
4001 DWORD sz = buflen, type;
4002 LONG ret;
4004 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4005 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
4006 WARN("Got ret = %d\n", ret);
4007 *needed = 0;
4008 return FALSE;
4010 /* add space for terminating '\0' */
4011 sz += sizeof(WCHAR);
4012 *needed = sz;
4014 if (ptr)
4015 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
4017 return TRUE;
4020 /*****************************************************************************
4021 * WINSPOOL_GetDefaultDevMode
4023 * Get a default DevMode values for wineps.
4025 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr, DWORD buflen, DWORD *needed)
4027 static const WCHAR winepsW[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4029 if (buflen >= sizeof(DEVMODEW))
4031 DEVMODEW *dm = (DEVMODEW *)ptr;
4033 /* the driver will update registry with real values */
4034 memset(dm, 0, sizeof(*dm));
4035 dm->dmSize = sizeof(*dm);
4036 lstrcpyW(dm->dmDeviceName, winepsW);
4038 *needed = sizeof(DEVMODEW);
4041 /*****************************************************************************
4042 * WINSPOOL_GetDevModeFromReg
4044 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4045 * DevMode is stored either as unicode or ascii.
4047 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4048 LPBYTE ptr,
4049 DWORD buflen, DWORD *needed)
4051 DWORD sz = buflen, type;
4052 LONG ret;
4054 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4055 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4056 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4057 if (sz < sizeof(DEVMODEA))
4059 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4060 return FALSE;
4062 /* ensures that dmSize is not erratically bogus if registry is invalid */
4063 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4064 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4065 sz += (CCHDEVICENAME + CCHFORMNAME);
4066 if (ptr && (buflen >= sz)) {
4067 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4068 memcpy(ptr, dmW, sz);
4069 HeapFree(GetProcessHeap(),0,dmW);
4071 *needed = sz;
4072 return TRUE;
4075 /*********************************************************************
4076 * WINSPOOL_GetPrinter_1
4078 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4080 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4081 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4083 DWORD size, left = cbBuf;
4084 BOOL space = (cbBuf > 0);
4085 LPBYTE ptr = buf;
4087 *pcbNeeded = 0;
4089 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4090 if(space && size <= left) {
4091 pi1->pName = (LPWSTR)ptr;
4092 ptr += size;
4093 left -= size;
4094 } else
4095 space = FALSE;
4096 *pcbNeeded += size;
4099 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4100 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4101 if(space && size <= left) {
4102 pi1->pDescription = (LPWSTR)ptr;
4103 ptr += size;
4104 left -= size;
4105 } else
4106 space = FALSE;
4107 *pcbNeeded += size;
4110 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4111 if(space && size <= left) {
4112 pi1->pComment = (LPWSTR)ptr;
4113 ptr += size;
4114 left -= size;
4115 } else
4116 space = FALSE;
4117 *pcbNeeded += size;
4120 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4122 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4123 memset(pi1, 0, sizeof(*pi1));
4125 return space;
4127 /*********************************************************************
4128 * WINSPOOL_GetPrinter_2
4130 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4132 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4133 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4135 DWORD size, left = cbBuf;
4136 BOOL space = (cbBuf > 0);
4137 LPBYTE ptr = buf;
4139 *pcbNeeded = 0;
4141 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4142 if(space && size <= left) {
4143 pi2->pPrinterName = (LPWSTR)ptr;
4144 ptr += size;
4145 left -= size;
4146 } else
4147 space = FALSE;
4148 *pcbNeeded += size;
4150 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4151 if(space && size <= left) {
4152 pi2->pShareName = (LPWSTR)ptr;
4153 ptr += size;
4154 left -= size;
4155 } else
4156 space = FALSE;
4157 *pcbNeeded += size;
4159 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4160 if(space && size <= left) {
4161 pi2->pPortName = (LPWSTR)ptr;
4162 ptr += size;
4163 left -= size;
4164 } else
4165 space = FALSE;
4166 *pcbNeeded += size;
4168 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4169 if(space && size <= left) {
4170 pi2->pDriverName = (LPWSTR)ptr;
4171 ptr += size;
4172 left -= size;
4173 } else
4174 space = FALSE;
4175 *pcbNeeded += size;
4177 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4178 if(space && size <= left) {
4179 pi2->pComment = (LPWSTR)ptr;
4180 ptr += size;
4181 left -= size;
4182 } else
4183 space = FALSE;
4184 *pcbNeeded += size;
4186 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4187 if(space && size <= left) {
4188 pi2->pLocation = (LPWSTR)ptr;
4189 ptr += size;
4190 left -= size;
4191 } else
4192 space = FALSE;
4193 *pcbNeeded += size;
4195 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4196 if(space && size <= left) {
4197 pi2->pDevMode = (LPDEVMODEW)ptr;
4198 ptr += size;
4199 left -= size;
4200 } else
4201 space = FALSE;
4202 *pcbNeeded += size;
4204 else
4206 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4207 if(space && size <= left) {
4208 pi2->pDevMode = (LPDEVMODEW)ptr;
4209 ptr += size;
4210 left -= size;
4211 } else
4212 space = FALSE;
4213 *pcbNeeded += size;
4215 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4216 if(space && size <= left) {
4217 pi2->pSepFile = (LPWSTR)ptr;
4218 ptr += size;
4219 left -= size;
4220 } else
4221 space = FALSE;
4222 *pcbNeeded += size;
4224 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4225 if(space && size <= left) {
4226 pi2->pPrintProcessor = (LPWSTR)ptr;
4227 ptr += size;
4228 left -= size;
4229 } else
4230 space = FALSE;
4231 *pcbNeeded += size;
4233 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4234 if(space && size <= left) {
4235 pi2->pDatatype = (LPWSTR)ptr;
4236 ptr += size;
4237 left -= size;
4238 } else
4239 space = FALSE;
4240 *pcbNeeded += size;
4242 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4243 if(space && size <= left) {
4244 pi2->pParameters = (LPWSTR)ptr;
4245 ptr += size;
4246 left -= size;
4247 } else
4248 space = FALSE;
4249 *pcbNeeded += size;
4251 if(pi2) {
4252 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4253 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4254 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4255 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4256 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4259 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4260 memset(pi2, 0, sizeof(*pi2));
4262 return space;
4265 /*********************************************************************
4266 * WINSPOOL_GetPrinter_4
4268 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4270 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4271 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4273 DWORD size, left = cbBuf;
4274 BOOL space = (cbBuf > 0);
4275 LPBYTE ptr = buf;
4277 *pcbNeeded = 0;
4279 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4280 if(space && size <= left) {
4281 pi4->pPrinterName = (LPWSTR)ptr;
4282 ptr += size;
4283 left -= size;
4284 } else
4285 space = FALSE;
4286 *pcbNeeded += size;
4288 if(pi4) {
4289 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4292 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4293 memset(pi4, 0, sizeof(*pi4));
4295 return space;
4298 /*********************************************************************
4299 * WINSPOOL_GetPrinter_5
4301 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4303 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4304 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4306 DWORD size, left = cbBuf;
4307 BOOL space = (cbBuf > 0);
4308 LPBYTE ptr = buf;
4310 *pcbNeeded = 0;
4312 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4313 if(space && size <= left) {
4314 pi5->pPrinterName = (LPWSTR)ptr;
4315 ptr += size;
4316 left -= size;
4317 } else
4318 space = FALSE;
4319 *pcbNeeded += size;
4321 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4322 if(space && size <= left) {
4323 pi5->pPortName = (LPWSTR)ptr;
4324 ptr += size;
4325 left -= size;
4326 } else
4327 space = FALSE;
4328 *pcbNeeded += size;
4330 if(pi5) {
4331 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4332 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4333 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4336 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4337 memset(pi5, 0, sizeof(*pi5));
4339 return space;
4342 /*********************************************************************
4343 * WINSPOOL_GetPrinter_7
4345 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4347 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4348 DWORD cbBuf, LPDWORD pcbNeeded)
4350 DWORD size, left = cbBuf;
4351 BOOL space = (cbBuf > 0);
4352 LPBYTE ptr = buf;
4354 *pcbNeeded = 0;
4356 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4358 ptr = NULL;
4359 size = sizeof(pi7->pszObjectGUID);
4361 if (space && size <= left) {
4362 pi7->pszObjectGUID = (LPWSTR)ptr;
4363 ptr += size;
4364 left -= size;
4365 } else
4366 space = FALSE;
4367 *pcbNeeded += size;
4368 if (pi7) {
4369 /* We do not have a Directory Service */
4370 pi7->dwAction = DSPRINT_UNPUBLISH;
4373 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4374 memset(pi7, 0, sizeof(*pi7));
4376 return space;
4379 /*********************************************************************
4380 * WINSPOOL_GetPrinter_9
4382 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4384 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4385 DWORD cbBuf, LPDWORD pcbNeeded)
4387 DWORD size;
4388 BOOL space = (cbBuf > 0);
4390 *pcbNeeded = 0;
4392 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4393 if(space && size <= cbBuf) {
4394 pi9->pDevMode = (LPDEVMODEW)buf;
4395 } else
4396 space = FALSE;
4397 *pcbNeeded += size;
4399 else
4401 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4402 if(space && size <= cbBuf) {
4403 pi9->pDevMode = (LPDEVMODEW)buf;
4404 } else
4405 space = FALSE;
4406 *pcbNeeded += size;
4409 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4410 memset(pi9, 0, sizeof(*pi9));
4412 return space;
4415 /*****************************************************************************
4416 * GetPrinterW [WINSPOOL.@]
4418 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4419 DWORD cbBuf, LPDWORD pcbNeeded)
4421 DWORD size, needed = 0, err;
4422 LPBYTE ptr = NULL;
4423 HKEY hkeyPrinter;
4424 BOOL ret;
4426 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4428 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4429 if (err)
4431 SetLastError( err );
4432 return FALSE;
4435 switch(Level) {
4436 case 2:
4438 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4440 size = sizeof(PRINTER_INFO_2W);
4441 if(size <= cbBuf) {
4442 ptr = pPrinter + size;
4443 cbBuf -= size;
4444 memset(pPrinter, 0, size);
4445 } else {
4446 pi2 = NULL;
4447 cbBuf = 0;
4449 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4450 needed += size;
4451 break;
4454 case 4:
4456 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4458 size = sizeof(PRINTER_INFO_4W);
4459 if(size <= cbBuf) {
4460 ptr = pPrinter + size;
4461 cbBuf -= size;
4462 memset(pPrinter, 0, size);
4463 } else {
4464 pi4 = NULL;
4465 cbBuf = 0;
4467 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4468 needed += size;
4469 break;
4473 case 5:
4475 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4477 size = sizeof(PRINTER_INFO_5W);
4478 if(size <= cbBuf) {
4479 ptr = pPrinter + size;
4480 cbBuf -= size;
4481 memset(pPrinter, 0, size);
4482 } else {
4483 pi5 = NULL;
4484 cbBuf = 0;
4487 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4488 needed += size;
4489 break;
4493 case 6:
4495 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4497 size = sizeof(PRINTER_INFO_6);
4498 if (size <= cbBuf) {
4499 /* FIXME: We do not update the status yet */
4500 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4501 ret = TRUE;
4502 } else {
4503 ret = FALSE;
4506 needed += size;
4507 break;
4510 case 7:
4512 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4514 size = sizeof(PRINTER_INFO_7W);
4515 if (size <= cbBuf) {
4516 ptr = pPrinter + size;
4517 cbBuf -= size;
4518 memset(pPrinter, 0, size);
4519 } else {
4520 pi7 = NULL;
4521 cbBuf = 0;
4524 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4525 needed += size;
4526 break;
4530 case 8:
4531 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4532 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4533 /* fall through */
4534 case 9:
4536 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4538 size = sizeof(PRINTER_INFO_9W);
4539 if(size <= cbBuf) {
4540 ptr = pPrinter + size;
4541 cbBuf -= size;
4542 memset(pPrinter, 0, size);
4543 } else {
4544 pi9 = NULL;
4545 cbBuf = 0;
4548 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4549 needed += size;
4550 break;
4554 default:
4555 FIXME("Unimplemented level %d\n", Level);
4556 SetLastError(ERROR_INVALID_LEVEL);
4557 RegCloseKey(hkeyPrinter);
4558 return FALSE;
4561 RegCloseKey(hkeyPrinter);
4563 TRACE("returning %d needed = %d\n", ret, needed);
4564 if(pcbNeeded) *pcbNeeded = needed;
4565 if(!ret)
4566 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4567 return ret;
4570 /*****************************************************************************
4571 * GetPrinterA [WINSPOOL.@]
4573 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4574 DWORD cbBuf, LPDWORD pcbNeeded)
4576 BOOL ret;
4577 LPBYTE buf = NULL;
4579 if (cbBuf)
4580 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4582 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4583 if (ret)
4584 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4585 HeapFree(GetProcessHeap(), 0, buf);
4587 return ret;
4590 /*****************************************************************************
4591 * WINSPOOL_EnumPrintersW
4593 * Implementation of EnumPrintersW
4595 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4596 DWORD dwLevel, LPBYTE lpbPrinters,
4597 DWORD cbBuf, LPDWORD lpdwNeeded,
4598 LPDWORD lpdwReturned)
4601 HKEY hkeyPrinters, hkeyPrinter;
4602 WCHAR PrinterName[255];
4603 DWORD needed = 0, number = 0;
4604 DWORD used, i, left;
4605 PBYTE pi, buf;
4607 if(lpbPrinters)
4608 memset(lpbPrinters, 0, cbBuf);
4609 if(lpdwReturned)
4610 *lpdwReturned = 0;
4611 if(lpdwNeeded)
4612 *lpdwNeeded = 0;
4614 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4615 if(dwType == PRINTER_ENUM_DEFAULT)
4616 return TRUE;
4618 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4619 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4620 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4621 if (!dwType) {
4622 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4623 return TRUE;
4628 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4629 FIXME("dwType = %08x\n", dwType);
4630 SetLastError(ERROR_INVALID_FLAGS);
4631 return FALSE;
4634 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4635 ERROR_SUCCESS) {
4636 ERR("Can't create Printers key\n");
4637 return FALSE;
4640 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4641 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4642 RegCloseKey(hkeyPrinters);
4643 ERR("Can't query Printers key\n");
4644 return FALSE;
4646 TRACE("Found %d printers\n", number);
4648 switch(dwLevel) {
4649 case 1:
4650 used = number * sizeof(PRINTER_INFO_1W);
4651 break;
4652 case 2:
4653 used = number * sizeof(PRINTER_INFO_2W);
4654 break;
4655 case 4:
4656 used = number * sizeof(PRINTER_INFO_4W);
4657 break;
4658 case 5:
4659 used = number * sizeof(PRINTER_INFO_5W);
4660 break;
4662 default:
4663 SetLastError(ERROR_INVALID_LEVEL);
4664 RegCloseKey(hkeyPrinters);
4665 return FALSE;
4667 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4669 for(i = 0; i < number; i++) {
4670 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, ARRAY_SIZE(PrinterName)) != ERROR_SUCCESS) {
4671 ERR("Can't enum key number %d\n", i);
4672 RegCloseKey(hkeyPrinters);
4673 return FALSE;
4675 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4676 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4677 ERROR_SUCCESS) {
4678 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4679 RegCloseKey(hkeyPrinters);
4680 return FALSE;
4683 if(cbBuf > used) {
4684 buf = lpbPrinters + used;
4685 left = cbBuf - used;
4686 } else {
4687 buf = NULL;
4688 left = 0;
4691 switch(dwLevel) {
4692 case 1:
4693 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4694 left, &needed);
4695 used += needed;
4696 if(pi) pi += sizeof(PRINTER_INFO_1W);
4697 break;
4698 case 2:
4699 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4700 left, &needed);
4701 used += needed;
4702 if(pi) pi += sizeof(PRINTER_INFO_2W);
4703 break;
4704 case 4:
4705 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4706 left, &needed);
4707 used += needed;
4708 if(pi) pi += sizeof(PRINTER_INFO_4W);
4709 break;
4710 case 5:
4711 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4712 left, &needed);
4713 used += needed;
4714 if(pi) pi += sizeof(PRINTER_INFO_5W);
4715 break;
4716 default:
4717 ERR("Shouldn't be here!\n");
4718 RegCloseKey(hkeyPrinter);
4719 RegCloseKey(hkeyPrinters);
4720 return FALSE;
4722 RegCloseKey(hkeyPrinter);
4724 RegCloseKey(hkeyPrinters);
4726 if(lpdwNeeded)
4727 *lpdwNeeded = used;
4729 if(used > cbBuf) {
4730 if(lpbPrinters)
4731 memset(lpbPrinters, 0, cbBuf);
4732 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4733 return FALSE;
4735 if(lpdwReturned)
4736 *lpdwReturned = number;
4737 SetLastError(ERROR_SUCCESS);
4738 return TRUE;
4742 /******************************************************************
4743 * EnumPrintersW [WINSPOOL.@]
4745 * Enumerates the available printers, print servers and print
4746 * providers, depending on the specified flags, name and level.
4748 * RETURNS:
4750 * If level is set to 1:
4751 * Returns an array of PRINTER_INFO_1 data structures in the
4752 * lpbPrinters buffer.
4754 * If level is set to 2:
4755 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4756 * Returns an array of PRINTER_INFO_2 data structures in the
4757 * lpbPrinters buffer. Note that according to MSDN also an
4758 * OpenPrinter should be performed on every remote printer.
4760 * If level is set to 4 (officially WinNT only):
4761 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4762 * Fast: Only the registry is queried to retrieve printer names,
4763 * no connection to the driver is made.
4764 * Returns an array of PRINTER_INFO_4 data structures in the
4765 * lpbPrinters buffer.
4767 * If level is set to 5 (officially WinNT4/Win9x only):
4768 * Fast: Only the registry is queried to retrieve printer names,
4769 * no connection to the driver is made.
4770 * Returns an array of PRINTER_INFO_5 data structures in the
4771 * lpbPrinters buffer.
4773 * If level set to 3 or 6+:
4774 * returns zero (failure!)
4776 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4777 * for information.
4779 * BUGS:
4780 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4781 * - Only levels 2, 4 and 5 are implemented at the moment.
4782 * - 16-bit printer drivers are not enumerated.
4783 * - Returned amount of bytes used/needed does not match the real Windoze
4784 * implementation (as in this implementation, all strings are part
4785 * of the buffer, whereas Win32 keeps them somewhere else)
4786 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4788 * NOTE:
4789 * - In a regular Wine installation, no registry settings for printers
4790 * exist, which makes this function return an empty list.
4792 BOOL WINAPI EnumPrintersW(
4793 DWORD dwType, /* [in] Types of print objects to enumerate */
4794 LPWSTR lpszName, /* [in] name of objects to enumerate */
4795 DWORD dwLevel, /* [in] type of printer info structure */
4796 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4797 DWORD cbBuf, /* [in] max size of buffer in bytes */
4798 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4799 LPDWORD lpdwReturned /* [out] number of entries returned */
4802 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4803 lpdwNeeded, lpdwReturned);
4806 /******************************************************************
4807 * EnumPrintersA [WINSPOOL.@]
4809 * See EnumPrintersW
4812 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4813 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4815 BOOL ret;
4816 UNICODE_STRING pNameU;
4817 LPWSTR pNameW;
4818 LPBYTE pPrintersW;
4820 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4821 pPrinters, cbBuf, pcbNeeded, pcReturned);
4823 pNameW = asciitounicode(&pNameU, pName);
4825 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4826 MS Office need this */
4827 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4829 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4831 RtlFreeUnicodeString(&pNameU);
4832 if (ret) {
4833 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4835 HeapFree(GetProcessHeap(), 0, pPrintersW);
4836 return ret;
4839 /*****************************************************************************
4840 * WINSPOOL_GetDriverInfoFromReg [internal]
4842 * Enters the information from the registry into the DRIVER_INFO struct
4844 * RETURNS
4845 * zero if the printer driver does not exist in the registry
4846 * (only if Level > 1) otherwise nonzero
4848 static BOOL WINSPOOL_GetDriverInfoFromReg(
4849 HKEY hkeyDrivers,
4850 LPWSTR DriverName,
4851 const printenv_t * env,
4852 DWORD Level,
4853 LPBYTE ptr, /* DRIVER_INFO */
4854 LPBYTE pDriverStrings, /* strings buffer */
4855 DWORD cbBuf, /* size of string buffer */
4856 LPDWORD pcbNeeded) /* space needed for str. */
4858 DWORD size, tmp;
4859 HKEY hkeyDriver;
4860 WCHAR driverdir[MAX_PATH];
4861 DWORD dirlen;
4862 LPBYTE strPtr = pDriverStrings;
4863 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4865 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4866 debugstr_w(DriverName), env,
4867 Level, di, pDriverStrings, cbBuf);
4869 if (di) ZeroMemory(di, di_sizeof[Level]);
4871 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4872 if (*pcbNeeded <= cbBuf)
4873 strcpyW((LPWSTR)strPtr, DriverName);
4875 /* pName for level 1 has a different offset! */
4876 if (Level == 1) {
4877 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4878 return TRUE;
4881 /* .cVersion and .pName for level > 1 */
4882 if (di) {
4883 di->cVersion = env->driverversion;
4884 di->pName = (LPWSTR) strPtr;
4885 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4888 /* Reserve Space for the largest subdir and a Backslash*/
4889 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4890 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4891 /* Should never Fail */
4892 return FALSE;
4894 lstrcatW(driverdir, env->versionsubdir);
4895 lstrcatW(driverdir, backslashW);
4897 /* dirlen must not include the terminating zero */
4898 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4900 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4901 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4902 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4903 return FALSE;
4906 /* pEnvironment */
4907 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4909 *pcbNeeded += size;
4910 if (*pcbNeeded <= cbBuf) {
4911 lstrcpyW((LPWSTR)strPtr, env->envname);
4912 if (di) di->pEnvironment = (LPWSTR)strPtr;
4913 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4916 /* .pDriverPath is the Graphics rendering engine.
4917 The full Path is required to avoid a crash in some apps */
4918 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4919 *pcbNeeded += size;
4920 if (*pcbNeeded <= cbBuf)
4921 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4923 if (di) di->pDriverPath = (LPWSTR)strPtr;
4924 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4927 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4928 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4929 *pcbNeeded += size;
4930 if (*pcbNeeded <= cbBuf)
4931 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4933 if (di) di->pDataFile = (LPWSTR)strPtr;
4934 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4937 /* .pConfigFile is the Driver user Interface */
4938 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4939 *pcbNeeded += size;
4940 if (*pcbNeeded <= cbBuf)
4941 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4943 if (di) di->pConfigFile = (LPWSTR)strPtr;
4944 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4947 if (Level == 2 ) {
4948 RegCloseKey(hkeyDriver);
4949 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4950 return TRUE;
4953 if (Level == 5 ) {
4954 RegCloseKey(hkeyDriver);
4955 FIXME("level 5: incomplete\n");
4956 return TRUE;
4959 /* .pHelpFile */
4960 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4961 *pcbNeeded += size;
4962 if (*pcbNeeded <= cbBuf)
4963 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4965 if (di) di->pHelpFile = (LPWSTR)strPtr;
4966 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4969 /* .pDependentFiles */
4970 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4971 *pcbNeeded += size;
4972 if (*pcbNeeded <= cbBuf)
4973 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4975 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4976 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4978 else if (GetVersion() & 0x80000000) {
4979 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4980 size = 2 * sizeof(WCHAR);
4981 *pcbNeeded += size;
4982 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4984 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4985 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4988 /* .pMonitorName is the optional Language Monitor */
4989 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4990 *pcbNeeded += size;
4991 if (*pcbNeeded <= cbBuf)
4992 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4994 if (di) di->pMonitorName = (LPWSTR)strPtr;
4995 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4998 /* .pDefaultDataType */
4999 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
5000 *pcbNeeded += size;
5001 if(*pcbNeeded <= cbBuf)
5002 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
5004 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
5005 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5008 if (Level == 3 ) {
5009 RegCloseKey(hkeyDriver);
5010 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5011 return TRUE;
5014 /* .pszzPreviousNames */
5015 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
5016 *pcbNeeded += size;
5017 if(*pcbNeeded <= cbBuf)
5018 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
5020 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
5021 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5024 if (Level == 4 ) {
5025 RegCloseKey(hkeyDriver);
5026 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5027 return TRUE;
5030 /* support is missing, but not important enough for a FIXME */
5031 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5033 /* .pszMfgName */
5034 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5035 *pcbNeeded += size;
5036 if(*pcbNeeded <= cbBuf)
5037 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5039 if (di) di->pszMfgName = (LPWSTR)strPtr;
5040 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5043 /* .pszOEMUrl */
5044 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5045 *pcbNeeded += size;
5046 if(*pcbNeeded <= cbBuf)
5047 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5049 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5050 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5053 /* .pszHardwareID */
5054 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5055 *pcbNeeded += size;
5056 if(*pcbNeeded <= cbBuf)
5057 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5059 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5060 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5063 /* .pszProvider */
5064 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5065 *pcbNeeded += size;
5066 if(*pcbNeeded <= cbBuf)
5067 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5069 if (di) di->pszProvider = (LPWSTR)strPtr;
5070 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5073 if (Level == 6 ) {
5074 RegCloseKey(hkeyDriver);
5075 return TRUE;
5078 /* support is missing, but not important enough for a FIXME */
5079 TRACE("level 8: incomplete\n");
5081 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5082 RegCloseKey(hkeyDriver);
5083 return TRUE;
5086 /*****************************************************************************
5087 * GetPrinterDriverW [WINSPOOL.@]
5089 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5090 DWORD Level, LPBYTE pDriverInfo,
5091 DWORD cbBuf, LPDWORD pcbNeeded)
5093 LPCWSTR name;
5094 WCHAR DriverName[100];
5095 DWORD ret, type, size, needed = 0;
5096 LPBYTE ptr = NULL;
5097 HKEY hkeyPrinter, hkeyDrivers;
5098 const printenv_t * env;
5100 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5101 Level,pDriverInfo,cbBuf, pcbNeeded);
5103 if (cbBuf > 0)
5104 ZeroMemory(pDriverInfo, cbBuf);
5106 if (!(name = get_opened_printer_name(hPrinter))) {
5107 SetLastError(ERROR_INVALID_HANDLE);
5108 return FALSE;
5111 if (Level < 1 || Level == 7 || Level > 8) {
5112 SetLastError(ERROR_INVALID_LEVEL);
5113 return FALSE;
5116 env = validate_envW(pEnvironment);
5117 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5119 ret = open_printer_reg_key( name, &hkeyPrinter );
5120 if (ret)
5122 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5123 SetLastError( ret );
5124 return FALSE;
5127 size = sizeof(DriverName);
5128 DriverName[0] = 0;
5129 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5130 (LPBYTE)DriverName, &size);
5131 RegCloseKey(hkeyPrinter);
5132 if(ret != ERROR_SUCCESS) {
5133 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5134 return FALSE;
5137 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5138 if(!hkeyDrivers) {
5139 ERR("Can't create Drivers key\n");
5140 return FALSE;
5143 size = di_sizeof[Level];
5144 if ((size <= cbBuf) && pDriverInfo)
5145 ptr = pDriverInfo + size;
5147 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5148 env, Level, pDriverInfo, ptr,
5149 (cbBuf < size) ? 0 : cbBuf - size,
5150 &needed)) {
5151 RegCloseKey(hkeyDrivers);
5152 return FALSE;
5155 RegCloseKey(hkeyDrivers);
5157 if(pcbNeeded) *pcbNeeded = size + needed;
5158 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5159 if(cbBuf >= size + needed) return TRUE;
5160 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5161 return FALSE;
5164 /*****************************************************************************
5165 * GetPrinterDriverA [WINSPOOL.@]
5167 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5168 DWORD Level, LPBYTE pDriverInfo,
5169 DWORD cbBuf, LPDWORD pcbNeeded)
5171 BOOL ret;
5172 UNICODE_STRING pEnvW;
5173 PWSTR pwstrEnvW;
5174 LPBYTE buf = NULL;
5176 if (cbBuf)
5178 ZeroMemory(pDriverInfo, cbBuf);
5179 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5182 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5183 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5184 cbBuf, pcbNeeded);
5185 if (ret)
5186 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5188 HeapFree(GetProcessHeap(), 0, buf);
5190 RtlFreeUnicodeString(&pEnvW);
5191 return ret;
5194 /*****************************************************************************
5195 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5197 * Return the PATH for the Printer-Drivers (UNICODE)
5199 * PARAMS
5200 * pName [I] Servername (NT only) or NULL (local Computer)
5201 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5202 * Level [I] Structure-Level (must be 1)
5203 * pDriverDirectory [O] PTR to Buffer that receives the Result
5204 * cbBuf [I] Size of Buffer at pDriverDirectory
5205 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5206 * required for pDriverDirectory
5208 * RETURNS
5209 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5210 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5211 * if cbBuf is too small
5213 * Native Values returned in pDriverDirectory on Success:
5214 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5215 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5216 *| win9x(Windows 4.0): "%winsysdir%"
5218 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5220 * FIXME
5221 *- Only NULL or "" is supported for pName
5224 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5225 DWORD Level, LPBYTE pDriverDirectory,
5226 DWORD cbBuf, LPDWORD pcbNeeded)
5228 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5229 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5231 if ((backend == NULL) && !load_backend()) return FALSE;
5233 if (Level != 1) {
5234 /* (Level != 1) is ignored in win9x */
5235 SetLastError(ERROR_INVALID_LEVEL);
5236 return FALSE;
5238 if (pcbNeeded == NULL) {
5239 /* (pcbNeeded == NULL) is ignored in win9x */
5240 SetLastError(RPC_X_NULL_REF_POINTER);
5241 return FALSE;
5244 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5245 pDriverDirectory, cbBuf, pcbNeeded);
5250 /*****************************************************************************
5251 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5253 * Return the PATH for the Printer-Drivers (ANSI)
5255 * See GetPrinterDriverDirectoryW.
5257 * NOTES
5258 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5261 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5262 DWORD Level, LPBYTE pDriverDirectory,
5263 DWORD cbBuf, LPDWORD pcbNeeded)
5265 UNICODE_STRING nameW, environmentW;
5266 BOOL ret;
5267 DWORD pcbNeededW;
5268 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5269 WCHAR *driverDirectoryW = NULL;
5271 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5272 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5274 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5276 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5277 else nameW.Buffer = NULL;
5278 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5279 else environmentW.Buffer = NULL;
5281 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5282 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5283 if (ret) {
5284 DWORD needed;
5285 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5286 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5287 if(pcbNeeded)
5288 *pcbNeeded = needed;
5289 ret = needed <= cbBuf;
5290 } else
5291 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5293 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5295 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5296 RtlFreeUnicodeString(&environmentW);
5297 RtlFreeUnicodeString(&nameW);
5299 return ret;
5302 /*****************************************************************************
5303 * AddPrinterDriverA [WINSPOOL.@]
5305 * See AddPrinterDriverW.
5308 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5310 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5311 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5314 /******************************************************************************
5315 * AddPrinterDriverW (WINSPOOL.@)
5317 * Install a Printer Driver
5319 * PARAMS
5320 * pName [I] Servername or NULL (local Computer)
5321 * level [I] Level for the supplied DRIVER_INFO_*W struct
5322 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5324 * RESULTS
5325 * Success: TRUE
5326 * Failure: FALSE
5329 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5331 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5332 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5335 /*****************************************************************************
5336 * AddPrintProcessorA [WINSPOOL.@]
5338 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5339 LPSTR pPrintProcessorName)
5341 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5342 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5343 return FALSE;
5346 /*****************************************************************************
5347 * AddPrintProcessorW [WINSPOOL.@]
5349 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5350 LPWSTR pPrintProcessorName)
5352 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5353 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5354 return TRUE;
5357 /*****************************************************************************
5358 * AddPrintProvidorA [WINSPOOL.@]
5360 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5362 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5363 return FALSE;
5366 /*****************************************************************************
5367 * AddPrintProvidorW [WINSPOOL.@]
5369 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5371 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5372 return FALSE;
5375 /*****************************************************************************
5376 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5378 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5379 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5381 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5382 pDevModeOutput, pDevModeInput);
5383 return 0;
5386 /*****************************************************************************
5387 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5389 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5390 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5392 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5393 pDevModeOutput, pDevModeInput);
5394 return 0;
5397 /*****************************************************************************
5398 * PrinterProperties [WINSPOOL.@]
5400 * Displays a dialog to set the properties of the printer.
5402 * RETURNS
5403 * nonzero on success or zero on failure
5405 * BUGS
5406 * implemented as stub only
5408 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5409 HANDLE hPrinter /* [in] handle to printer object */
5411 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5412 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5413 return FALSE;
5416 /*****************************************************************************
5417 * EnumJobsA [WINSPOOL.@]
5420 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5421 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5422 LPDWORD pcReturned)
5424 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5425 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5427 if(pcbNeeded) *pcbNeeded = 0;
5428 if(pcReturned) *pcReturned = 0;
5429 return FALSE;
5433 /*****************************************************************************
5434 * EnumJobsW [WINSPOOL.@]
5437 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5438 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5439 LPDWORD pcReturned)
5441 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5442 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5444 if(pcbNeeded) *pcbNeeded = 0;
5445 if(pcReturned) *pcReturned = 0;
5446 return FALSE;
5449 /*****************************************************************************
5450 * WINSPOOL_EnumPrinterDrivers [internal]
5452 * Delivers information about all printer drivers installed on the
5453 * localhost or a given server
5455 * RETURNS
5456 * nonzero on success or zero on failure. If the buffer for the returned
5457 * information is too small the function will return an error
5459 * BUGS
5460 * - only implemented for localhost, foreign hosts will return an error
5462 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5463 DWORD Level, LPBYTE pDriverInfo,
5464 DWORD driver_index,
5465 DWORD cbBuf, LPDWORD pcbNeeded,
5466 LPDWORD pcFound, DWORD data_offset)
5468 { HKEY hkeyDrivers;
5469 DWORD i, size = 0;
5470 const printenv_t * env;
5472 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5473 debugstr_w(pName), debugstr_w(pEnvironment),
5474 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5476 env = validate_envW(pEnvironment);
5477 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5479 *pcFound = 0;
5481 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5482 if(!hkeyDrivers) {
5483 ERR("Can't open Drivers key\n");
5484 return FALSE;
5487 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5488 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5489 RegCloseKey(hkeyDrivers);
5490 ERR("Can't query Drivers key\n");
5491 return FALSE;
5493 TRACE("Found %d Drivers\n", *pcFound);
5495 /* get size of single struct
5496 * unicode and ascii structure have the same size
5498 size = di_sizeof[Level];
5500 if (data_offset == 0)
5501 data_offset = size * (*pcFound);
5502 *pcbNeeded = data_offset;
5504 for( i = 0; i < *pcFound; i++) {
5505 WCHAR DriverNameW[255];
5506 PBYTE table_ptr = NULL;
5507 PBYTE data_ptr = NULL;
5508 DWORD needed = 0;
5510 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, ARRAY_SIZE(DriverNameW)) != ERROR_SUCCESS) {
5511 ERR("Can't enum key number %d\n", i);
5512 RegCloseKey(hkeyDrivers);
5513 return FALSE;
5516 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5517 table_ptr = pDriverInfo + (driver_index + i) * size;
5518 if (pDriverInfo && *pcbNeeded <= cbBuf)
5519 data_ptr = pDriverInfo + *pcbNeeded;
5521 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5522 env, Level, table_ptr, data_ptr,
5523 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5524 &needed)) {
5525 RegCloseKey(hkeyDrivers);
5526 return FALSE;
5529 *pcbNeeded += needed;
5532 RegCloseKey(hkeyDrivers);
5534 if(cbBuf < *pcbNeeded){
5535 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5536 return FALSE;
5539 return TRUE;
5542 /*****************************************************************************
5543 * EnumPrinterDriversW [WINSPOOL.@]
5545 * see function EnumPrinterDrivers for RETURNS, BUGS
5547 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5548 LPBYTE pDriverInfo, DWORD cbBuf,
5549 LPDWORD pcbNeeded, LPDWORD pcReturned)
5551 static const WCHAR allW[] = {'a','l','l',0};
5552 BOOL ret;
5553 DWORD found;
5555 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5557 SetLastError(RPC_X_NULL_REF_POINTER);
5558 return FALSE;
5561 /* check for local drivers */
5562 if((pName) && (pName[0])) {
5563 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5564 SetLastError(ERROR_ACCESS_DENIED);
5565 return FALSE;
5568 /* check input parameter */
5569 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5570 SetLastError(ERROR_INVALID_LEVEL);
5571 return FALSE;
5574 if(pDriverInfo && cbBuf > 0)
5575 memset( pDriverInfo, 0, cbBuf);
5577 /* Exception: pull all printers */
5578 if (pEnvironment && !strcmpW(pEnvironment, allW))
5580 DWORD i, needed, bufsize = cbBuf;
5581 DWORD total_found = 0;
5582 DWORD data_offset;
5584 /* Precompute the overall total; we need this to know
5585 where pointers end and data begins (i.e. data_offset) */
5586 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
5588 needed = found = 0;
5589 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5590 NULL, 0, 0, &needed, &found, 0);
5591 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5592 total_found += found;
5595 data_offset = di_sizeof[Level] * total_found;
5597 *pcReturned = 0;
5598 *pcbNeeded = 0;
5599 total_found = 0;
5600 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
5602 needed = found = 0;
5603 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5604 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5605 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5606 else if (ret)
5607 *pcReturned += found;
5608 *pcbNeeded = needed;
5609 data_offset = needed;
5610 total_found += found;
5612 return ret;
5615 /* Normal behavior */
5616 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5617 0, cbBuf, pcbNeeded, &found, 0);
5618 if (ret)
5619 *pcReturned = found;
5621 return ret;
5624 /*****************************************************************************
5625 * EnumPrinterDriversA [WINSPOOL.@]
5627 * see function EnumPrinterDrivers for RETURNS, BUGS
5629 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5630 LPBYTE pDriverInfo, DWORD cbBuf,
5631 LPDWORD pcbNeeded, LPDWORD pcReturned)
5633 BOOL ret;
5634 UNICODE_STRING pNameW, pEnvironmentW;
5635 PWSTR pwstrNameW, pwstrEnvironmentW;
5636 LPBYTE buf = NULL;
5638 if (cbBuf)
5639 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5641 pwstrNameW = asciitounicode(&pNameW, pName);
5642 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5644 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5645 buf, cbBuf, pcbNeeded, pcReturned);
5646 if (ret)
5647 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5649 HeapFree(GetProcessHeap(), 0, buf);
5651 RtlFreeUnicodeString(&pNameW);
5652 RtlFreeUnicodeString(&pEnvironmentW);
5654 return ret;
5657 /******************************************************************************
5658 * EnumPortsA (WINSPOOL.@)
5660 * See EnumPortsW.
5663 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5664 LPDWORD pcbNeeded, LPDWORD pcReturned)
5666 BOOL res;
5667 LPBYTE bufferW = NULL;
5668 LPWSTR nameW = NULL;
5669 DWORD needed = 0;
5670 DWORD numentries = 0;
5671 INT len;
5673 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5674 cbBuf, pcbNeeded, pcReturned);
5676 /* convert servername to unicode */
5677 if (pName) {
5678 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5679 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5680 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5682 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5683 needed = cbBuf * sizeof(WCHAR);
5684 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5685 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5687 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5688 if (pcbNeeded) needed = *pcbNeeded;
5689 /* HeapReAlloc return NULL, when bufferW was NULL */
5690 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5691 HeapAlloc(GetProcessHeap(), 0, needed);
5693 /* Try again with the large Buffer */
5694 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5696 needed = pcbNeeded ? *pcbNeeded : 0;
5697 numentries = pcReturned ? *pcReturned : 0;
5700 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5701 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5703 if (res) {
5704 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5705 DWORD entrysize = 0;
5706 DWORD index;
5707 LPSTR ptr;
5708 LPPORT_INFO_2W pi2w;
5709 LPPORT_INFO_2A pi2a;
5711 needed = 0;
5712 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5714 /* First pass: calculate the size for all Entries */
5715 pi2w = (LPPORT_INFO_2W) bufferW;
5716 pi2a = (LPPORT_INFO_2A) pPorts;
5717 index = 0;
5718 while (index < numentries) {
5719 index++;
5720 needed += entrysize; /* PORT_INFO_?A */
5721 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5723 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5724 NULL, 0, NULL, NULL);
5725 if (Level > 1) {
5726 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5727 NULL, 0, NULL, NULL);
5728 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5729 NULL, 0, NULL, NULL);
5731 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5732 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5733 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5736 /* check for errors and quit on failure */
5737 if (cbBuf < needed) {
5738 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5739 res = FALSE;
5740 goto cleanup;
5742 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5743 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5744 cbBuf -= len ; /* free Bytes in the user-Buffer */
5745 pi2w = (LPPORT_INFO_2W) bufferW;
5746 pi2a = (LPPORT_INFO_2A) pPorts;
5747 index = 0;
5748 /* Second Pass: Fill the User Buffer (if we have one) */
5749 while ((index < numentries) && pPorts) {
5750 index++;
5751 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5752 pi2a->pPortName = ptr;
5753 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5754 ptr, cbBuf , NULL, NULL);
5755 ptr += len;
5756 cbBuf -= len;
5757 if (Level > 1) {
5758 pi2a->pMonitorName = ptr;
5759 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5760 ptr, cbBuf, NULL, NULL);
5761 ptr += len;
5762 cbBuf -= len;
5764 pi2a->pDescription = ptr;
5765 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5766 ptr, cbBuf, NULL, NULL);
5767 ptr += len;
5768 cbBuf -= len;
5770 pi2a->fPortType = pi2w->fPortType;
5771 pi2a->Reserved = 0; /* documented: "must be zero" */
5774 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5775 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5776 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5780 cleanup:
5781 if (pcbNeeded) *pcbNeeded = needed;
5782 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5784 HeapFree(GetProcessHeap(), 0, nameW);
5785 HeapFree(GetProcessHeap(), 0, bufferW);
5787 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5788 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5790 return (res);
5794 /******************************************************************************
5795 * EnumPortsW (WINSPOOL.@)
5797 * Enumerate available Ports
5799 * PARAMS
5800 * pName [I] Servername or NULL (local Computer)
5801 * Level [I] Structure-Level (1 or 2)
5802 * pPorts [O] PTR to Buffer that receives the Result
5803 * cbBuf [I] Size of Buffer at pPorts
5804 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5805 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5807 * RETURNS
5808 * Success: TRUE
5809 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5812 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5815 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5816 cbBuf, pcbNeeded, pcReturned);
5818 if ((backend == NULL) && !load_backend()) return FALSE;
5820 /* Level is not checked in win9x */
5821 if (!Level || (Level > 2)) {
5822 WARN("level (%d) is ignored in win9x\n", Level);
5823 SetLastError(ERROR_INVALID_LEVEL);
5824 return FALSE;
5826 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5827 SetLastError(RPC_X_NULL_REF_POINTER);
5828 return FALSE;
5831 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5834 /******************************************************************************
5835 * GetDefaultPrinterW (WINSPOOL.@)
5837 * FIXME
5838 * This function must read the value from data 'device' of key
5839 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5841 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5843 BOOL retval = TRUE;
5844 DWORD insize, len;
5845 WCHAR *buffer, *ptr;
5847 if (!namesize)
5849 SetLastError(ERROR_INVALID_PARAMETER);
5850 return FALSE;
5853 /* make the buffer big enough for the stuff from the profile/registry,
5854 * the content must fit into the local buffer to compute the correct
5855 * size even if the extern buffer is too small or not given.
5856 * (20 for ,driver,port) */
5857 insize = *namesize;
5858 len = max(100, (insize + 20));
5859 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5861 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5863 SetLastError (ERROR_FILE_NOT_FOUND);
5864 retval = FALSE;
5865 goto end;
5867 TRACE("%s\n", debugstr_w(buffer));
5869 if ((ptr = strchrW(buffer, ',')) == NULL)
5871 SetLastError(ERROR_INVALID_NAME);
5872 retval = FALSE;
5873 goto end;
5876 *ptr = 0;
5877 *namesize = strlenW(buffer) + 1;
5878 if(!name || (*namesize > insize))
5880 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5881 retval = FALSE;
5882 goto end;
5884 strcpyW(name, buffer);
5886 end:
5887 HeapFree( GetProcessHeap(), 0, buffer);
5888 return retval;
5892 /******************************************************************************
5893 * GetDefaultPrinterA (WINSPOOL.@)
5895 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5897 BOOL retval = TRUE;
5898 DWORD insize = 0;
5899 WCHAR *bufferW = NULL;
5901 if (!namesize)
5903 SetLastError(ERROR_INVALID_PARAMETER);
5904 return FALSE;
5907 if(name && *namesize) {
5908 insize = *namesize;
5909 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5912 if(!GetDefaultPrinterW( bufferW, namesize)) {
5913 retval = FALSE;
5914 goto end;
5917 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5918 NULL, NULL);
5919 if (!*namesize)
5921 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5922 retval = FALSE;
5924 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5926 end:
5927 HeapFree( GetProcessHeap(), 0, bufferW);
5928 return retval;
5932 /******************************************************************************
5933 * SetDefaultPrinterW (WINSPOOL.204)
5935 * Set the Name of the Default Printer
5937 * PARAMS
5938 * pszPrinter [I] Name of the Printer or NULL
5940 * RETURNS
5941 * Success: True
5942 * Failure: FALSE
5944 * NOTES
5945 * When the Parameter is NULL or points to an Empty String and
5946 * a Default Printer was already present, then this Function changes nothing.
5947 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5948 * the First enumerated local Printer is used.
5951 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5953 WCHAR default_printer[MAX_PATH];
5954 LPWSTR buffer = NULL;
5955 HKEY hreg;
5956 DWORD size;
5957 DWORD namelen;
5958 LONG lres;
5960 TRACE("(%s)\n", debugstr_w(pszPrinter));
5961 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5963 default_printer[0] = '\0';
5964 size = ARRAY_SIZE(default_printer);
5966 /* if we have a default Printer, do nothing. */
5967 if (GetDefaultPrinterW(default_printer, &size))
5968 return TRUE;
5970 pszPrinter = NULL;
5971 /* we have no default Printer: search local Printers and use the first */
5972 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5974 default_printer[0] = '\0';
5975 size = ARRAY_SIZE(default_printer);
5976 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5978 pszPrinter = default_printer;
5979 TRACE("using %s\n", debugstr_w(pszPrinter));
5981 RegCloseKey(hreg);
5984 if (pszPrinter == NULL) {
5985 TRACE("no local printer found\n");
5986 SetLastError(ERROR_FILE_NOT_FOUND);
5987 return FALSE;
5991 /* "pszPrinter" is never empty or NULL here. */
5992 namelen = lstrlenW(pszPrinter);
5993 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5994 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5995 if (!buffer ||
5996 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5997 HeapFree(GetProcessHeap(), 0, buffer);
5998 SetLastError(ERROR_FILE_NOT_FOUND);
5999 return FALSE;
6002 /* read the devices entry for the printer (driver,port) to build the string for the
6003 default device entry (printer,driver,port) */
6004 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
6005 buffer[namelen] = ',';
6006 namelen++; /* move index to the start of the driver */
6008 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
6009 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
6010 if (!lres) {
6011 TRACE("set device to %s\n", debugstr_w(buffer));
6013 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
6014 TRACE("failed to set the device entry: %d\n", GetLastError());
6015 lres = ERROR_INVALID_PRINTER_NAME;
6018 /* remove the next section, when INIFileMapping is implemented */
6020 HKEY hdev;
6021 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
6022 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6023 RegCloseKey(hdev);
6027 else
6029 if (lres != ERROR_FILE_NOT_FOUND)
6030 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6032 SetLastError(ERROR_INVALID_PRINTER_NAME);
6035 RegCloseKey(hreg);
6036 HeapFree(GetProcessHeap(), 0, buffer);
6037 return (lres == ERROR_SUCCESS);
6040 /******************************************************************************
6041 * SetDefaultPrinterA (WINSPOOL.202)
6043 * See SetDefaultPrinterW.
6046 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6048 LPWSTR bufferW = NULL;
6049 BOOL res;
6051 TRACE("(%s)\n", debugstr_a(pszPrinter));
6052 if(pszPrinter) {
6053 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6054 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6055 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6057 res = SetDefaultPrinterW(bufferW);
6058 HeapFree(GetProcessHeap(), 0, bufferW);
6059 return res;
6062 /******************************************************************************
6063 * SetPrinterDataExA (WINSPOOL.@)
6065 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6066 LPCSTR pValueName, DWORD Type,
6067 LPBYTE pData, DWORD cbData)
6069 HKEY hkeyPrinter, hkeySubkey;
6070 DWORD ret;
6072 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6073 debugstr_a(pValueName), Type, pData, cbData);
6075 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6076 != ERROR_SUCCESS)
6077 return ret;
6079 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6080 != ERROR_SUCCESS) {
6081 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6082 RegCloseKey(hkeyPrinter);
6083 return ret;
6085 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6086 RegCloseKey(hkeySubkey);
6087 RegCloseKey(hkeyPrinter);
6088 return ret;
6091 /******************************************************************************
6092 * SetPrinterDataExW (WINSPOOL.@)
6094 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6095 LPCWSTR pValueName, DWORD Type,
6096 LPBYTE pData, DWORD cbData)
6098 HKEY hkeyPrinter, hkeySubkey;
6099 DWORD ret;
6101 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6102 debugstr_w(pValueName), Type, pData, cbData);
6104 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6105 != ERROR_SUCCESS)
6106 return ret;
6108 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6109 != ERROR_SUCCESS) {
6110 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6111 RegCloseKey(hkeyPrinter);
6112 return ret;
6114 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6115 RegCloseKey(hkeySubkey);
6116 RegCloseKey(hkeyPrinter);
6117 return ret;
6120 /******************************************************************************
6121 * SetPrinterDataA (WINSPOOL.@)
6123 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6124 LPBYTE pData, DWORD cbData)
6126 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6127 pData, cbData);
6130 /******************************************************************************
6131 * SetPrinterDataW (WINSPOOL.@)
6133 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6134 LPBYTE pData, DWORD cbData)
6136 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6137 pData, cbData);
6140 /******************************************************************************
6141 * GetPrinterDataExA (WINSPOOL.@)
6143 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6144 LPCSTR pValueName, LPDWORD pType,
6145 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6147 opened_printer_t *printer;
6148 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6149 DWORD ret;
6151 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6152 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6154 printer = get_opened_printer(hPrinter);
6155 if(!printer) return ERROR_INVALID_HANDLE;
6157 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6158 if (ret) return ret;
6160 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6162 if (printer->name) {
6164 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6165 if (ret) {
6166 RegCloseKey(hkeyPrinters);
6167 return ret;
6169 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6170 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6171 RegCloseKey(hkeyPrinter);
6172 RegCloseKey(hkeyPrinters);
6173 return ret;
6176 *pcbNeeded = nSize;
6177 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6178 0, pType, pData, pcbNeeded);
6180 if (!ret && !pData) ret = ERROR_MORE_DATA;
6182 RegCloseKey(hkeySubkey);
6183 RegCloseKey(hkeyPrinter);
6184 RegCloseKey(hkeyPrinters);
6186 TRACE("--> %d\n", ret);
6187 return ret;
6190 /******************************************************************************
6191 * GetPrinterDataExW (WINSPOOL.@)
6193 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6194 LPCWSTR pValueName, LPDWORD pType,
6195 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6197 opened_printer_t *printer;
6198 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6199 DWORD ret;
6201 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6202 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6204 printer = get_opened_printer(hPrinter);
6205 if(!printer) return ERROR_INVALID_HANDLE;
6207 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6208 if (ret) return ret;
6210 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6212 if (printer->name) {
6214 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6215 if (ret) {
6216 RegCloseKey(hkeyPrinters);
6217 return ret;
6219 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6220 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6221 RegCloseKey(hkeyPrinter);
6222 RegCloseKey(hkeyPrinters);
6223 return ret;
6226 *pcbNeeded = nSize;
6227 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6228 0, pType, pData, pcbNeeded);
6230 if (!ret && !pData) ret = ERROR_MORE_DATA;
6232 RegCloseKey(hkeySubkey);
6233 RegCloseKey(hkeyPrinter);
6234 RegCloseKey(hkeyPrinters);
6236 TRACE("--> %d\n", ret);
6237 return ret;
6240 /******************************************************************************
6241 * GetPrinterDataA (WINSPOOL.@)
6243 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6244 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6246 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6247 pData, nSize, pcbNeeded);
6250 /******************************************************************************
6251 * GetPrinterDataW (WINSPOOL.@)
6253 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6254 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6256 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6257 pData, nSize, pcbNeeded);
6260 /*******************************************************************************
6261 * EnumPrinterDataExW [WINSPOOL.@]
6263 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6264 LPBYTE pEnumValues, DWORD cbEnumValues,
6265 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6267 HKEY hkPrinter, hkSubKey;
6268 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6269 cbValueNameLen, cbMaxValueLen, cbValueLen,
6270 cbBufSize, dwType;
6271 LPWSTR lpValueName;
6272 HANDLE hHeap;
6273 PBYTE lpValue;
6274 PPRINTER_ENUM_VALUESW ppev;
6276 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6278 if (pKeyName == NULL || *pKeyName == 0)
6279 return ERROR_INVALID_PARAMETER;
6281 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6282 if (ret != ERROR_SUCCESS)
6284 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6285 hPrinter, ret);
6286 return ret;
6289 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6290 if (ret != ERROR_SUCCESS)
6292 r = RegCloseKey (hkPrinter);
6293 if (r != ERROR_SUCCESS)
6294 WARN ("RegCloseKey returned %i\n", r);
6295 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6296 debugstr_w (pKeyName), ret);
6297 return ret;
6300 ret = RegCloseKey (hkPrinter);
6301 if (ret != ERROR_SUCCESS)
6303 ERR ("RegCloseKey returned %i\n", ret);
6304 r = RegCloseKey (hkSubKey);
6305 if (r != ERROR_SUCCESS)
6306 WARN ("RegCloseKey returned %i\n", r);
6307 return ret;
6310 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6311 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6312 if (ret != ERROR_SUCCESS)
6314 r = RegCloseKey (hkSubKey);
6315 if (r != ERROR_SUCCESS)
6316 WARN ("RegCloseKey returned %i\n", r);
6317 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6318 return ret;
6321 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6322 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6324 if (cValues == 0) /* empty key */
6326 r = RegCloseKey (hkSubKey);
6327 if (r != ERROR_SUCCESS)
6328 WARN ("RegCloseKey returned %i\n", r);
6329 *pcbEnumValues = *pnEnumValues = 0;
6330 return ERROR_SUCCESS;
6333 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6335 hHeap = GetProcessHeap ();
6336 if (hHeap == NULL)
6338 ERR ("GetProcessHeap failed\n");
6339 r = RegCloseKey (hkSubKey);
6340 if (r != ERROR_SUCCESS)
6341 WARN ("RegCloseKey returned %i\n", r);
6342 return ERROR_OUTOFMEMORY;
6345 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6346 if (lpValueName == NULL)
6348 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6349 r = RegCloseKey (hkSubKey);
6350 if (r != ERROR_SUCCESS)
6351 WARN ("RegCloseKey returned %i\n", r);
6352 return ERROR_OUTOFMEMORY;
6355 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6356 if (lpValue == NULL)
6358 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6359 if (HeapFree (hHeap, 0, lpValueName) == 0)
6360 WARN ("HeapFree failed with code %i\n", GetLastError ());
6361 r = RegCloseKey (hkSubKey);
6362 if (r != ERROR_SUCCESS)
6363 WARN ("RegCloseKey returned %i\n", r);
6364 return ERROR_OUTOFMEMORY;
6367 TRACE ("pass 1: calculating buffer required for all names and values\n");
6369 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6371 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6373 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6375 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6376 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6377 NULL, NULL, lpValue, &cbValueLen);
6378 if (ret != ERROR_SUCCESS)
6380 if (HeapFree (hHeap, 0, lpValue) == 0)
6381 WARN ("HeapFree failed with code %i\n", GetLastError ());
6382 if (HeapFree (hHeap, 0, lpValueName) == 0)
6383 WARN ("HeapFree failed with code %i\n", GetLastError ());
6384 r = RegCloseKey (hkSubKey);
6385 if (r != ERROR_SUCCESS)
6386 WARN ("RegCloseKey returned %i\n", r);
6387 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6388 return ret;
6391 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6392 debugstr_w (lpValueName), dwIndex,
6393 cbValueNameLen + 1, cbValueLen);
6395 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6396 cbBufSize += cbValueLen;
6399 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6401 *pcbEnumValues = cbBufSize;
6402 *pnEnumValues = cValues;
6404 if (cbEnumValues < cbBufSize) /* buffer too small */
6406 if (HeapFree (hHeap, 0, lpValue) == 0)
6407 WARN ("HeapFree failed with code %i\n", GetLastError ());
6408 if (HeapFree (hHeap, 0, lpValueName) == 0)
6409 WARN ("HeapFree failed with code %i\n", GetLastError ());
6410 r = RegCloseKey (hkSubKey);
6411 if (r != ERROR_SUCCESS)
6412 WARN ("RegCloseKey returned %i\n", r);
6413 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6414 return ERROR_MORE_DATA;
6417 TRACE ("pass 2: copying all names and values to buffer\n");
6419 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6420 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6422 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6424 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6425 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6426 NULL, &dwType, lpValue, &cbValueLen);
6427 if (ret != ERROR_SUCCESS)
6429 if (HeapFree (hHeap, 0, lpValue) == 0)
6430 WARN ("HeapFree failed with code %i\n", GetLastError ());
6431 if (HeapFree (hHeap, 0, lpValueName) == 0)
6432 WARN ("HeapFree failed with code %i\n", GetLastError ());
6433 r = RegCloseKey (hkSubKey);
6434 if (r != ERROR_SUCCESS)
6435 WARN ("RegCloseKey returned %i\n", r);
6436 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6437 return ret;
6440 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6441 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6442 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6443 pEnumValues += cbValueNameLen;
6445 /* return # of *bytes* (including trailing \0), not # of chars */
6446 ppev[dwIndex].cbValueName = cbValueNameLen;
6448 ppev[dwIndex].dwType = dwType;
6450 memcpy (pEnumValues, lpValue, cbValueLen);
6451 ppev[dwIndex].pData = pEnumValues;
6452 pEnumValues += cbValueLen;
6454 ppev[dwIndex].cbData = cbValueLen;
6456 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6457 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6460 if (HeapFree (hHeap, 0, lpValue) == 0)
6462 ret = GetLastError ();
6463 ERR ("HeapFree failed with code %i\n", ret);
6464 if (HeapFree (hHeap, 0, lpValueName) == 0)
6465 WARN ("HeapFree failed with code %i\n", GetLastError ());
6466 r = RegCloseKey (hkSubKey);
6467 if (r != ERROR_SUCCESS)
6468 WARN ("RegCloseKey returned %i\n", r);
6469 return ret;
6472 if (HeapFree (hHeap, 0, lpValueName) == 0)
6474 ret = GetLastError ();
6475 ERR ("HeapFree failed with code %i\n", ret);
6476 r = RegCloseKey (hkSubKey);
6477 if (r != ERROR_SUCCESS)
6478 WARN ("RegCloseKey returned %i\n", r);
6479 return ret;
6482 ret = RegCloseKey (hkSubKey);
6483 if (ret != ERROR_SUCCESS)
6485 ERR ("RegCloseKey returned %i\n", ret);
6486 return ret;
6489 return ERROR_SUCCESS;
6492 /*******************************************************************************
6493 * EnumPrinterDataExA [WINSPOOL.@]
6495 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6496 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6497 * what Windows 2000 SP1 does.
6500 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6501 LPBYTE pEnumValues, DWORD cbEnumValues,
6502 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6504 INT len;
6505 LPWSTR pKeyNameW;
6506 DWORD ret, dwIndex, dwBufSize;
6507 HANDLE hHeap;
6508 LPSTR pBuffer;
6510 TRACE ("%p %s\n", hPrinter, pKeyName);
6512 if (pKeyName == NULL || *pKeyName == 0)
6513 return ERROR_INVALID_PARAMETER;
6515 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6516 if (len == 0)
6518 ret = GetLastError ();
6519 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6520 return ret;
6523 hHeap = GetProcessHeap ();
6524 if (hHeap == NULL)
6526 ERR ("GetProcessHeap failed\n");
6527 return ERROR_OUTOFMEMORY;
6530 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6531 if (pKeyNameW == NULL)
6533 ERR ("Failed to allocate %i bytes from process heap\n",
6534 (LONG)(len * sizeof (WCHAR)));
6535 return ERROR_OUTOFMEMORY;
6538 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6540 ret = GetLastError ();
6541 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6542 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6543 WARN ("HeapFree failed with code %i\n", GetLastError ());
6544 return ret;
6547 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6548 pcbEnumValues, pnEnumValues);
6549 if (ret != ERROR_SUCCESS)
6551 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6552 WARN ("HeapFree failed with code %i\n", GetLastError ());
6553 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6554 return ret;
6557 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6559 ret = GetLastError ();
6560 ERR ("HeapFree failed with code %i\n", ret);
6561 return ret;
6564 if (*pnEnumValues == 0) /* empty key */
6565 return ERROR_SUCCESS;
6567 dwBufSize = 0;
6568 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6570 PPRINTER_ENUM_VALUESW ppev =
6571 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6573 if (dwBufSize < ppev->cbValueName)
6574 dwBufSize = ppev->cbValueName;
6576 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6577 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6578 dwBufSize = ppev->cbData;
6581 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6583 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6584 if (pBuffer == NULL)
6586 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6587 return ERROR_OUTOFMEMORY;
6590 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6592 PPRINTER_ENUM_VALUESW ppev =
6593 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6595 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6596 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6597 NULL);
6598 if (len == 0)
6600 ret = GetLastError ();
6601 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6602 if (HeapFree (hHeap, 0, pBuffer) == 0)
6603 WARN ("HeapFree failed with code %i\n", GetLastError ());
6604 return ret;
6607 memcpy (ppev->pValueName, pBuffer, len);
6609 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6611 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6612 ppev->dwType != REG_MULTI_SZ)
6613 continue;
6615 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6616 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6617 if (len == 0)
6619 ret = GetLastError ();
6620 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6621 if (HeapFree (hHeap, 0, pBuffer) == 0)
6622 WARN ("HeapFree failed with code %i\n", GetLastError ());
6623 return ret;
6626 memcpy (ppev->pData, pBuffer, len);
6628 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6629 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6632 if (HeapFree (hHeap, 0, pBuffer) == 0)
6634 ret = GetLastError ();
6635 ERR ("HeapFree failed with code %i\n", ret);
6636 return ret;
6639 return ERROR_SUCCESS;
6642 /******************************************************************************
6643 * AbortPrinter (WINSPOOL.@)
6645 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6647 FIXME("(%p), stub!\n", hPrinter);
6648 return TRUE;
6651 /******************************************************************************
6652 * AddPortA (WINSPOOL.@)
6654 * See AddPortW.
6657 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6659 LPWSTR nameW = NULL;
6660 LPWSTR monitorW = NULL;
6661 DWORD len;
6662 BOOL res;
6664 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6666 if (pName) {
6667 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6668 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6669 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6672 if (pMonitorName) {
6673 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6674 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6675 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6677 res = AddPortW(nameW, hWnd, monitorW);
6678 HeapFree(GetProcessHeap(), 0, nameW);
6679 HeapFree(GetProcessHeap(), 0, monitorW);
6680 return res;
6683 /******************************************************************************
6684 * AddPortW (WINSPOOL.@)
6686 * Add a Port for a specific Monitor
6688 * PARAMS
6689 * pName [I] Servername or NULL (local Computer)
6690 * hWnd [I] Handle to parent Window for the Dialog-Box
6691 * pMonitorName [I] Name of the Monitor that manage the Port
6693 * RETURNS
6694 * Success: TRUE
6695 * Failure: FALSE
6698 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6700 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6702 if ((backend == NULL) && !load_backend()) return FALSE;
6704 if (!pMonitorName) {
6705 SetLastError(RPC_X_NULL_REF_POINTER);
6706 return FALSE;
6709 return backend->fpAddPort(pName, hWnd, pMonitorName);
6712 /******************************************************************************
6713 * AddPortExA (WINSPOOL.@)
6715 * See AddPortExW.
6718 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6720 PORT_INFO_2W pi2W;
6721 PORT_INFO_2A * pi2A;
6722 LPWSTR nameW = NULL;
6723 LPWSTR monitorW = NULL;
6724 DWORD len;
6725 BOOL res;
6727 pi2A = (PORT_INFO_2A *) pBuffer;
6729 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6730 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6732 if ((level < 1) || (level > 2)) {
6733 SetLastError(ERROR_INVALID_LEVEL);
6734 return FALSE;
6737 if (!pi2A) {
6738 SetLastError(ERROR_INVALID_PARAMETER);
6739 return FALSE;
6742 if (pName) {
6743 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6744 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6745 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6748 if (pMonitorName) {
6749 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6750 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6751 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6754 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6756 if (pi2A->pPortName) {
6757 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6758 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6759 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6762 if (level > 1) {
6763 if (pi2A->pMonitorName) {
6764 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6765 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6766 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6769 if (pi2A->pDescription) {
6770 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6771 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6772 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6774 pi2W.fPortType = pi2A->fPortType;
6775 pi2W.Reserved = pi2A->Reserved;
6778 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6780 HeapFree(GetProcessHeap(), 0, nameW);
6781 HeapFree(GetProcessHeap(), 0, monitorW);
6782 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6783 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6784 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6785 return res;
6789 /******************************************************************************
6790 * AddPortExW (WINSPOOL.@)
6792 * Add a Port for a specific Monitor, without presenting a user interface
6794 * PARAMS
6795 * pName [I] Servername or NULL (local Computer)
6796 * level [I] Structure-Level (1 or 2) for pBuffer
6797 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6798 * pMonitorName [I] Name of the Monitor that manage the Port
6800 * RETURNS
6801 * Success: TRUE
6802 * Failure: FALSE
6805 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6807 PORT_INFO_2W * pi2;
6809 pi2 = (PORT_INFO_2W *) pBuffer;
6811 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6812 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6813 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6814 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6816 if ((backend == NULL) && !load_backend()) return FALSE;
6818 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6819 SetLastError(ERROR_INVALID_PARAMETER);
6820 return FALSE;
6823 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6826 /******************************************************************************
6827 * AddPrinterConnectionA (WINSPOOL.@)
6829 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6831 FIXME("%s\n", debugstr_a(pName));
6832 return FALSE;
6835 /******************************************************************************
6836 * AddPrinterConnectionW (WINSPOOL.@)
6838 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6840 FIXME("%s\n", debugstr_w(pName));
6841 return FALSE;
6844 /******************************************************************************
6845 * AddPrinterDriverExW (WINSPOOL.@)
6847 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6849 * PARAMS
6850 * pName [I] Servername or NULL (local Computer)
6851 * level [I] Level for the supplied DRIVER_INFO_*W struct
6852 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6853 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6855 * RESULTS
6856 * Success: TRUE
6857 * Failure: FALSE
6860 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6862 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6864 if ((backend == NULL) && !load_backend()) return FALSE;
6866 if (level < 2 || level == 5 || level == 7 || level > 8) {
6867 SetLastError(ERROR_INVALID_LEVEL);
6868 return FALSE;
6871 if (!pDriverInfo) {
6872 SetLastError(ERROR_INVALID_PARAMETER);
6873 return FALSE;
6876 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6879 /******************************************************************************
6880 * AddPrinterDriverExA (WINSPOOL.@)
6882 * See AddPrinterDriverExW.
6885 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6887 DRIVER_INFO_8A *diA;
6888 DRIVER_INFO_8W diW;
6889 LPWSTR nameW = NULL;
6890 DWORD lenA;
6891 DWORD len;
6892 BOOL res = FALSE;
6894 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6896 diA = (DRIVER_INFO_8A *) pDriverInfo;
6897 ZeroMemory(&diW, sizeof(diW));
6899 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6900 SetLastError(ERROR_INVALID_LEVEL);
6901 return FALSE;
6904 if (diA == NULL) {
6905 SetLastError(ERROR_INVALID_PARAMETER);
6906 return FALSE;
6909 /* convert servername to unicode */
6910 if (pName) {
6911 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6912 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6913 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6916 /* common fields */
6917 diW.cVersion = diA->cVersion;
6919 if (diA->pName) {
6920 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6921 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6922 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6925 if (diA->pEnvironment) {
6926 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6927 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6928 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6931 if (diA->pDriverPath) {
6932 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6933 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6934 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6937 if (diA->pDataFile) {
6938 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6939 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6940 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6943 if (diA->pConfigFile) {
6944 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6945 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6946 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6949 if ((Level > 2) && diA->pHelpFile) {
6950 len = MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, NULL, 0);
6951 diW.pHelpFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6952 MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, diW.pHelpFile, len);
6955 if ((Level > 2) && diA->pDependentFiles) {
6956 lenA = multi_sz_lenA(diA->pDependentFiles);
6957 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6958 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6959 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6962 if ((Level > 2) && diA->pMonitorName) {
6963 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6964 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6965 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6968 if ((Level > 2) && diA->pDefaultDataType) {
6969 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6970 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6971 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6974 if ((Level > 3) && diA->pszzPreviousNames) {
6975 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6976 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6977 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6978 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6981 if (Level > 5) {
6982 diW.ftDriverDate = diA->ftDriverDate;
6983 diW.dwlDriverVersion = diA->dwlDriverVersion;
6986 if ((Level > 5) && diA->pszMfgName) {
6987 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6988 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6989 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6992 if ((Level > 5) && diA->pszOEMUrl) {
6993 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6994 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6995 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6998 if ((Level > 5) && diA->pszHardwareID) {
6999 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
7000 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7001 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
7004 if ((Level > 5) && diA->pszProvider) {
7005 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
7006 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7007 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
7010 if ((Level > 7) && diA->pszPrintProcessor) {
7011 len = MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, NULL, 0);
7012 diW.pszPrintProcessor = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7013 MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, diW.pszPrintProcessor, len);
7016 if ((Level > 7) && diA->pszVendorSetup) {
7017 len = MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, NULL, 0);
7018 diW.pszVendorSetup = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7019 MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, diW.pszVendorSetup, len);
7022 if ((Level > 7) && diA->pszzColorProfiles) {
7023 lenA = multi_sz_lenA(diA->pszzColorProfiles);
7024 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, NULL, 0);
7025 diW.pszzColorProfiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7026 MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, diW.pszzColorProfiles, len);
7029 if ((Level > 7) && diA->pszInfPath) {
7030 len = MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, NULL, 0);
7031 diW.pszInfPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7032 MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, diW.pszInfPath, len);
7035 if ((Level > 7) && diA->pszzCoreDriverDependencies) {
7036 lenA = multi_sz_lenA(diA->pszzCoreDriverDependencies);
7037 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, NULL, 0);
7038 diW.pszzCoreDriverDependencies = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7039 MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, diW.pszzCoreDriverDependencies, len);
7042 if (Level > 7) {
7043 diW.dwPrinterDriverAttributes = diA->dwPrinterDriverAttributes;
7044 diW.ftMinInboxDriverVerDate = diA->ftMinInboxDriverVerDate;
7045 diW.dwlMinInboxDriverVerVersion = diA->dwlMinInboxDriverVerVersion;
7048 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
7049 TRACE("got %u with %u\n", res, GetLastError());
7050 HeapFree(GetProcessHeap(), 0, nameW);
7051 HeapFree(GetProcessHeap(), 0, diW.pName);
7052 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
7053 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
7054 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
7055 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
7056 HeapFree(GetProcessHeap(), 0, diW.pHelpFile);
7057 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
7058 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
7059 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
7060 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
7061 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
7062 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
7063 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
7064 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
7065 HeapFree(GetProcessHeap(), 0, diW.pszPrintProcessor);
7066 HeapFree(GetProcessHeap(), 0, diW.pszVendorSetup);
7067 HeapFree(GetProcessHeap(), 0, diW.pszzColorProfiles);
7068 HeapFree(GetProcessHeap(), 0, diW.pszInfPath);
7069 HeapFree(GetProcessHeap(), 0, diW.pszzCoreDriverDependencies);
7071 TRACE("=> %u with %u\n", res, GetLastError());
7072 return res;
7075 /******************************************************************************
7076 * ConfigurePortA (WINSPOOL.@)
7078 * See ConfigurePortW.
7081 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7083 LPWSTR nameW = NULL;
7084 LPWSTR portW = NULL;
7085 INT len;
7086 DWORD res;
7088 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7090 /* convert servername to unicode */
7091 if (pName) {
7092 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7093 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7094 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7097 /* convert portname to unicode */
7098 if (pPortName) {
7099 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7100 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7101 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7104 res = ConfigurePortW(nameW, hWnd, portW);
7105 HeapFree(GetProcessHeap(), 0, nameW);
7106 HeapFree(GetProcessHeap(), 0, portW);
7107 return res;
7110 /******************************************************************************
7111 * ConfigurePortW (WINSPOOL.@)
7113 * Display the Configuration-Dialog for a specific Port
7115 * PARAMS
7116 * pName [I] Servername or NULL (local Computer)
7117 * hWnd [I] Handle to parent Window for the Dialog-Box
7118 * pPortName [I] Name of the Port, that should be configured
7120 * RETURNS
7121 * Success: TRUE
7122 * Failure: FALSE
7125 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7128 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7130 if ((backend == NULL) && !load_backend()) return FALSE;
7132 if (!pPortName) {
7133 SetLastError(RPC_X_NULL_REF_POINTER);
7134 return FALSE;
7137 return backend->fpConfigurePort(pName, hWnd, pPortName);
7140 /******************************************************************************
7141 * ConnectToPrinterDlg (WINSPOOL.@)
7143 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7145 FIXME("%p %x\n", hWnd, Flags);
7146 return NULL;
7149 /******************************************************************************
7150 * DeletePrinterConnectionA (WINSPOOL.@)
7152 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7154 FIXME("%s\n", debugstr_a(pName));
7155 return TRUE;
7158 /******************************************************************************
7159 * DeletePrinterConnectionW (WINSPOOL.@)
7161 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7163 FIXME("%s\n", debugstr_w(pName));
7164 return TRUE;
7167 /******************************************************************************
7168 * DeletePrinterDriverExW (WINSPOOL.@)
7170 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7171 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7173 HKEY hkey_drivers;
7174 BOOL ret = FALSE;
7176 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7177 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7179 if(pName && pName[0])
7181 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7182 SetLastError(ERROR_INVALID_PARAMETER);
7183 return FALSE;
7186 if(dwDeleteFlag)
7188 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7189 SetLastError(ERROR_INVALID_PARAMETER);
7190 return FALSE;
7193 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7195 if(!hkey_drivers)
7197 ERR("Can't open drivers key\n");
7198 return FALSE;
7201 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7202 ret = TRUE;
7204 RegCloseKey(hkey_drivers);
7206 return ret;
7209 /******************************************************************************
7210 * DeletePrinterDriverExA (WINSPOOL.@)
7212 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7213 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7215 UNICODE_STRING NameW, EnvW, DriverW;
7216 BOOL ret;
7218 asciitounicode(&NameW, pName);
7219 asciitounicode(&EnvW, pEnvironment);
7220 asciitounicode(&DriverW, pDriverName);
7222 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7224 RtlFreeUnicodeString(&DriverW);
7225 RtlFreeUnicodeString(&EnvW);
7226 RtlFreeUnicodeString(&NameW);
7228 return ret;
7231 /******************************************************************************
7232 * DeletePrinterDataExW (WINSPOOL.@)
7234 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7235 LPCWSTR pValueName)
7237 FIXME("%p %s %s\n", hPrinter,
7238 debugstr_w(pKeyName), debugstr_w(pValueName));
7239 return ERROR_INVALID_PARAMETER;
7242 /******************************************************************************
7243 * DeletePrinterDataExA (WINSPOOL.@)
7245 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7246 LPCSTR pValueName)
7248 FIXME("%p %s %s\n", hPrinter,
7249 debugstr_a(pKeyName), debugstr_a(pValueName));
7250 return ERROR_INVALID_PARAMETER;
7253 /******************************************************************************
7254 * DeletePrintProcessorA (WINSPOOL.@)
7256 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7258 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7259 debugstr_a(pPrintProcessorName));
7260 return TRUE;
7263 /******************************************************************************
7264 * DeletePrintProcessorW (WINSPOOL.@)
7266 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7268 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7269 debugstr_w(pPrintProcessorName));
7270 return TRUE;
7273 /******************************************************************************
7274 * DeletePrintProvidorA (WINSPOOL.@)
7276 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7278 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7279 debugstr_a(pPrintProviderName));
7280 return TRUE;
7283 /******************************************************************************
7284 * DeletePrintProvidorW (WINSPOOL.@)
7286 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7288 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7289 debugstr_w(pPrintProviderName));
7290 return TRUE;
7293 /******************************************************************************
7294 * EnumFormsA (WINSPOOL.@)
7296 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7297 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7299 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7300 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7301 return FALSE;
7304 /******************************************************************************
7305 * EnumFormsW (WINSPOOL.@)
7307 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7308 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7310 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7311 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7312 return FALSE;
7315 /*****************************************************************************
7316 * EnumMonitorsA [WINSPOOL.@]
7318 * See EnumMonitorsW.
7321 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7322 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7324 BOOL res;
7325 LPBYTE bufferW = NULL;
7326 LPWSTR nameW = NULL;
7327 DWORD needed = 0;
7328 DWORD numentries = 0;
7329 INT len;
7331 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7332 cbBuf, pcbNeeded, pcReturned);
7334 /* convert servername to unicode */
7335 if (pName) {
7336 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7337 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7338 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7340 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7341 needed = cbBuf * sizeof(WCHAR);
7342 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7343 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7345 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7346 if (pcbNeeded) needed = *pcbNeeded;
7347 /* HeapReAlloc return NULL, when bufferW was NULL */
7348 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7349 HeapAlloc(GetProcessHeap(), 0, needed);
7351 /* Try again with the large Buffer */
7352 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7354 numentries = pcReturned ? *pcReturned : 0;
7355 needed = 0;
7357 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7358 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7360 if (res) {
7361 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7362 DWORD entrysize = 0;
7363 DWORD index;
7364 LPSTR ptr;
7365 LPMONITOR_INFO_2W mi2w;
7366 LPMONITOR_INFO_2A mi2a;
7368 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7369 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7371 /* First pass: calculate the size for all Entries */
7372 mi2w = (LPMONITOR_INFO_2W) bufferW;
7373 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7374 index = 0;
7375 while (index < numentries) {
7376 index++;
7377 needed += entrysize; /* MONITOR_INFO_?A */
7378 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7380 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7381 NULL, 0, NULL, NULL);
7382 if (Level > 1) {
7383 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7384 NULL, 0, NULL, NULL);
7385 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7386 NULL, 0, NULL, NULL);
7388 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7389 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7390 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7393 /* check for errors and quit on failure */
7394 if (cbBuf < needed) {
7395 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7396 res = FALSE;
7397 goto emA_cleanup;
7399 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7400 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7401 cbBuf -= len ; /* free Bytes in the user-Buffer */
7402 mi2w = (LPMONITOR_INFO_2W) bufferW;
7403 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7404 index = 0;
7405 /* Second Pass: Fill the User Buffer (if we have one) */
7406 while ((index < numentries) && pMonitors) {
7407 index++;
7408 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7409 mi2a->pName = ptr;
7410 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7411 ptr, cbBuf , NULL, NULL);
7412 ptr += len;
7413 cbBuf -= len;
7414 if (Level > 1) {
7415 mi2a->pEnvironment = ptr;
7416 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7417 ptr, cbBuf, NULL, NULL);
7418 ptr += len;
7419 cbBuf -= len;
7421 mi2a->pDLLName = ptr;
7422 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7423 ptr, cbBuf, NULL, NULL);
7424 ptr += len;
7425 cbBuf -= len;
7427 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7428 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7429 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7432 emA_cleanup:
7433 if (pcbNeeded) *pcbNeeded = needed;
7434 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7436 HeapFree(GetProcessHeap(), 0, nameW);
7437 HeapFree(GetProcessHeap(), 0, bufferW);
7439 TRACE("returning %d with %d (%d byte for %d entries)\n",
7440 (res), GetLastError(), needed, numentries);
7442 return (res);
7446 /*****************************************************************************
7447 * EnumMonitorsW [WINSPOOL.@]
7449 * Enumerate available Port-Monitors
7451 * PARAMS
7452 * pName [I] Servername or NULL (local Computer)
7453 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7454 * pMonitors [O] PTR to Buffer that receives the Result
7455 * cbBuf [I] Size of Buffer at pMonitors
7456 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7457 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7459 * RETURNS
7460 * Success: TRUE
7461 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7464 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7465 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7468 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7469 cbBuf, pcbNeeded, pcReturned);
7471 if ((backend == NULL) && !load_backend()) return FALSE;
7473 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7474 SetLastError(RPC_X_NULL_REF_POINTER);
7475 return FALSE;
7478 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7481 /******************************************************************************
7482 * SpoolerInit (WINSPOOL.@)
7484 * Initialize the Spooler
7486 * RETURNS
7487 * Success: TRUE
7488 * Failure: FALSE
7490 * NOTES
7491 * The function fails on windows, when the spooler service is not running
7494 BOOL WINAPI SpoolerInit(void)
7497 if ((backend == NULL) && !load_backend()) return FALSE;
7498 return TRUE;
7501 /******************************************************************************
7502 * XcvDataW (WINSPOOL.@)
7504 * Execute commands in the Printmonitor DLL
7506 * PARAMS
7507 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7508 * pszDataName [i] Name of the command to execute
7509 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7510 * cbInputData [i] Size in Bytes of Buffer at pInputData
7511 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7512 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7513 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7514 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7516 * RETURNS
7517 * Success: TRUE
7518 * Failure: FALSE
7520 * NOTES
7521 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7522 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7524 * Minimal List of commands, that a Printmonitor DLL should support:
7526 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7527 *| "AddPort" : Add a Port
7528 *| "DeletePort": Delete a Port
7530 * Many Printmonitors support additional commands. Examples for localspl.dll:
7531 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7532 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7535 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7536 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7537 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7539 opened_printer_t *printer;
7541 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7542 pInputData, cbInputData, pOutputData,
7543 cbOutputData, pcbOutputNeeded, pdwStatus);
7545 if ((backend == NULL) && !load_backend()) return FALSE;
7547 printer = get_opened_printer(hXcv);
7548 if (!printer || (!printer->backend_printer)) {
7549 SetLastError(ERROR_INVALID_HANDLE);
7550 return FALSE;
7553 if (!pcbOutputNeeded) {
7554 SetLastError(ERROR_INVALID_PARAMETER);
7555 return FALSE;
7558 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7559 SetLastError(RPC_X_NULL_REF_POINTER);
7560 return FALSE;
7563 *pcbOutputNeeded = 0;
7565 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7566 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7570 /*****************************************************************************
7571 * EnumPrinterDataA [WINSPOOL.@]
7574 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7575 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7576 DWORD cbData, LPDWORD pcbData )
7578 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7579 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7580 return ERROR_NO_MORE_ITEMS;
7583 /*****************************************************************************
7584 * EnumPrinterDataW [WINSPOOL.@]
7587 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7588 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7589 DWORD cbData, LPDWORD pcbData )
7591 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7592 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7593 return ERROR_NO_MORE_ITEMS;
7596 /*****************************************************************************
7597 * EnumPrinterKeyA [WINSPOOL.@]
7600 DWORD WINAPI EnumPrinterKeyA(HANDLE printer, const CHAR *key, CHAR *subkey, DWORD size, DWORD *needed)
7602 FIXME("%p %s %p %x %p\n", printer, debugstr_a(key), subkey, size, needed);
7603 return ERROR_CALL_NOT_IMPLEMENTED;
7606 /*****************************************************************************
7607 * EnumPrinterKeyW [WINSPOOL.@]
7610 DWORD WINAPI EnumPrinterKeyW(HANDLE printer, const WCHAR *key, WCHAR *subkey, DWORD size, DWORD *needed)
7612 FIXME("%p %s %p %x %p\n", printer, debugstr_w(key), subkey, size, needed);
7613 return ERROR_CALL_NOT_IMPLEMENTED;
7616 /*****************************************************************************
7617 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7620 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7621 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7622 LPDWORD pcbNeeded, LPDWORD pcReturned)
7624 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7625 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7626 pcbNeeded, pcReturned);
7627 return FALSE;
7630 /*****************************************************************************
7631 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7634 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7635 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7636 LPDWORD pcbNeeded, LPDWORD pcReturned)
7638 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7639 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7640 pcbNeeded, pcReturned);
7641 return FALSE;
7644 /*****************************************************************************
7645 * EnumPrintProcessorsA [WINSPOOL.@]
7647 * See EnumPrintProcessorsW.
7650 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7651 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7653 BOOL res;
7654 LPBYTE bufferW = NULL;
7655 LPWSTR nameW = NULL;
7656 LPWSTR envW = NULL;
7657 DWORD needed = 0;
7658 DWORD numentries = 0;
7659 INT len;
7661 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7662 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7664 /* convert names to unicode */
7665 if (pName) {
7666 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7667 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7668 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7670 if (pEnvironment) {
7671 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7672 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7673 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7676 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7677 needed = cbBuf * sizeof(WCHAR);
7678 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7679 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7681 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7682 if (pcbNeeded) needed = *pcbNeeded;
7683 /* HeapReAlloc return NULL, when bufferW was NULL */
7684 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7685 HeapAlloc(GetProcessHeap(), 0, needed);
7687 /* Try again with the large Buffer */
7688 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7690 numentries = pcReturned ? *pcReturned : 0;
7691 needed = 0;
7693 if (res) {
7694 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7695 DWORD index;
7696 LPSTR ptr;
7697 PPRINTPROCESSOR_INFO_1W ppiw;
7698 PPRINTPROCESSOR_INFO_1A ppia;
7700 /* First pass: calculate the size for all Entries */
7701 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7702 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7703 index = 0;
7704 while (index < numentries) {
7705 index++;
7706 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7707 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7709 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7710 NULL, 0, NULL, NULL);
7712 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7713 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7716 /* check for errors and quit on failure */
7717 if (cbBuf < needed) {
7718 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7719 res = FALSE;
7720 goto epp_cleanup;
7723 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7724 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7725 cbBuf -= len ; /* free Bytes in the user-Buffer */
7726 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7727 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7728 index = 0;
7729 /* Second Pass: Fill the User Buffer (if we have one) */
7730 while ((index < numentries) && pPPInfo) {
7731 index++;
7732 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7733 ppia->pName = ptr;
7734 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7735 ptr, cbBuf , NULL, NULL);
7736 ptr += len;
7737 cbBuf -= len;
7739 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7740 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7744 epp_cleanup:
7745 if (pcbNeeded) *pcbNeeded = needed;
7746 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7748 HeapFree(GetProcessHeap(), 0, nameW);
7749 HeapFree(GetProcessHeap(), 0, envW);
7750 HeapFree(GetProcessHeap(), 0, bufferW);
7752 TRACE("returning %d with %d (%d byte for %d entries)\n",
7753 (res), GetLastError(), needed, numentries);
7755 return (res);
7758 /*****************************************************************************
7759 * EnumPrintProcessorsW [WINSPOOL.@]
7761 * Enumerate available Print Processors
7763 * PARAMS
7764 * pName [I] Servername or NULL (local Computer)
7765 * pEnvironment [I] Printing-Environment or NULL (Default)
7766 * Level [I] Structure-Level (Only 1 is allowed)
7767 * pPPInfo [O] PTR to Buffer that receives the Result
7768 * cbBuf [I] Size of Buffer at pPPInfo
7769 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7770 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7772 * RETURNS
7773 * Success: TRUE
7774 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7777 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7778 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7781 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7782 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7784 if ((backend == NULL) && !load_backend()) return FALSE;
7786 if (!pcbNeeded || !pcReturned) {
7787 SetLastError(RPC_X_NULL_REF_POINTER);
7788 return FALSE;
7791 if (!pPPInfo && (cbBuf > 0)) {
7792 SetLastError(ERROR_INVALID_USER_BUFFER);
7793 return FALSE;
7796 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7797 cbBuf, pcbNeeded, pcReturned);
7800 /*****************************************************************************
7801 * ExtDeviceMode [WINSPOOL.@]
7804 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7805 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7806 DWORD fMode)
7808 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7809 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7810 debugstr_a(pProfile), fMode);
7811 return -1;
7814 /*****************************************************************************
7815 * FindClosePrinterChangeNotification [WINSPOOL.@]
7818 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7820 FIXME("Stub: %p\n", hChange);
7821 return TRUE;
7824 /*****************************************************************************
7825 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7828 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7829 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7831 FIXME("Stub: %p %x %x %p\n",
7832 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7833 return INVALID_HANDLE_VALUE;
7836 /*****************************************************************************
7837 * FindNextPrinterChangeNotification [WINSPOOL.@]
7840 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7841 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7843 FIXME("Stub: %p %p %p %p\n",
7844 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7845 return FALSE;
7848 /*****************************************************************************
7849 * FreePrinterNotifyInfo [WINSPOOL.@]
7852 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7854 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7855 return TRUE;
7858 /*****************************************************************************
7859 * string_to_buf
7861 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7862 * ansi depending on the unicode parameter.
7864 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7866 if(!str)
7868 *size = 0;
7869 return TRUE;
7872 if(unicode)
7874 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7875 if(*size <= cb)
7877 memcpy(ptr, str, *size);
7878 return TRUE;
7880 return FALSE;
7882 else
7884 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7885 if(*size <= cb)
7887 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7888 return TRUE;
7890 return FALSE;
7894 /*****************************************************************************
7895 * get_job_info_1
7897 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7898 LPDWORD pcbNeeded, BOOL unicode)
7900 DWORD size, left = cbBuf;
7901 BOOL space = (cbBuf > 0);
7902 LPBYTE ptr = buf;
7904 *pcbNeeded = 0;
7906 if(space)
7908 ji1->JobId = job->job_id;
7911 string_to_buf(job->document_title, ptr, left, &size, unicode);
7912 if(space && size <= left)
7914 ji1->pDocument = (LPWSTR)ptr;
7915 ptr += size;
7916 left -= size;
7918 else
7919 space = FALSE;
7920 *pcbNeeded += size;
7922 if (job->printer_name)
7924 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7925 if(space && size <= left)
7927 ji1->pPrinterName = (LPWSTR)ptr;
7928 ptr += size;
7929 left -= size;
7931 else
7932 space = FALSE;
7933 *pcbNeeded += size;
7936 return space;
7939 /*****************************************************************************
7940 * get_job_info_2
7942 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7943 LPDWORD pcbNeeded, BOOL unicode)
7945 DWORD size, left = cbBuf;
7946 DWORD shift;
7947 BOOL space = (cbBuf > 0);
7948 LPBYTE ptr = buf;
7949 LPDEVMODEA dmA = NULL;
7950 LPDEVMODEW devmode;
7952 *pcbNeeded = 0;
7954 if(space)
7956 ji2->JobId = job->job_id;
7959 string_to_buf(job->document_title, ptr, left, &size, unicode);
7960 if(space && size <= left)
7962 ji2->pDocument = (LPWSTR)ptr;
7963 ptr += size;
7964 left -= size;
7966 else
7967 space = FALSE;
7968 *pcbNeeded += size;
7970 if (job->printer_name)
7972 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7973 if(space && size <= left)
7975 ji2->pPrinterName = (LPWSTR)ptr;
7976 ptr += size;
7977 left -= size;
7979 else
7980 space = FALSE;
7981 *pcbNeeded += size;
7984 if (job->devmode)
7986 if (!unicode)
7988 dmA = DEVMODEdupWtoA(job->devmode);
7989 devmode = (LPDEVMODEW) dmA;
7990 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7992 else
7994 devmode = job->devmode;
7995 size = devmode->dmSize + devmode->dmDriverExtra;
7998 if (!devmode)
7999 FIXME("Can't convert DEVMODE W to A\n");
8000 else
8002 /* align DEVMODE to a DWORD boundary */
8003 shift = (4 - (*pcbNeeded & 3)) & 3;
8004 size += shift;
8006 if (size <= left)
8008 ptr += shift;
8009 memcpy(ptr, devmode, size-shift);
8010 ji2->pDevMode = (LPDEVMODEW)ptr;
8011 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
8012 ptr += size-shift;
8013 left -= size;
8015 else
8016 space = FALSE;
8017 *pcbNeeded +=size;
8021 return space;
8024 /*****************************************************************************
8025 * get_job_info
8027 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8028 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
8030 BOOL ret = FALSE;
8031 DWORD needed = 0, size;
8032 job_t *job;
8033 LPBYTE ptr = pJob;
8035 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
8037 EnterCriticalSection(&printer_handles_cs);
8038 job = get_job(hPrinter, JobId);
8039 if(!job)
8040 goto end;
8042 switch(Level)
8044 case 1:
8045 size = sizeof(JOB_INFO_1W);
8046 if(cbBuf >= size)
8048 cbBuf -= size;
8049 ptr += size;
8050 memset(pJob, 0, size);
8052 else
8053 cbBuf = 0;
8054 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
8055 needed += size;
8056 break;
8058 case 2:
8059 size = sizeof(JOB_INFO_2W);
8060 if(cbBuf >= size)
8062 cbBuf -= size;
8063 ptr += size;
8064 memset(pJob, 0, size);
8066 else
8067 cbBuf = 0;
8068 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
8069 needed += size;
8070 break;
8072 case 3:
8073 size = sizeof(JOB_INFO_3);
8074 if(cbBuf >= size)
8076 cbBuf -= size;
8077 memset(pJob, 0, size);
8078 ret = TRUE;
8080 else
8081 cbBuf = 0;
8082 needed = size;
8083 break;
8085 default:
8086 SetLastError(ERROR_INVALID_LEVEL);
8087 goto end;
8089 if(pcbNeeded)
8090 *pcbNeeded = needed;
8091 end:
8092 LeaveCriticalSection(&printer_handles_cs);
8093 return ret;
8096 /*****************************************************************************
8097 * GetJobA [WINSPOOL.@]
8100 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8101 DWORD cbBuf, LPDWORD pcbNeeded)
8103 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8106 /*****************************************************************************
8107 * GetJobW [WINSPOOL.@]
8110 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8111 DWORD cbBuf, LPDWORD pcbNeeded)
8113 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8116 /*****************************************************************************
8117 * schedule_pipe
8119 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8121 #ifdef HAVE_FORK
8122 char *unixname, *cmdA;
8123 DWORD len;
8124 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8125 BOOL ret = FALSE;
8126 char buf[1024];
8127 pid_t pid, wret;
8128 int status;
8130 if(!(unixname = wine_get_unix_file_name(filename)))
8131 return FALSE;
8133 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8134 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8135 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8137 TRACE("printing with: %s\n", cmdA);
8139 if((file_fd = open(unixname, O_RDONLY)) == -1)
8140 goto end;
8142 if (pipe(fds))
8144 ERR("pipe() failed!\n");
8145 goto end;
8148 if ((pid = fork()) == 0)
8150 close(0);
8151 dup2(fds[0], 0);
8152 close(fds[1]);
8154 /* reset signals that we previously set to SIG_IGN */
8155 signal(SIGPIPE, SIG_DFL);
8157 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8158 _exit(1);
8160 else if (pid == -1)
8162 ERR("fork() failed!\n");
8163 goto end;
8166 close(fds[0]);
8167 fds[0] = -1;
8168 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8169 write(fds[1], buf, no_read);
8171 close(fds[1]);
8172 fds[1] = -1;
8174 /* reap child */
8175 do {
8176 wret = waitpid(pid, &status, 0);
8177 } while (wret < 0 && errno == EINTR);
8178 if (wret < 0)
8180 ERR("waitpid() failed!\n");
8181 goto end;
8183 if (!WIFEXITED(status) || WEXITSTATUS(status))
8185 ERR("child process failed! %d\n", status);
8186 goto end;
8189 ret = TRUE;
8191 end:
8192 if(file_fd != -1) close(file_fd);
8193 if(fds[0] != -1) close(fds[0]);
8194 if(fds[1] != -1) close(fds[1]);
8196 HeapFree(GetProcessHeap(), 0, cmdA);
8197 HeapFree(GetProcessHeap(), 0, unixname);
8198 return ret;
8199 #else
8200 return FALSE;
8201 #endif
8204 /*****************************************************************************
8205 * schedule_lpr
8207 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8209 WCHAR *cmd;
8210 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8211 BOOL r;
8213 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8214 sprintfW(cmd, fmtW, printer_name);
8216 r = schedule_pipe(cmd, filename);
8218 HeapFree(GetProcessHeap(), 0, cmd);
8219 return r;
8222 #ifdef SONAME_LIBCUPS
8223 /*****************************************************************************
8224 * get_cups_jobs_ticket_options
8226 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8227 * The CUPS scheduler only looks for these in Print-File requests, and since
8228 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8229 * parsed.
8231 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8233 FILE *fp = fopen( file, "r" );
8234 char buf[257]; /* DSC max of 256 + '\0' */
8235 const char *ps_adobe = "%!PS-Adobe-";
8236 const char *cups_job = "%cupsJobTicket:";
8238 if (!fp) return num_options;
8239 if (!fgets( buf, sizeof(buf), fp )) goto end;
8240 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8241 while (fgets( buf, sizeof(buf), fp ))
8243 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8244 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8247 end:
8248 fclose( fp );
8249 return num_options;
8252 static int get_cups_default_options( const char *printer, int num_options, cups_option_t **options )
8254 cups_dest_t *dest;
8255 int i;
8257 if (!pcupsGetNamedDest) return num_options;
8259 dest = pcupsGetNamedDest( NULL, printer, NULL );
8260 if (!dest) return num_options;
8262 for (i = 0; i < dest->num_options; i++)
8264 if (!pcupsGetOption( dest->options[i].name, num_options, *options ))
8265 num_options = pcupsAddOption( dest->options[i].name, dest->options[i].value,
8266 num_options, options );
8269 pcupsFreeDests( 1, dest );
8270 return num_options;
8272 #endif
8274 /*****************************************************************************
8275 * schedule_cups
8277 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8279 #ifdef SONAME_LIBCUPS
8280 if(pcupsPrintFile)
8282 char *unixname, *queue, *unix_doc_title;
8283 DWORD len;
8284 BOOL ret;
8285 int num_options = 0, i;
8286 cups_option_t *options = NULL;
8288 if(!(unixname = wine_get_unix_file_name(filename)))
8289 return FALSE;
8291 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8292 queue = HeapAlloc(GetProcessHeap(), 0, len);
8293 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8295 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8296 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8297 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8299 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8300 num_options = get_cups_default_options( queue, num_options, &options );
8302 TRACE( "printing via cups with options:\n" );
8303 for (i = 0; i < num_options; i++)
8304 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8306 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8307 if (ret == 0 && pcupsLastErrorString)
8308 WARN("cupsPrintFile failed with error %s\n", debugstr_a(pcupsLastErrorString()));
8310 pcupsFreeOptions( num_options, options );
8312 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8313 HeapFree(GetProcessHeap(), 0, queue);
8314 HeapFree(GetProcessHeap(), 0, unixname);
8315 return ret;
8317 else
8318 #endif
8320 return schedule_lpr(printer_name, filename);
8324 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8326 LPWSTR filename;
8328 switch(msg)
8330 case WM_INITDIALOG:
8331 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8332 return TRUE;
8334 case WM_COMMAND:
8335 if(HIWORD(wparam) == BN_CLICKED)
8337 if(LOWORD(wparam) == IDOK)
8339 HANDLE hf;
8340 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8341 LPWSTR *output;
8343 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8344 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8346 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8348 WCHAR caption[200], message[200];
8349 int mb_ret;
8351 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, ARRAY_SIZE(caption));
8352 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, ARRAY_SIZE(message));
8353 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8354 if(mb_ret == IDCANCEL)
8356 HeapFree(GetProcessHeap(), 0, filename);
8357 return TRUE;
8360 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8361 if(hf == INVALID_HANDLE_VALUE)
8363 WCHAR caption[200], message[200];
8365 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, ARRAY_SIZE(caption));
8366 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, ARRAY_SIZE(message));
8367 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8368 HeapFree(GetProcessHeap(), 0, filename);
8369 return TRUE;
8371 CloseHandle(hf);
8372 DeleteFileW(filename);
8373 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8374 *output = filename;
8375 EndDialog(hwnd, IDOK);
8376 return TRUE;
8378 if(LOWORD(wparam) == IDCANCEL)
8380 EndDialog(hwnd, IDCANCEL);
8381 return TRUE;
8384 return FALSE;
8386 return FALSE;
8389 /*****************************************************************************
8390 * get_filename
8392 static BOOL get_filename(LPWSTR *filename)
8394 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8395 file_dlg_proc, (LPARAM)filename) == IDOK;
8398 /*****************************************************************************
8399 * schedule_file
8401 static BOOL schedule_file(LPCWSTR filename)
8403 LPWSTR output = NULL;
8405 if(get_filename(&output))
8407 BOOL r;
8408 TRACE("copy to %s\n", debugstr_w(output));
8409 r = CopyFileW(filename, output, FALSE);
8410 HeapFree(GetProcessHeap(), 0, output);
8411 return r;
8413 return FALSE;
8416 /*****************************************************************************
8417 * schedule_unixfile
8419 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8421 int in_fd, out_fd, no_read;
8422 char buf[1024];
8423 BOOL ret = FALSE;
8424 char *unixname, *outputA;
8425 DWORD len;
8427 if(!(unixname = wine_get_unix_file_name(filename)))
8428 return FALSE;
8430 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8431 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8432 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8434 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8435 in_fd = open(unixname, O_RDONLY);
8436 if(out_fd == -1 || in_fd == -1)
8437 goto end;
8439 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8440 write(out_fd, buf, no_read);
8442 ret = TRUE;
8443 end:
8444 if(in_fd != -1) close(in_fd);
8445 if(out_fd != -1) close(out_fd);
8446 HeapFree(GetProcessHeap(), 0, outputA);
8447 HeapFree(GetProcessHeap(), 0, unixname);
8448 return ret;
8451 /*****************************************************************************
8452 * ScheduleJob [WINSPOOL.@]
8455 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8457 opened_printer_t *printer;
8458 BOOL ret = FALSE;
8459 struct list *cursor, *cursor2;
8461 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8462 EnterCriticalSection(&printer_handles_cs);
8463 printer = get_opened_printer(hPrinter);
8464 if(!printer)
8465 goto end;
8467 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8469 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8470 HANDLE hf;
8472 if(job->job_id != dwJobID) continue;
8474 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8475 if(hf != INVALID_HANDLE_VALUE)
8477 PRINTER_INFO_5W *pi5 = NULL;
8478 LPWSTR portname = job->portname;
8479 DWORD needed;
8480 HKEY hkey;
8481 WCHAR output[1024];
8482 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8483 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8485 if (!portname)
8487 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8488 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8489 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8490 portname = pi5->pPortName;
8492 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8493 debugstr_w(portname));
8495 output[0] = 0;
8497 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8498 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8500 DWORD type, count = sizeof(output);
8501 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8502 RegCloseKey(hkey);
8504 if(output[0] == '|')
8506 ret = schedule_pipe(output + 1, job->filename);
8508 else if(output[0])
8510 ret = schedule_unixfile(output, job->filename);
8512 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8514 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8516 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8518 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8520 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8522 ret = schedule_file(job->filename);
8524 else if(isalpha(portname[0]) && portname[1] == ':')
8526 TRACE("copying to %s\n", debugstr_w(portname));
8527 ret = CopyFileW(job->filename, portname, FALSE);
8529 else
8531 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8533 HeapFree(GetProcessHeap(), 0, pi5);
8534 CloseHandle(hf);
8535 DeleteFileW(job->filename);
8537 list_remove(cursor);
8538 HeapFree(GetProcessHeap(), 0, job->document_title);
8539 HeapFree(GetProcessHeap(), 0, job->printer_name);
8540 HeapFree(GetProcessHeap(), 0, job->portname);
8541 HeapFree(GetProcessHeap(), 0, job->filename);
8542 HeapFree(GetProcessHeap(), 0, job->devmode);
8543 HeapFree(GetProcessHeap(), 0, job);
8544 break;
8546 end:
8547 LeaveCriticalSection(&printer_handles_cs);
8548 return ret;
8551 /*****************************************************************************
8552 * StartDocDlgA [WINSPOOL.@]
8554 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8556 UNICODE_STRING usBuffer;
8557 DOCINFOW docW = { 0 };
8558 LPWSTR retW;
8559 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8560 LPSTR ret = NULL;
8562 docW.cbSize = sizeof(docW);
8563 if (doc->lpszDocName)
8565 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8566 if (!(docW.lpszDocName = docnameW)) goto failed;
8568 if (doc->lpszOutput)
8570 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8571 if (!(docW.lpszOutput = outputW)) goto failed;
8573 if (doc->lpszDatatype)
8575 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8576 if (!(docW.lpszDatatype = datatypeW)) goto failed;
8578 docW.fwType = doc->fwType;
8580 retW = StartDocDlgW(hPrinter, &docW);
8582 if(retW)
8584 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8585 ret = HeapAlloc(GetProcessHeap(), 0, len);
8586 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8587 HeapFree(GetProcessHeap(), 0, retW);
8590 failed:
8591 HeapFree(GetProcessHeap(), 0, datatypeW);
8592 HeapFree(GetProcessHeap(), 0, outputW);
8593 HeapFree(GetProcessHeap(), 0, docnameW);
8595 return ret;
8598 /*****************************************************************************
8599 * StartDocDlgW [WINSPOOL.@]
8601 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8602 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8603 * port is "FILE:". Also returns the full path if passed a relative path.
8605 * The caller should free the returned string from the process heap.
8607 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8609 LPWSTR ret = NULL;
8610 DWORD len, attr;
8612 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8614 PRINTER_INFO_5W *pi5;
8615 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8616 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8617 return NULL;
8618 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8619 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8620 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8622 HeapFree(GetProcessHeap(), 0, pi5);
8623 return NULL;
8625 HeapFree(GetProcessHeap(), 0, pi5);
8628 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8630 LPWSTR name;
8632 if (get_filename(&name))
8634 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8636 HeapFree(GetProcessHeap(), 0, name);
8637 return NULL;
8639 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8640 GetFullPathNameW(name, len, ret, NULL);
8641 HeapFree(GetProcessHeap(), 0, name);
8643 return ret;
8646 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8647 return NULL;
8649 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8650 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8652 attr = GetFileAttributesW(ret);
8653 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8655 HeapFree(GetProcessHeap(), 0, ret);
8656 ret = NULL;
8658 return ret;
8661 /*****************************************************************************
8662 * UploadPrinterDriverPackageA [WINSPOOL.@]
8664 HRESULT WINAPI UploadPrinterDriverPackageA( LPCSTR server, LPCSTR path, LPCSTR env,
8665 DWORD flags, HWND hwnd, LPSTR dst, PULONG dstlen )
8667 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server), debugstr_a(path), debugstr_a(env),
8668 flags, hwnd, dst, dstlen);
8669 return E_NOTIMPL;
8672 /*****************************************************************************
8673 * UploadPrinterDriverPackageW [WINSPOOL.@]
8675 HRESULT WINAPI UploadPrinterDriverPackageW( LPCWSTR server, LPCWSTR path, LPCWSTR env,
8676 DWORD flags, HWND hwnd, LPWSTR dst, PULONG dstlen )
8678 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server), debugstr_w(path), debugstr_w(env),
8679 flags, hwnd, dst, dstlen);
8680 return E_NOTIMPL;
8683 /*****************************************************************************
8684 * PerfOpen [WINSPOOL.@]
8686 DWORD WINAPI PerfOpen(LPWSTR context)
8688 FIXME("%s: stub\n", debugstr_w(context));
8689 return ERROR_SUCCESS;
8692 /*****************************************************************************
8693 * PerfClose [WINSPOOL.@]
8695 DWORD WINAPI PerfClose(void)
8697 FIXME("stub\n");
8698 return ERROR_SUCCESS;
8701 /*****************************************************************************
8702 * PerfCollect [WINSPOOL.@]
8704 DWORD WINAPI PerfCollect(LPWSTR query, LPVOID *data, LPDWORD size, LPDWORD obj_count)
8706 FIXME("%s, %p, %p, %p: stub\n", debugstr_w(query), data, size, obj_count);
8707 *size = 0;
8708 *obj_count = 0;
8709 return ERROR_SUCCESS;