winepulse: Set pulse master volume to 0 when session is muted.
[wine.git] / dlls / winspool.drv / info.c
blob4d0542d20e38cfe864b692d3dfa2691a89dd4619
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include "wine/port.h"
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <stddef.h>
36 #include <errno.h>
37 #ifdef HAVE_SYS_WAIT_H
38 #include <sys/wait.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif
43 #include <signal.h>
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
46 #endif
47 #ifdef HAVE_CUPS_PPD_H
48 # include <cups/ppd.h>
49 #endif
51 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
52 #define GetCurrentProcess GetCurrentProcess_Mac
53 #define GetCurrentThread GetCurrentThread_Mac
54 #define LoadResource LoadResource_Mac
55 #define AnimatePalette AnimatePalette_Mac
56 #define EqualRgn EqualRgn_Mac
57 #define FillRgn FillRgn_Mac
58 #define FrameRgn FrameRgn_Mac
59 #define GetPixel GetPixel_Mac
60 #define InvertRgn InvertRgn_Mac
61 #define LineTo LineTo_Mac
62 #define OffsetRgn OffsetRgn_Mac
63 #define PaintRgn PaintRgn_Mac
64 #define Polygon Polygon_Mac
65 #define ResizePalette ResizePalette_Mac
66 #define SetRectRgn SetRectRgn_Mac
67 #define EqualRect EqualRect_Mac
68 #define FillRect FillRect_Mac
69 #define FrameRect FrameRect_Mac
70 #define GetCursor GetCursor_Mac
71 #define InvertRect InvertRect_Mac
72 #define OffsetRect OffsetRect_Mac
73 #define PtInRect PtInRect_Mac
74 #define SetCursor SetCursor_Mac
75 #define SetRect SetRect_Mac
76 #define ShowCursor ShowCursor_Mac
77 #define UnionRect UnionRect_Mac
78 #include <ApplicationServices/ApplicationServices.h>
79 #undef GetCurrentProcess
80 #undef GetCurrentThread
81 #undef LoadResource
82 #undef AnimatePalette
83 #undef EqualRgn
84 #undef FillRgn
85 #undef FrameRgn
86 #undef GetPixel
87 #undef InvertRgn
88 #undef LineTo
89 #undef OffsetRgn
90 #undef PaintRgn
91 #undef Polygon
92 #undef ResizePalette
93 #undef SetRectRgn
94 #undef EqualRect
95 #undef FillRect
96 #undef FrameRect
97 #undef GetCursor
98 #undef InvertRect
99 #undef OffsetRect
100 #undef PtInRect
101 #undef SetCursor
102 #undef SetRect
103 #undef ShowCursor
104 #undef UnionRect
105 #endif
107 #define NONAMELESSSTRUCT
108 #define NONAMELESSUNION
110 #include "windef.h"
111 #include "winbase.h"
112 #include "winuser.h"
113 #include "winerror.h"
114 #include "winreg.h"
115 #include "wingdi.h"
116 #include "winspool.h"
117 #include "winternl.h"
118 #include "wine/windef16.h"
119 #include "wine/unicode.h"
120 #include "wine/debug.h"
121 #include "wine/list.h"
122 #include "winnls.h"
124 #include "ddk/winsplp.h"
125 #include "wspool.h"
127 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
129 /* ############################### */
131 static CRITICAL_SECTION printer_handles_cs;
132 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
134 0, 0, &printer_handles_cs,
135 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
136 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
138 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
140 /* ############################### */
142 typedef struct {
143 DWORD job_id;
144 HANDLE hf;
145 } started_doc_t;
147 typedef struct {
148 struct list jobs;
149 LONG ref;
150 } jobqueue_t;
152 typedef struct {
153 LPWSTR name;
154 LPWSTR printername;
155 HANDLE backend_printer;
156 jobqueue_t *queue;
157 started_doc_t *doc;
158 DEVMODEW *devmode;
159 } opened_printer_t;
161 typedef struct {
162 struct list entry;
163 DWORD job_id;
164 WCHAR *filename;
165 WCHAR *portname;
166 WCHAR *document_title;
167 WCHAR *printer_name;
168 LPDEVMODEW devmode;
169 } job_t;
172 typedef struct {
173 LPCWSTR envname;
174 LPCWSTR subdir;
175 DWORD driverversion;
176 LPCWSTR versionregpath;
177 LPCWSTR versionsubdir;
178 } printenv_t;
180 /* ############################### */
182 static opened_printer_t **printer_handles;
183 static UINT nb_printer_handles;
184 static LONG next_job_id = 1;
186 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
187 WORD fwCapability, LPSTR lpszOutput,
188 LPDEVMODEA lpdm );
189 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
190 LPSTR lpszDevice, LPSTR lpszPort,
191 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
192 DWORD fwMode );
194 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
195 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
196 'c','o','n','t','r','o','l','\\',
197 'P','r','i','n','t','\\',
198 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
199 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
201 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
202 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
203 'C','o','n','t','r','o','l','\\',
204 'P','r','i','n','t','\\',
205 'P','r','i','n','t','e','r','s',0};
207 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
208 'M','i','c','r','o','s','o','f','t','\\',
209 'W','i','n','d','o','w','s',' ','N','T','\\',
210 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
211 'W','i','n','d','o','w','s',0};
213 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
214 'M','i','c','r','o','s','o','f','t','\\',
215 'W','i','n','d','o','w','s',' ','N','T','\\',
216 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
217 'D','e','v','i','c','e','s',0};
219 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
220 'M','i','c','r','o','s','o','f','t','\\',
221 'W','i','n','d','o','w','s',' ','N','T','\\',
222 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
223 'P','r','i','n','t','e','r','P','o','r','t','s',0};
225 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
226 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
227 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
228 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
229 static const WCHAR subdir_x64W[] = {'x','6','4',0};
230 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
231 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
232 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
233 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
234 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
236 static const WCHAR AttributesW[] = {'A','t','t','r','i','b','u','t','e','s',0};
237 static const WCHAR backslashW[] = {'\\',0};
238 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
239 'i','o','n',' ','F','i','l','e',0};
240 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
241 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
242 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
243 static const WCHAR Default_PriorityW[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
244 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
245 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
246 static const WCHAR dnsTimeoutW[] = {'d','n','s','T','i','m','e','o','u','t',0};
247 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
248 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
249 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
250 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
251 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
252 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
253 static const WCHAR NameW[] = {'N','a','m','e',0};
254 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
255 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
256 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
257 static const WCHAR PortW[] = {'P','o','r','t',0};
258 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
259 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
260 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
261 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',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 windowsW[] = {'w','i','n','d','o','w','s',0};
273 static WCHAR rawW[] = {'R','A','W',0};
274 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
275 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
276 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
277 static const WCHAR commaW[] = {',',0};
278 static WCHAR emptyStringW[] = {0};
280 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
282 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
283 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
284 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
286 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
287 'D','o','c','u','m','e','n','t',0};
289 static const WCHAR PPD_Overrides[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
290 static const WCHAR DefaultPageSize[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
292 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
293 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
294 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
295 0, sizeof(DRIVER_INFO_8W)};
298 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
299 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
300 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
301 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
302 sizeof(PRINTER_INFO_9W)};
304 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
305 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
306 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
308 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
310 /******************************************************************
311 * validate the user-supplied printing-environment [internal]
313 * PARAMS
314 * env [I] PTR to Environment-String or NULL
316 * RETURNS
317 * Failure: NULL
318 * Success: PTR to printenv_t
320 * NOTES
321 * An empty string is handled the same way as NULL.
322 * SetLastError(ERROR_INVALID_ENVIRONMENT) is called on Failure
326 static const printenv_t * validate_envW(LPCWSTR env)
328 const printenv_t *result = NULL;
329 unsigned int i;
331 TRACE("testing %s\n", debugstr_w(env));
332 if (env && env[0])
334 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
336 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
338 result = all_printenv[i];
339 break;
343 if (result == NULL) {
344 FIXME("unsupported Environment: %s\n", debugstr_w(env));
345 SetLastError(ERROR_INVALID_ENVIRONMENT);
347 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
349 else
351 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
353 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
355 return result;
359 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
360 if passed a NULL string. This returns NULLs to the result.
362 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
364 if ( (src) )
366 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
367 return usBufferPtr->Buffer;
369 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
370 return NULL;
373 static LPWSTR strdupW(LPCWSTR p)
375 LPWSTR ret;
376 DWORD len;
378 if(!p) return NULL;
379 len = (strlenW(p) + 1) * sizeof(WCHAR);
380 ret = HeapAlloc(GetProcessHeap(), 0, len);
381 memcpy(ret, p, len);
382 return ret;
385 static LPSTR strdupWtoA( LPCWSTR str )
387 LPSTR ret;
388 INT len;
390 if (!str) return NULL;
391 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
392 ret = HeapAlloc( GetProcessHeap(), 0, len );
393 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
394 return ret;
397 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
399 DEVMODEW *ret;
401 if (!dm) return NULL;
402 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
403 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
404 return ret;
407 /***********************************************************
408 * DEVMODEdupWtoA
409 * Creates an ansi copy of supplied devmode
411 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
413 LPDEVMODEA dmA;
414 DWORD size;
416 if (!dmW) return NULL;
417 size = dmW->dmSize - CCHDEVICENAME -
418 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
420 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
421 if (!dmA) return NULL;
423 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
424 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
426 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
428 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
429 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
431 else
433 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
434 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
435 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
436 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
438 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
441 dmA->dmSize = size;
442 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
443 return dmA;
447 /******************************************************************
448 * verify, that the filename is a local file
451 static inline BOOL is_local_file(LPWSTR name)
453 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
456 /* ################################ */
458 static int multi_sz_lenA(const char *str)
460 const char *ptr = str;
461 if(!str) return 0;
464 ptr += lstrlenA(ptr) + 1;
465 } while(*ptr);
467 return ptr - str + 1;
470 /*****************************************************************************
471 * get_dword_from_reg
473 * Return DWORD associated with name from hkey.
475 static DWORD get_dword_from_reg( HKEY hkey, const WCHAR *name )
477 DWORD sz = sizeof(DWORD), type, value = 0;
478 LONG ret;
480 ret = RegQueryValueExW( hkey, name, 0, &type, (LPBYTE)&value, &sz );
482 if (ret != ERROR_SUCCESS)
484 WARN( "Got ret = %d on name %s\n", ret, debugstr_w(name) );
485 return 0;
487 if (type != REG_DWORD)
489 ERR( "Got type %d\n", type );
490 return 0;
492 return value;
495 static inline DWORD set_reg_DWORD( HKEY hkey, const WCHAR *keyname, const DWORD value )
497 return RegSetValueExW( hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value) );
500 /******************************************************************
501 * get_opened_printer
502 * Get the pointer to the opened printer referred by the handle
504 static opened_printer_t *get_opened_printer(HANDLE hprn)
506 UINT_PTR idx = (UINT_PTR)hprn;
507 opened_printer_t *ret = NULL;
509 EnterCriticalSection(&printer_handles_cs);
511 if ((idx > 0) && (idx <= nb_printer_handles)) {
512 ret = printer_handles[idx - 1];
514 LeaveCriticalSection(&printer_handles_cs);
515 return ret;
518 /******************************************************************
519 * get_opened_printer_name
520 * Get the pointer to the opened printer name referred by the handle
522 static LPCWSTR get_opened_printer_name(HANDLE hprn)
524 opened_printer_t *printer = get_opened_printer(hprn);
525 if(!printer) return NULL;
526 return printer->name;
529 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
531 HKEY printers;
532 DWORD err;
534 *key = NULL;
535 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
536 if (err) return err;
538 err = RegOpenKeyW( printers, name, key );
539 if (err) err = ERROR_INVALID_PRINTER_NAME;
540 RegCloseKey( printers );
541 return err;
544 /******************************************************************
545 * WINSPOOL_GetOpenedPrinterRegKey
548 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
550 LPCWSTR name = get_opened_printer_name(hPrinter);
552 if(!name) return ERROR_INVALID_HANDLE;
553 return open_printer_reg_key( name, phkey );
556 static void set_default_printer(const char *devname, const char *name)
558 char *buf = HeapAlloc(GetProcessHeap(), 0, strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
559 HKEY hkey;
561 sprintf(buf, "%s,WINEPS.DRV,LPR:%s", devname, name);
562 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey))
564 RegSetValueExA(hkey, "Device", 0, REG_SZ, (BYTE *)buf, strlen(buf) + 1);
565 RegCloseKey(hkey);
567 HeapFree(GetProcessHeap(), 0, buf);
570 static BOOL add_printer_driver(const WCHAR *name, WCHAR *ppd)
572 DRIVER_INFO_3W di3;
573 unsigned int i;
574 BOOL res;
576 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
577 di3.cVersion = 3;
578 di3.pName = (WCHAR*)name;
579 di3.pDriverPath = driver_nt;
580 di3.pDataFile = ppd;
581 di3.pConfigFile = driver_nt;
582 di3.pDefaultDataType = rawW;
584 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
586 di3.pEnvironment = (WCHAR *) all_printenv[i]->envname;
587 if (all_printenv[i]->envname == envname_win40W)
589 /* We use wineps16.drv as driver for 16 bit */
590 di3.pDriverPath = driver_9x;
591 di3.pConfigFile = driver_9x;
593 res = AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY );
594 TRACE("got %d and %d for %s (%s)\n", res, GetLastError(), debugstr_w(name), debugstr_w(di3.pEnvironment));
596 if (!res && (GetLastError() != ERROR_PRINTER_DRIVER_ALREADY_INSTALLED))
598 ERR("failed with %u for %s (%s) %s\n", GetLastError(), debugstr_w(name),
599 debugstr_w(di3.pEnvironment), debugstr_w(di3.pDriverPath));
600 return FALSE;
604 return TRUE;
607 static inline char *expand_env_string( char *str, DWORD type )
609 if (type == REG_EXPAND_SZ)
611 char *tmp;
612 DWORD needed = ExpandEnvironmentStringsA( str, NULL, 0 );
613 tmp = HeapAlloc( GetProcessHeap(), 0, needed );
614 if (tmp)
616 ExpandEnvironmentStringsA( str, tmp, needed );
617 HeapFree( GetProcessHeap(), 0, str );
618 return tmp;
621 return str;
624 static char *get_fallback_ppd_name( const char *printer_name )
626 static const WCHAR ppds_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
627 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
628 HKEY hkey;
629 DWORD needed, type;
630 char *ret = NULL;
632 if (RegOpenKeyW( HKEY_CURRENT_USER, ppds_key, &hkey ) == ERROR_SUCCESS )
634 const char *value_name = NULL;
636 if (RegQueryValueExA( hkey, printer_name, 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
637 value_name = printer_name;
638 else if (RegQueryValueExA( hkey, "generic", 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
639 value_name = "generic";
641 if (value_name)
643 ret = HeapAlloc( GetProcessHeap(), 0, needed );
644 if (!ret) return NULL;
645 RegQueryValueExA( hkey, value_name, 0, &type, (BYTE *)ret, &needed );
647 RegCloseKey( hkey );
648 if (ret) return expand_env_string( ret, type );
650 return NULL;
653 static BOOL copy_file( const char *src, const char *dst )
655 int fds[2] = {-1, -1}, num;
656 char buf[1024];
657 BOOL ret = FALSE;
659 fds[0] = open( src, O_RDONLY );
660 fds[1] = open( dst, O_CREAT | O_TRUNC | O_WRONLY, 0666 );
661 if (fds[0] == -1 || fds[1] == -1) goto fail;
663 while ((num = read( fds[0], buf, sizeof(buf) )) != 0)
665 if (num == -1) goto fail;
666 if (write( fds[1], buf, num ) != num) goto fail;
668 ret = TRUE;
670 fail:
671 if (fds[1] != -1) close( fds[1] );
672 if (fds[0] != -1) close( fds[0] );
673 return ret;
676 static BOOL get_internal_fallback_ppd( const WCHAR *ppd )
678 static const WCHAR typeW[] = {'P','P','D','F','I','L','E',0};
680 char *ptr, *end;
681 DWORD size, written;
682 HANDLE file;
683 BOOL ret;
684 HRSRC res = FindResourceW( WINSPOOL_hInstance, MAKEINTRESOURCEW(1), typeW );
686 if (!res || !(ptr = LoadResource( WINSPOOL_hInstance, res ))) return FALSE;
687 size = SizeofResource( WINSPOOL_hInstance, res );
688 end = memchr( ptr, 0, size ); /* resource file may contain additional nulls */
689 if (end) size = end - ptr;
690 file = CreateFileW( ppd, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0 );
691 if (file == INVALID_HANDLE_VALUE) return FALSE;
692 ret = WriteFile( file, ptr, size, &written, NULL ) && written == size;
693 CloseHandle( file );
694 if (ret) TRACE( "using internal fallback for %s\n", debugstr_w( ppd ));
695 else DeleteFileW( ppd );
696 return ret;
699 static BOOL get_fallback_ppd( const char *printer_name, const WCHAR *ppd )
701 char *dst, *src = get_fallback_ppd_name( printer_name );
702 BOOL ret = FALSE;
704 if (!src) return get_internal_fallback_ppd( ppd );
706 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name), debugstr_w(ppd), debugstr_a(src) );
708 if (!(dst = wine_get_unix_file_name( ppd ))) goto fail;
710 if (symlink( src, dst ) == -1)
711 if (errno != ENOSYS || !copy_file( src, dst ))
712 goto fail;
714 ret = TRUE;
715 fail:
716 HeapFree( GetProcessHeap(), 0, dst );
717 HeapFree( GetProcessHeap(), 0, src );
718 return ret;
721 static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
723 static const WCHAR dot_ppd[] = {'.','p','p','d',0};
724 static const WCHAR invalid_chars[] = {'*','?','<','>','|','"','/','\\',0};
725 int dir_len = strlenW( dir ), file_len = strlenW( file_name );
726 int len = (dir_len + file_len + ARRAY_SIZE( dot_ppd )) * sizeof(WCHAR);
727 WCHAR *ppd = HeapAlloc( GetProcessHeap(), 0, len ), *p;
729 if (!ppd) return NULL;
730 memcpy( ppd, dir, dir_len * sizeof(WCHAR) );
731 memcpy( ppd + dir_len, file_name, file_len * sizeof(WCHAR) );
732 memcpy( ppd + dir_len + file_len, dot_ppd, sizeof(dot_ppd) );
734 p = ppd + dir_len;
735 while ((p = strpbrkW( p, invalid_chars ))) *p++ = '_';
737 return ppd;
740 static WCHAR *get_ppd_dir( void )
742 static const WCHAR wine_ppds[] = {'w','i','n','e','_','p','p','d','s','\\',0};
743 DWORD len;
744 WCHAR *dir, tmp_path[MAX_PATH];
745 BOOL res;
747 len = GetTempPathW( ARRAY_SIZE( tmp_path ), tmp_path );
748 if (!len) return NULL;
749 dir = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
750 if (!dir) return NULL;
752 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
753 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
754 res = CreateDirectoryW( dir, NULL );
755 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
757 HeapFree( GetProcessHeap(), 0, dir );
758 dir = NULL;
760 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
761 return dir;
764 static void unlink_ppd( const WCHAR *ppd )
766 char *unix_name = wine_get_unix_file_name( ppd );
767 unlink( unix_name );
768 HeapFree( GetProcessHeap(), 0, unix_name );
771 #ifdef SONAME_LIBCUPS
773 static void *cupshandle;
775 #define CUPS_FUNCS \
776 DO_FUNC(cupsAddOption); \
777 DO_FUNC(cupsFreeDests); \
778 DO_FUNC(cupsFreeOptions); \
779 DO_FUNC(cupsGetDests); \
780 DO_FUNC(cupsGetOption); \
781 DO_FUNC(cupsParseOptions); \
782 DO_FUNC(cupsPrintFile)
783 #define CUPS_OPT_FUNCS \
784 DO_FUNC(cupsGetNamedDest); \
785 DO_FUNC(cupsGetPPD); \
786 DO_FUNC(cupsGetPPD3); \
787 DO_FUNC(cupsLastErrorString)
789 #define DO_FUNC(f) static typeof(f) *p##f
790 CUPS_FUNCS;
791 #undef DO_FUNC
792 static cups_dest_t * (*pcupsGetNamedDest)(http_t *, const char *, const char *);
793 static const char * (*pcupsGetPPD)(const char *);
794 static http_status_t (*pcupsGetPPD3)(http_t *, const char *, time_t *, char *, size_t);
795 static const char * (*pcupsLastErrorString)(void);
797 static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name,
798 time_t *modtime, char *buffer,
799 size_t bufsize )
801 const char *ppd;
803 if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
805 if (!pcupsGetPPD) return HTTP_NOT_FOUND;
807 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
809 *modtime = 0;
810 ppd = pcupsGetPPD( name );
812 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
814 if (!ppd) return HTTP_NOT_FOUND;
816 if (rename( ppd, buffer ) == -1)
818 BOOL res = copy_file( ppd, buffer );
819 unlink( ppd );
820 if (!res) return HTTP_NOT_FOUND;
822 return HTTP_OK;
825 static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
827 time_t modtime = 0;
828 http_status_t http_status;
829 char *unix_name = wine_get_unix_file_name( ppd );
831 TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
833 if (!unix_name) return FALSE;
835 http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
836 unix_name, strlen( unix_name ) + 1 );
838 if (http_status != HTTP_OK) unlink( unix_name );
839 HeapFree( GetProcessHeap(), 0, unix_name );
841 if (http_status == HTTP_OK) return TRUE;
843 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
844 debugstr_a(printer_name), http_status );
845 return get_fallback_ppd( printer_name, ppd );
848 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
850 const char *value;
851 WCHAR *ret;
852 int len;
854 value = pcupsGetOption( name, num_options, options );
855 if (!value) return NULL;
857 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
858 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
859 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
861 return ret;
864 static cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
866 WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
867 cups_ptype_t ret = 0;
869 if (type && *type)
871 ret = (cups_ptype_t)strtoulW( type, &end, 10 );
872 if (*end) ret = 0;
874 HeapFree( GetProcessHeap(), 0, type );
875 return ret;
878 static void load_cups(void)
880 cupshandle = dlopen( SONAME_LIBCUPS, RTLD_NOW );
881 if (!cupshandle) return;
883 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
885 #define DO_FUNC(x) \
886 p##x = dlsym( cupshandle, #x ); \
887 if (!p##x) \
889 ERR("failed to load symbol %s\n", #x); \
890 cupshandle = NULL; \
891 return; \
893 CUPS_FUNCS;
894 #undef DO_FUNC
895 #define DO_FUNC(x) p##x = dlsym( cupshandle, #x )
896 CUPS_OPT_FUNCS;
897 #undef DO_FUNC
900 static BOOL CUPS_LoadPrinters(void)
902 int i, nrofdests;
903 BOOL hadprinter = FALSE, haddefault = FALSE;
904 cups_dest_t *dests;
905 PRINTER_INFO_2W pi2;
906 WCHAR *port, *ppd_dir = NULL, *ppd;
907 HKEY hkeyPrinter, hkeyPrinters;
908 WCHAR nameW[MAX_PATH];
909 HANDLE added_printer;
910 cups_ptype_t printer_type;
912 if (!cupshandle) return FALSE;
914 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
915 ERROR_SUCCESS) {
916 ERR("Can't create Printers key\n");
917 return FALSE;
920 nrofdests = pcupsGetDests(&dests);
921 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
922 for (i=0;i<nrofdests;i++) {
923 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, ARRAY_SIZE(nameW));
924 printer_type = get_cups_printer_type( dests + i );
926 TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
928 if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
930 TRACE( "skipping scanner-only device\n" );
931 continue;
934 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
935 lstrcpyW(port, CUPS_Port);
936 lstrcatW(port, nameW);
938 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
939 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
940 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
941 and continue */
942 TRACE("Printer already exists\n");
943 /* overwrite old LPR:* port */
944 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
945 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
946 /* flag that the PPD file should be checked for an update */
947 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
948 RegCloseKey(hkeyPrinter);
949 } else {
950 BOOL added_driver = FALSE;
952 if (!ppd_dir && !(ppd_dir = get_ppd_dir()))
954 HeapFree( GetProcessHeap(), 0, port );
955 break;
957 ppd = get_ppd_filename( ppd_dir, nameW );
958 if (get_cups_ppd( dests[i].name, ppd ))
960 added_driver = add_printer_driver( nameW, ppd );
961 unlink_ppd( ppd );
963 HeapFree( GetProcessHeap(), 0, ppd );
964 if (!added_driver)
966 HeapFree( GetProcessHeap(), 0, port );
967 continue;
970 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
971 pi2.pPrinterName = nameW;
972 pi2.pDatatype = rawW;
973 pi2.pPrintProcessor = WinPrintW;
974 pi2.pDriverName = nameW;
975 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
976 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
977 pi2.pPortName = port;
978 pi2.pParameters = emptyStringW;
979 pi2.pShareName = emptyStringW;
980 pi2.pSepFile = emptyStringW;
982 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
983 if (added_printer) ClosePrinter( added_printer );
984 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
985 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
987 HeapFree( GetProcessHeap(), 0, pi2.pComment );
988 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
990 HeapFree( GetProcessHeap(), 0, port );
992 hadprinter = TRUE;
993 if (dests[i].is_default) {
994 SetDefaultPrinterW(nameW);
995 haddefault = TRUE;
999 if (ppd_dir)
1001 RemoveDirectoryW( ppd_dir );
1002 HeapFree( GetProcessHeap(), 0, ppd_dir );
1005 if (hadprinter && !haddefault) {
1006 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, ARRAY_SIZE(nameW));
1007 SetDefaultPrinterW(nameW);
1009 pcupsFreeDests(nrofdests, dests);
1010 RegCloseKey(hkeyPrinters);
1011 return TRUE;
1014 #endif
1016 static char *get_queue_name( HANDLE printer, BOOL *cups )
1018 WCHAR *port, *name = NULL;
1019 DWORD err, needed, type;
1020 char *ret = NULL;
1021 HKEY key;
1023 *cups = FALSE;
1025 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1026 if (err) return NULL;
1027 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1028 if (err) goto end;
1029 port = HeapAlloc( GetProcessHeap(), 0, needed );
1030 if (!port) goto end;
1031 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1033 if (!strncmpW( port, CUPS_Port, ARRAY_SIZE( CUPS_Port ) -1 ))
1035 name = port + ARRAY_SIZE( CUPS_Port ) - 1;
1036 *cups = TRUE;
1038 else if (!strncmpW( port, LPR_Port, ARRAY_SIZE( LPR_Port ) -1 ))
1039 name = port + ARRAY_SIZE( LPR_Port ) - 1;
1040 if (name)
1042 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1043 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1044 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1046 HeapFree( GetProcessHeap(), 0, port );
1047 end:
1048 RegCloseKey( key );
1049 return ret;
1053 static void set_ppd_overrides( HANDLE printer )
1055 WCHAR *wstr = NULL;
1056 int size = 0;
1057 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1058 OSStatus status;
1059 PMPrintSession session = NULL;
1060 PMPageFormat format = NULL;
1061 PMPaper paper;
1062 CFStringRef paper_name;
1063 CFRange range;
1065 status = PMCreateSession( &session );
1066 if (status) goto end;
1068 status = PMCreatePageFormat( &format );
1069 if (status) goto end;
1071 status = PMSessionDefaultPageFormat( session, format );
1072 if (status) goto end;
1074 status = PMGetPageFormatPaper( format, &paper );
1075 if (status) goto end;
1077 status = PMPaperGetPPDPaperName( paper, &paper_name );
1078 if (status) goto end;
1080 range.location = 0;
1081 range.length = CFStringGetLength( paper_name );
1082 size = (range.length + 1) * sizeof(WCHAR);
1084 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1085 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1086 wstr[range.length] = 0;
1088 end:
1089 if (format) PMRelease( format );
1090 if (session) PMRelease( session );
1091 #endif
1093 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1094 HeapFree( GetProcessHeap(), 0, wstr );
1097 static BOOL update_driver( HANDLE printer )
1099 BOOL ret, is_cups;
1100 const WCHAR *name = get_opened_printer_name( printer );
1101 WCHAR *ppd_dir, *ppd;
1102 char *queue_name;
1104 if (!name) return FALSE;
1105 queue_name = get_queue_name( printer, &is_cups );
1106 if (!queue_name) return FALSE;
1108 if (!(ppd_dir = get_ppd_dir()))
1110 HeapFree( GetProcessHeap(), 0, queue_name );
1111 return FALSE;
1113 ppd = get_ppd_filename( ppd_dir, name );
1115 #ifdef SONAME_LIBCUPS
1116 if (is_cups)
1117 ret = get_cups_ppd( queue_name, ppd );
1118 else
1119 #endif
1120 ret = get_fallback_ppd( queue_name, ppd );
1122 if (ret)
1124 TRACE( "updating driver %s\n", debugstr_w( name ) );
1125 ret = add_printer_driver( name, ppd );
1126 unlink_ppd( ppd );
1128 HeapFree( GetProcessHeap(), 0, ppd_dir );
1129 HeapFree( GetProcessHeap(), 0, ppd );
1130 HeapFree( GetProcessHeap(), 0, queue_name );
1132 set_ppd_overrides( printer );
1134 /* call into the driver to update the devmode */
1135 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1137 return ret;
1140 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1142 PRINTER_INFO_2A pinfo2a;
1143 const char *r;
1144 size_t name_len;
1145 char *e,*s,*name,*prettyname,*devname;
1146 BOOL ret = FALSE, set_default = FALSE;
1147 char *port = NULL, *env_default;
1148 HKEY hkeyPrinter, hkeyPrinters = NULL;
1149 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1150 HANDLE added_printer;
1152 while (isspace(*pent)) pent++;
1153 r = strchr(pent,':');
1154 if (r)
1155 name_len = r - pent;
1156 else
1157 name_len = strlen(pent);
1158 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1159 memcpy(name, pent, name_len);
1160 name[name_len] = '\0';
1161 if (r)
1162 pent = r;
1163 else
1164 pent = "";
1166 TRACE("name=%s entry=%s\n",name, pent);
1168 if(ispunct(*name)) { /* a tc entry, not a real printer */
1169 TRACE("skipping tc entry\n");
1170 goto end;
1173 if(strstr(pent,":server")) { /* server only version so skip */
1174 TRACE("skipping server entry\n");
1175 goto end;
1178 /* Determine whether this is a postscript printer. */
1180 ret = TRUE;
1181 env_default = getenv("PRINTER");
1182 prettyname = name;
1183 /* Get longest name, usually the one at the right for later display. */
1184 while((s=strchr(prettyname,'|'))) {
1185 *s = '\0';
1186 e = s;
1187 while(isspace(*--e)) *e = '\0';
1188 TRACE("\t%s\n", debugstr_a(prettyname));
1189 if(env_default && !_strnicmp(prettyname, env_default, -1)) set_default = TRUE;
1190 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1193 e = prettyname + strlen(prettyname);
1194 while(isspace(*--e)) *e = '\0';
1195 TRACE("\t%s\n", debugstr_a(prettyname));
1196 if(env_default && !_strnicmp(prettyname, env_default, -1)) set_default = TRUE;
1198 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1199 * if it is too long, we use it as comment below. */
1200 devname = prettyname;
1201 if (strlen(devname)>=CCHDEVICENAME-1)
1202 devname = name;
1203 if (strlen(devname)>=CCHDEVICENAME-1) {
1204 ret = FALSE;
1205 goto end;
1208 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1209 sprintf(port,"LPR:%s",name);
1211 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1212 ERROR_SUCCESS) {
1213 ERR("Can't create Printers key\n");
1214 ret = FALSE;
1215 goto end;
1218 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, ARRAY_SIZE(devnameW));
1220 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1221 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1222 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1223 and continue */
1224 TRACE("Printer already exists\n");
1225 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1226 /* flag that the PPD file should be checked for an update */
1227 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1228 RegCloseKey(hkeyPrinter);
1229 } else {
1230 static CHAR data_type[] = "RAW",
1231 print_proc[] = "WinPrint",
1232 comment[] = "WINEPS Printer using LPR",
1233 params[] = "<parameters?>",
1234 share_name[] = "<share name?>",
1235 sep_file[] = "<sep file?>";
1236 BOOL added_driver = FALSE;
1238 if (!ppd_dir && !(ppd_dir = get_ppd_dir())) goto end;
1239 ppd = get_ppd_filename( ppd_dir, devnameW );
1240 if (get_fallback_ppd( devname, ppd ))
1242 added_driver = add_printer_driver( devnameW, ppd );
1243 unlink_ppd( ppd );
1245 HeapFree( GetProcessHeap(), 0, ppd );
1246 if (!added_driver) goto end;
1248 memset(&pinfo2a,0,sizeof(pinfo2a));
1249 pinfo2a.pPrinterName = devname;
1250 pinfo2a.pDatatype = data_type;
1251 pinfo2a.pPrintProcessor = print_proc;
1252 pinfo2a.pDriverName = devname;
1253 pinfo2a.pComment = comment;
1254 pinfo2a.pLocation = prettyname;
1255 pinfo2a.pPortName = port;
1256 pinfo2a.pParameters = params;
1257 pinfo2a.pShareName = share_name;
1258 pinfo2a.pSepFile = sep_file;
1260 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1261 if (added_printer) ClosePrinter( added_printer );
1262 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1263 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1266 if (isfirst || set_default)
1267 set_default_printer(devname, name);
1269 end:
1270 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1271 if (ppd_dir)
1273 RemoveDirectoryW( ppd_dir );
1274 HeapFree( GetProcessHeap(), 0, ppd_dir );
1276 HeapFree(GetProcessHeap(), 0, port);
1277 HeapFree(GetProcessHeap(), 0, name);
1278 return ret;
1281 static BOOL
1282 PRINTCAP_LoadPrinters(void) {
1283 BOOL hadprinter = FALSE;
1284 char buf[200];
1285 FILE *f;
1286 char *pent = NULL;
1287 BOOL had_bash = FALSE;
1289 f = fopen("/etc/printcap","r");
1290 if (!f)
1291 return FALSE;
1293 while(fgets(buf,sizeof(buf),f)) {
1294 char *start, *end;
1296 end=strchr(buf,'\n');
1297 if (end) *end='\0';
1299 start = buf;
1300 while(isspace(*start)) start++;
1301 if(*start == '#' || *start == '\0')
1302 continue;
1304 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1305 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1306 HeapFree(GetProcessHeap(),0,pent);
1307 pent = NULL;
1310 if (end && *--end == '\\') {
1311 *end = '\0';
1312 had_bash = TRUE;
1313 } else
1314 had_bash = FALSE;
1316 if (pent) {
1317 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1318 strcat(pent,start);
1319 } else {
1320 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1321 strcpy(pent,start);
1325 if(pent) {
1326 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1327 HeapFree(GetProcessHeap(),0,pent);
1329 fclose(f);
1330 return hadprinter;
1333 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1335 if (value)
1336 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1337 (lstrlenW(value) + 1) * sizeof(WCHAR));
1338 else
1339 return ERROR_FILE_NOT_FOUND;
1342 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1344 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1345 DWORD ret = ERROR_FILE_NOT_FOUND;
1347 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1348 and we support these drivers. NT writes DEVMODEW so somehow
1349 we'll need to distinguish between these when we support NT
1350 drivers */
1352 if (dmA)
1354 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1355 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1356 HeapFree( GetProcessHeap(), 0, dmA );
1359 return ret;
1362 /******************************************************************
1363 * get_servername_from_name (internal)
1365 * for an external server, a copy of the serverpart from the full name is returned
1368 static LPWSTR get_servername_from_name(LPCWSTR name)
1370 LPWSTR server;
1371 LPWSTR ptr;
1372 WCHAR buffer[MAX_PATH];
1373 DWORD len;
1375 if (name == NULL) return NULL;
1376 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1378 server = strdupW(&name[2]); /* skip over both backslash */
1379 if (server == NULL) return NULL;
1381 /* strip '\' and the printername */
1382 ptr = strchrW(server, '\\');
1383 if (ptr) ptr[0] = '\0';
1385 TRACE("found %s\n", debugstr_w(server));
1387 len = ARRAY_SIZE(buffer);
1388 if (GetComputerNameW(buffer, &len)) {
1389 if (lstrcmpW(buffer, server) == 0) {
1390 /* The requested Servername is our computername */
1391 HeapFree(GetProcessHeap(), 0, server);
1392 return NULL;
1395 return server;
1398 /******************************************************************
1399 * get_basename_from_name (internal)
1401 * skip over the serverpart from the full name
1404 static LPCWSTR get_basename_from_name(LPCWSTR name)
1406 if (name == NULL) return NULL;
1407 if ((name[0] == '\\') && (name[1] == '\\')) {
1408 /* skip over the servername and search for the following '\' */
1409 name = strchrW(&name[2], '\\');
1410 if ((name) && (name[1])) {
1411 /* found a separator ('\') followed by a name:
1412 skip over the separator and return the rest */
1413 name++;
1415 else
1417 /* no basename present (we found only a servername) */
1418 return NULL;
1421 return name;
1424 static void free_printer_entry( opened_printer_t *printer )
1426 /* the queue is shared, so don't free that here */
1427 HeapFree( GetProcessHeap(), 0, printer->printername );
1428 HeapFree( GetProcessHeap(), 0, printer->name );
1429 HeapFree( GetProcessHeap(), 0, printer->devmode );
1430 HeapFree( GetProcessHeap(), 0, printer );
1433 /******************************************************************
1434 * get_opened_printer_entry
1435 * Get the first place empty in the opened printer table
1437 * ToDo:
1438 * - pDefault is ignored
1440 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1442 UINT_PTR handle = nb_printer_handles, i;
1443 jobqueue_t *queue = NULL;
1444 opened_printer_t *printer = NULL;
1445 LPWSTR servername;
1446 LPCWSTR printername;
1448 if ((backend == NULL) && !load_backend()) return NULL;
1450 servername = get_servername_from_name(name);
1451 if (servername) {
1452 FIXME("server %s not supported\n", debugstr_w(servername));
1453 HeapFree(GetProcessHeap(), 0, servername);
1454 SetLastError(ERROR_INVALID_PRINTER_NAME);
1455 return NULL;
1458 printername = get_basename_from_name(name);
1459 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1461 /* an empty printername is invalid */
1462 if (printername && (!printername[0])) {
1463 SetLastError(ERROR_INVALID_PARAMETER);
1464 return NULL;
1467 EnterCriticalSection(&printer_handles_cs);
1469 for (i = 0; i < nb_printer_handles; i++)
1471 if (!printer_handles[i])
1473 if(handle == nb_printer_handles)
1474 handle = i;
1476 else
1478 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1479 queue = printer_handles[i]->queue;
1483 if (handle >= nb_printer_handles)
1485 opened_printer_t **new_array;
1486 if (printer_handles)
1487 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1488 (nb_printer_handles + 16) * sizeof(*new_array) );
1489 else
1490 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1491 (nb_printer_handles + 16) * sizeof(*new_array) );
1493 if (!new_array)
1495 handle = 0;
1496 goto end;
1498 printer_handles = new_array;
1499 nb_printer_handles += 16;
1502 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1504 handle = 0;
1505 goto end;
1508 /* get a printer handle from the backend */
1509 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1510 handle = 0;
1511 goto end;
1514 /* clone the base name. This is NULL for the printserver */
1515 printer->printername = strdupW(printername);
1517 /* clone the full name */
1518 printer->name = strdupW(name);
1519 if (name && (!printer->name)) {
1520 handle = 0;
1521 goto end;
1524 if (pDefault && pDefault->pDevMode)
1525 printer->devmode = dup_devmode( pDefault->pDevMode );
1527 if(queue)
1528 printer->queue = queue;
1529 else
1531 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1532 if (!printer->queue) {
1533 handle = 0;
1534 goto end;
1536 list_init(&printer->queue->jobs);
1537 printer->queue->ref = 0;
1539 InterlockedIncrement(&printer->queue->ref);
1541 printer_handles[handle] = printer;
1542 handle++;
1543 end:
1544 LeaveCriticalSection(&printer_handles_cs);
1545 if (!handle && printer) {
1546 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1547 free_printer_entry( printer );
1550 return (HANDLE)handle;
1553 static void old_printer_check( BOOL delete_phase )
1555 PRINTER_INFO_5W* pi;
1556 DWORD needed, type, num, delete, i, size;
1557 const DWORD one = 1;
1558 HKEY key;
1559 HANDLE hprn;
1561 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1562 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1564 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1565 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1566 for (i = 0; i < num; i++)
1568 if (!pi[i].pPortName) continue;
1570 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1571 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1572 continue;
1574 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1576 if (!delete_phase)
1578 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1579 RegCloseKey( key );
1581 else
1583 delete = 0;
1584 size = sizeof( delete );
1585 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1586 RegCloseKey( key );
1587 if (delete)
1589 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1590 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1592 DeletePrinter( hprn );
1593 ClosePrinter( hprn );
1595 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1599 HeapFree(GetProcessHeap(), 0, pi);
1602 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1603 'M','U','T','E','X','_','_','\0'};
1604 static HANDLE init_mutex;
1606 void WINSPOOL_LoadSystemPrinters(void)
1608 HKEY hkey, hkeyPrinters;
1609 DWORD needed, num, i;
1610 WCHAR PrinterName[256];
1611 BOOL done = FALSE;
1613 #ifdef SONAME_LIBCUPS
1614 load_cups();
1615 #endif
1617 /* FIXME: The init code should be moved to spoolsv.exe */
1618 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1619 if (!init_mutex)
1621 ERR( "Failed to create mutex\n" );
1622 return;
1624 if (GetLastError() == ERROR_ALREADY_EXISTS)
1626 WaitForSingleObject( init_mutex, INFINITE );
1627 ReleaseMutex( init_mutex );
1628 TRACE( "Init already done\n" );
1629 return;
1632 /* This ensures that all printer entries have a valid Name value. If causes
1633 problems later if they don't. If one is found to be missed we create one
1634 and set it equal to the name of the key */
1635 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1636 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1637 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1638 for(i = 0; i < num; i++) {
1639 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, ARRAY_SIZE(PrinterName)) == ERROR_SUCCESS) {
1640 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1641 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1642 set_reg_szW(hkey, NameW, PrinterName);
1644 RegCloseKey(hkey);
1649 RegCloseKey(hkeyPrinters);
1652 old_printer_check( FALSE );
1654 #ifdef SONAME_LIBCUPS
1655 done = CUPS_LoadPrinters();
1656 #endif
1658 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1659 PRINTCAP_LoadPrinters();
1661 old_printer_check( TRUE );
1663 ReleaseMutex( init_mutex );
1664 return;
1667 /******************************************************************
1668 * get_job
1670 * Get the pointer to the specified job.
1671 * Should hold the printer_handles_cs before calling.
1673 static job_t *get_job(HANDLE hprn, DWORD JobId)
1675 opened_printer_t *printer = get_opened_printer(hprn);
1676 job_t *job;
1678 if(!printer) return NULL;
1679 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1681 if(job->job_id == JobId)
1682 return job;
1684 return NULL;
1687 /***********************************************************
1688 * DEVMODEcpyAtoW
1690 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1692 BOOL Formname;
1693 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1694 DWORD size;
1696 Formname = (dmA->dmSize > off_formname);
1697 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1698 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1699 dmW->dmDeviceName, CCHDEVICENAME);
1700 if(!Formname) {
1701 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1702 dmA->dmSize - CCHDEVICENAME);
1703 } else {
1704 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1705 off_formname - CCHDEVICENAME);
1706 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1707 dmW->dmFormName, CCHFORMNAME);
1708 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1709 (off_formname + CCHFORMNAME));
1711 dmW->dmSize = size;
1712 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1713 dmA->dmDriverExtra);
1714 return dmW;
1717 /******************************************************************
1718 * convert_printerinfo_W_to_A [internal]
1721 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1722 DWORD level, DWORD outlen, DWORD numentries)
1724 DWORD id = 0;
1725 LPSTR ptr;
1726 INT len;
1728 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1730 len = pi_sizeof[level] * numentries;
1731 ptr = (LPSTR) out + len;
1732 outlen -= len;
1734 /* copy the numbers of all PRINTER_INFO_* first */
1735 memcpy(out, pPrintersW, len);
1737 while (id < numentries) {
1738 switch (level) {
1739 case 1:
1741 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1742 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1744 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1745 if (piW->pDescription) {
1746 piA->pDescription = ptr;
1747 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1748 ptr, outlen, NULL, NULL);
1749 ptr += len;
1750 outlen -= len;
1752 if (piW->pName) {
1753 piA->pName = ptr;
1754 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1755 ptr, outlen, NULL, NULL);
1756 ptr += len;
1757 outlen -= len;
1759 if (piW->pComment) {
1760 piA->pComment = ptr;
1761 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1762 ptr, outlen, NULL, NULL);
1763 ptr += len;
1764 outlen -= len;
1766 break;
1769 case 2:
1771 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1772 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1773 LPDEVMODEA dmA;
1775 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1776 if (piW->pServerName) {
1777 piA->pServerName = ptr;
1778 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1779 ptr, outlen, NULL, NULL);
1780 ptr += len;
1781 outlen -= len;
1783 if (piW->pPrinterName) {
1784 piA->pPrinterName = ptr;
1785 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1786 ptr, outlen, NULL, NULL);
1787 ptr += len;
1788 outlen -= len;
1790 if (piW->pShareName) {
1791 piA->pShareName = ptr;
1792 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1793 ptr, outlen, NULL, NULL);
1794 ptr += len;
1795 outlen -= len;
1797 if (piW->pPortName) {
1798 piA->pPortName = ptr;
1799 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1800 ptr, outlen, NULL, NULL);
1801 ptr += len;
1802 outlen -= len;
1804 if (piW->pDriverName) {
1805 piA->pDriverName = ptr;
1806 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1807 ptr, outlen, NULL, NULL);
1808 ptr += len;
1809 outlen -= len;
1811 if (piW->pComment) {
1812 piA->pComment = ptr;
1813 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1814 ptr, outlen, NULL, NULL);
1815 ptr += len;
1816 outlen -= len;
1818 if (piW->pLocation) {
1819 piA->pLocation = ptr;
1820 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1821 ptr, outlen, NULL, NULL);
1822 ptr += len;
1823 outlen -= len;
1826 dmA = DEVMODEdupWtoA(piW->pDevMode);
1827 if (dmA) {
1828 /* align DEVMODEA to a DWORD boundary */
1829 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1830 ptr += len;
1831 outlen -= len;
1833 piA->pDevMode = (LPDEVMODEA) ptr;
1834 len = dmA->dmSize + dmA->dmDriverExtra;
1835 memcpy(ptr, dmA, len);
1836 HeapFree(GetProcessHeap(), 0, dmA);
1838 ptr += len;
1839 outlen -= len;
1842 if (piW->pSepFile) {
1843 piA->pSepFile = ptr;
1844 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1845 ptr, outlen, NULL, NULL);
1846 ptr += len;
1847 outlen -= len;
1849 if (piW->pPrintProcessor) {
1850 piA->pPrintProcessor = ptr;
1851 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1852 ptr, outlen, NULL, NULL);
1853 ptr += len;
1854 outlen -= len;
1856 if (piW->pDatatype) {
1857 piA->pDatatype = ptr;
1858 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1859 ptr, outlen, NULL, NULL);
1860 ptr += len;
1861 outlen -= len;
1863 if (piW->pParameters) {
1864 piA->pParameters = ptr;
1865 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1866 ptr, outlen, NULL, NULL);
1867 ptr += len;
1868 outlen -= len;
1870 if (piW->pSecurityDescriptor) {
1871 piA->pSecurityDescriptor = NULL;
1872 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1874 break;
1877 case 4:
1879 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1880 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1882 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1884 if (piW->pPrinterName) {
1885 piA->pPrinterName = ptr;
1886 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1887 ptr, outlen, NULL, NULL);
1888 ptr += len;
1889 outlen -= len;
1891 if (piW->pServerName) {
1892 piA->pServerName = ptr;
1893 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1894 ptr, outlen, NULL, NULL);
1895 ptr += len;
1896 outlen -= len;
1898 break;
1901 case 5:
1903 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1904 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1906 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1908 if (piW->pPrinterName) {
1909 piA->pPrinterName = ptr;
1910 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1911 ptr, outlen, NULL, NULL);
1912 ptr += len;
1913 outlen -= len;
1915 if (piW->pPortName) {
1916 piA->pPortName = ptr;
1917 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1918 ptr, outlen, NULL, NULL);
1919 ptr += len;
1920 outlen -= len;
1922 break;
1925 case 6: /* 6A and 6W are the same structure */
1926 break;
1928 case 7:
1930 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1931 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1933 TRACE("(%u) #%u\n", level, id);
1934 if (piW->pszObjectGUID) {
1935 piA->pszObjectGUID = ptr;
1936 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1937 ptr, outlen, NULL, NULL);
1938 ptr += len;
1939 outlen -= len;
1941 break;
1944 case 8:
1945 case 9:
1947 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1948 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1949 LPDEVMODEA dmA;
1951 TRACE("(%u) #%u\n", level, id);
1952 dmA = DEVMODEdupWtoA(piW->pDevMode);
1953 if (dmA) {
1954 /* align DEVMODEA to a DWORD boundary */
1955 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1956 ptr += len;
1957 outlen -= len;
1959 piA->pDevMode = (LPDEVMODEA) ptr;
1960 len = dmA->dmSize + dmA->dmDriverExtra;
1961 memcpy(ptr, dmA, len);
1962 HeapFree(GetProcessHeap(), 0, dmA);
1964 ptr += len;
1965 outlen -= len;
1968 break;
1971 default:
1972 FIXME("for level %u\n", level);
1974 pPrintersW += pi_sizeof[level];
1975 out += pi_sizeof[level];
1976 id++;
1980 /******************************************************************
1981 * convert_driverinfo_W_to_A [internal]
1984 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1985 DWORD level, DWORD outlen, DWORD numentries)
1987 DWORD id = 0;
1988 LPSTR ptr;
1989 INT len;
1991 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1993 len = di_sizeof[level] * numentries;
1994 ptr = (LPSTR) out + len;
1995 outlen -= len;
1997 /* copy the numbers of all PRINTER_INFO_* first */
1998 memcpy(out, pDriversW, len);
2000 #define COPY_STRING(fld) \
2001 { if (diW->fld){ \
2002 diA->fld = ptr; \
2003 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
2004 ptr += len; outlen -= len;\
2006 #define COPY_MULTIZ_STRING(fld) \
2007 { LPWSTR p = diW->fld; if (p){ \
2008 diA->fld = ptr; \
2009 do {\
2010 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2011 ptr += len; outlen -= len; p += len;\
2013 while(len > 1 && outlen > 0); \
2016 while (id < numentries)
2018 switch (level)
2020 case 1:
2022 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
2023 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
2025 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2027 COPY_STRING(pName);
2028 break;
2030 case 2:
2032 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2033 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2035 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2037 COPY_STRING(pName);
2038 COPY_STRING(pEnvironment);
2039 COPY_STRING(pDriverPath);
2040 COPY_STRING(pDataFile);
2041 COPY_STRING(pConfigFile);
2042 break;
2044 case 3:
2046 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2047 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2049 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2051 COPY_STRING(pName);
2052 COPY_STRING(pEnvironment);
2053 COPY_STRING(pDriverPath);
2054 COPY_STRING(pDataFile);
2055 COPY_STRING(pConfigFile);
2056 COPY_STRING(pHelpFile);
2057 COPY_MULTIZ_STRING(pDependentFiles);
2058 COPY_STRING(pMonitorName);
2059 COPY_STRING(pDefaultDataType);
2060 break;
2062 case 4:
2064 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2065 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2067 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2069 COPY_STRING(pName);
2070 COPY_STRING(pEnvironment);
2071 COPY_STRING(pDriverPath);
2072 COPY_STRING(pDataFile);
2073 COPY_STRING(pConfigFile);
2074 COPY_STRING(pHelpFile);
2075 COPY_MULTIZ_STRING(pDependentFiles);
2076 COPY_STRING(pMonitorName);
2077 COPY_STRING(pDefaultDataType);
2078 COPY_MULTIZ_STRING(pszzPreviousNames);
2079 break;
2081 case 5:
2083 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2084 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2086 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2088 COPY_STRING(pName);
2089 COPY_STRING(pEnvironment);
2090 COPY_STRING(pDriverPath);
2091 COPY_STRING(pDataFile);
2092 COPY_STRING(pConfigFile);
2093 break;
2095 case 6:
2097 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2098 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2100 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2102 COPY_STRING(pName);
2103 COPY_STRING(pEnvironment);
2104 COPY_STRING(pDriverPath);
2105 COPY_STRING(pDataFile);
2106 COPY_STRING(pConfigFile);
2107 COPY_STRING(pHelpFile);
2108 COPY_MULTIZ_STRING(pDependentFiles);
2109 COPY_STRING(pMonitorName);
2110 COPY_STRING(pDefaultDataType);
2111 COPY_MULTIZ_STRING(pszzPreviousNames);
2112 COPY_STRING(pszMfgName);
2113 COPY_STRING(pszOEMUrl);
2114 COPY_STRING(pszHardwareID);
2115 COPY_STRING(pszProvider);
2116 break;
2118 case 8:
2120 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2121 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2123 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2125 COPY_STRING(pName);
2126 COPY_STRING(pEnvironment);
2127 COPY_STRING(pDriverPath);
2128 COPY_STRING(pDataFile);
2129 COPY_STRING(pConfigFile);
2130 COPY_STRING(pHelpFile);
2131 COPY_MULTIZ_STRING(pDependentFiles);
2132 COPY_STRING(pMonitorName);
2133 COPY_STRING(pDefaultDataType);
2134 COPY_MULTIZ_STRING(pszzPreviousNames);
2135 COPY_STRING(pszMfgName);
2136 COPY_STRING(pszOEMUrl);
2137 COPY_STRING(pszHardwareID);
2138 COPY_STRING(pszProvider);
2139 COPY_STRING(pszPrintProcessor);
2140 COPY_STRING(pszVendorSetup);
2141 COPY_MULTIZ_STRING(pszzColorProfiles);
2142 COPY_STRING(pszInfPath);
2143 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2144 break;
2148 default:
2149 FIXME("for level %u\n", level);
2152 pDriversW += di_sizeof[level];
2153 out += di_sizeof[level];
2154 id++;
2157 #undef COPY_STRING
2158 #undef COPY_MULTIZ_STRING
2162 /***********************************************************
2163 * printer_info_AtoW
2165 static void *printer_info_AtoW( const void *data, DWORD level )
2167 void *ret;
2168 UNICODE_STRING usBuffer;
2170 if (!data) return NULL;
2172 if (level < 1 || level > 9) return NULL;
2174 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2175 if (!ret) return NULL;
2177 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2179 switch (level)
2181 case 2:
2183 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2184 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2186 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2187 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2188 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2189 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2190 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2191 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2192 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2193 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2194 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2195 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2196 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2197 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2198 break;
2201 case 8:
2202 case 9:
2204 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2205 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2207 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2208 break;
2211 default:
2212 FIXME( "Unhandled level %d\n", level );
2213 HeapFree( GetProcessHeap(), 0, ret );
2214 return NULL;
2217 return ret;
2220 /***********************************************************
2221 * free_printer_info
2223 static void free_printer_info( void *data, DWORD level )
2225 if (!data) return;
2227 switch (level)
2229 case 2:
2231 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2233 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2234 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2235 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2236 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2237 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2238 HeapFree( GetProcessHeap(), 0, piW->pComment );
2239 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2240 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2241 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2242 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2243 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2244 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2245 break;
2248 case 8:
2249 case 9:
2251 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2253 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2254 break;
2257 default:
2258 FIXME( "Unhandled level %d\n", level );
2261 HeapFree( GetProcessHeap(), 0, data );
2262 return;
2265 /******************************************************************
2266 * DeviceCapabilities [WINSPOOL.@]
2267 * DeviceCapabilitiesA [WINSPOOL.@]
2270 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2271 LPSTR pOutput, LPDEVMODEA lpdm)
2273 INT ret;
2275 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice), debugstr_a(pPort), cap, pOutput, lpdm);
2277 if (!GDI_CallDeviceCapabilities16)
2279 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2280 (LPCSTR)104 );
2281 if (!GDI_CallDeviceCapabilities16) return -1;
2283 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2285 /* If DC_PAPERSIZE map POINT16s to POINTs */
2286 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2287 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2288 POINT *pt = (POINT *)pOutput;
2289 INT i;
2290 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2291 for(i = 0; i < ret; i++, pt++)
2293 pt->x = tmp[i].x;
2294 pt->y = tmp[i].y;
2296 HeapFree( GetProcessHeap(), 0, tmp );
2298 return ret;
2302 /*****************************************************************************
2303 * DeviceCapabilitiesW [WINSPOOL.@]
2305 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2308 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2309 WORD fwCapability, LPWSTR pOutput,
2310 const DEVMODEW *pDevMode)
2312 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2313 LPSTR pDeviceA = strdupWtoA(pDevice);
2314 LPSTR pPortA = strdupWtoA(pPort);
2315 INT ret;
2317 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability, pOutput, pDevMode);
2319 if(pOutput && (fwCapability == DC_BINNAMES ||
2320 fwCapability == DC_FILEDEPENDENCIES ||
2321 fwCapability == DC_PAPERNAMES)) {
2322 /* These need A -> W translation */
2323 INT size = 0, i;
2324 LPSTR pOutputA;
2325 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2326 dmA);
2327 if(ret == -1)
2328 return ret;
2329 switch(fwCapability) {
2330 case DC_BINNAMES:
2331 size = 24;
2332 break;
2333 case DC_PAPERNAMES:
2334 case DC_FILEDEPENDENCIES:
2335 size = 64;
2336 break;
2338 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2339 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2340 dmA);
2341 for(i = 0; i < ret; i++)
2342 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2343 pOutput + (i * size), size);
2344 HeapFree(GetProcessHeap(), 0, pOutputA);
2345 } else {
2346 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2347 (LPSTR)pOutput, dmA);
2349 HeapFree(GetProcessHeap(),0,pPortA);
2350 HeapFree(GetProcessHeap(),0,pDeviceA);
2351 HeapFree(GetProcessHeap(),0,dmA);
2352 return ret;
2355 /******************************************************************
2356 * DocumentPropertiesA [WINSPOOL.@]
2358 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2360 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2361 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2362 LPDEVMODEA pDevModeInput,DWORD fMode )
2364 LPSTR lpName = pDeviceName, dupname = NULL;
2365 static CHAR port[] = "LPT1:";
2366 LONG ret;
2368 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2369 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2372 if(!pDeviceName || !*pDeviceName) {
2373 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2374 if(!lpNameW) {
2375 ERR("no name from hPrinter?\n");
2376 SetLastError(ERROR_INVALID_HANDLE);
2377 return -1;
2379 lpName = dupname = strdupWtoA(lpNameW);
2382 if (!GDI_CallExtDeviceMode16)
2384 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2385 (LPCSTR)102 );
2386 if (!GDI_CallExtDeviceMode16) {
2387 ERR("No CallExtDeviceMode16?\n");
2388 ret = -1;
2389 goto end;
2392 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2393 pDevModeInput, NULL, fMode);
2395 end:
2396 HeapFree(GetProcessHeap(), 0, dupname);
2397 return ret;
2401 /*****************************************************************************
2402 * DocumentPropertiesW (WINSPOOL.@)
2404 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2406 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2407 LPWSTR pDeviceName,
2408 LPDEVMODEW pDevModeOutput,
2409 LPDEVMODEW pDevModeInput, DWORD fMode)
2412 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2413 LPDEVMODEA pDevModeInputA;
2414 LPDEVMODEA pDevModeOutputA = NULL;
2415 LONG ret;
2417 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2418 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2419 fMode);
2420 if(pDevModeOutput) {
2421 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2422 if(ret < 0) return ret;
2423 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2425 pDevModeInputA = (fMode & DM_IN_BUFFER) ? DEVMODEdupWtoA(pDevModeInput) : NULL;
2426 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2427 pDevModeInputA, fMode);
2428 if(pDevModeOutput) {
2429 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2430 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2432 if(fMode == 0 && ret > 0)
2433 ret += (CCHDEVICENAME + CCHFORMNAME);
2434 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2435 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2436 return ret;
2439 /*****************************************************************************
2440 * IsValidDevmodeA [WINSPOOL.@]
2442 * Validate a DEVMODE structure and fix errors if possible.
2445 BOOL WINAPI IsValidDevmodeA(PDEVMODEA pDevMode, SIZE_T size)
2447 FIXME("(%p,%ld): stub\n", pDevMode, size);
2449 if(!pDevMode)
2450 return FALSE;
2452 return TRUE;
2455 /*****************************************************************************
2456 * IsValidDevmodeW [WINSPOOL.@]
2458 * Validate a DEVMODE structure and fix errors if possible.
2461 BOOL WINAPI IsValidDevmodeW(PDEVMODEW dm, SIZE_T size)
2463 static const struct
2465 DWORD flag;
2466 SIZE_T size;
2467 } map[] =
2469 #define F_SIZE(field) FIELD_OFFSET(DEVMODEW, field) + sizeof(dm->field)
2470 { DM_ORIENTATION, F_SIZE(u1.s1.dmOrientation) },
2471 { DM_PAPERSIZE, F_SIZE(u1.s1.dmPaperSize) },
2472 { DM_PAPERLENGTH, F_SIZE(u1.s1.dmPaperLength) },
2473 { DM_PAPERWIDTH, F_SIZE(u1.s1.dmPaperWidth) },
2474 { DM_SCALE, F_SIZE(u1.s1.dmScale) },
2475 { DM_COPIES, F_SIZE(u1.s1.dmCopies) },
2476 { DM_DEFAULTSOURCE, F_SIZE(u1.s1.dmDefaultSource) },
2477 { DM_PRINTQUALITY, F_SIZE(u1.s1.dmPrintQuality) },
2478 { DM_POSITION, F_SIZE(u1.s2.dmPosition) },
2479 { DM_DISPLAYORIENTATION, F_SIZE(u1.s2.dmDisplayOrientation) },
2480 { DM_DISPLAYFIXEDOUTPUT, F_SIZE(u1.s2.dmDisplayFixedOutput) },
2481 { DM_COLOR, F_SIZE(dmColor) },
2482 { DM_DUPLEX, F_SIZE(dmDuplex) },
2483 { DM_YRESOLUTION, F_SIZE(dmYResolution) },
2484 { DM_TTOPTION, F_SIZE(dmTTOption) },
2485 { DM_COLLATE, F_SIZE(dmCollate) },
2486 { DM_FORMNAME, F_SIZE(dmFormName) },
2487 { DM_LOGPIXELS, F_SIZE(dmLogPixels) },
2488 { DM_BITSPERPEL, F_SIZE(dmBitsPerPel) },
2489 { DM_PELSWIDTH, F_SIZE(dmPelsWidth) },
2490 { DM_PELSHEIGHT, F_SIZE(dmPelsHeight) },
2491 { DM_DISPLAYFLAGS, F_SIZE(u2.dmDisplayFlags) },
2492 { DM_NUP, F_SIZE(u2.dmNup) },
2493 { DM_DISPLAYFREQUENCY, F_SIZE(dmDisplayFrequency) },
2494 { DM_ICMMETHOD, F_SIZE(dmICMMethod) },
2495 { DM_ICMINTENT, F_SIZE(dmICMIntent) },
2496 { DM_MEDIATYPE, F_SIZE(dmMediaType) },
2497 { DM_DITHERTYPE, F_SIZE(dmDitherType) },
2498 { DM_PANNINGWIDTH, F_SIZE(dmPanningWidth) },
2499 { DM_PANNINGHEIGHT, F_SIZE(dmPanningHeight) }
2500 #undef F_SIZE
2502 int i;
2504 if (!dm) return FALSE;
2505 if (size < FIELD_OFFSET(DEVMODEW, dmFields) + sizeof(dm->dmFields)) return FALSE;
2507 for (i = 0; i < ARRAY_SIZE(map); i++)
2508 if ((dm->dmFields & map[i].flag) && size < map[i].size)
2509 return FALSE;
2511 return TRUE;
2514 /******************************************************************
2515 * OpenPrinterA [WINSPOOL.@]
2517 * See OpenPrinterW.
2520 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2521 LPPRINTER_DEFAULTSA pDefault)
2523 UNICODE_STRING lpPrinterNameW;
2524 UNICODE_STRING usBuffer;
2525 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2526 PWSTR pwstrPrinterNameW;
2527 BOOL ret;
2529 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName), phPrinter, pDefault);
2531 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2533 if(pDefault) {
2534 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2535 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2536 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2537 pDefaultW = &DefaultW;
2539 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2540 if(pDefault) {
2541 RtlFreeUnicodeString(&usBuffer);
2542 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2544 RtlFreeUnicodeString(&lpPrinterNameW);
2545 return ret;
2548 /******************************************************************
2549 * OpenPrinterW [WINSPOOL.@]
2551 * Open a Printer / Printserver or a Printer-Object
2553 * PARAMS
2554 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2555 * phPrinter [O] The resulting Handle is stored here
2556 * pDefault [I] PTR to Default Printer Settings or NULL
2558 * RETURNS
2559 * Success: TRUE
2560 * Failure: FALSE
2562 * NOTES
2563 * lpPrinterName is one of:
2564 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2565 *| Printer: "PrinterName"
2566 *| Printer-Object: "PrinterName,Job xxx"
2567 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2568 *| XcvPort: "Servername,XcvPort PortName"
2570 * BUGS
2571 *| Printer-Object not supported
2572 *| pDefaults is ignored
2575 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2577 HKEY key;
2579 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2581 if(!phPrinter) {
2582 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2583 SetLastError(ERROR_INVALID_PARAMETER);
2584 return FALSE;
2587 /* Get the unique handle of the printer or Printserver */
2588 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2590 if (*phPrinter && WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key ) == ERROR_SUCCESS)
2592 DWORD deleting = 0, size = sizeof( deleting ), type;
2593 DWORD status;
2594 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2595 WaitForSingleObject( init_mutex, INFINITE );
2596 status = get_dword_from_reg( key, StatusW );
2597 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2598 ReleaseMutex( init_mutex );
2599 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2600 update_driver( *phPrinter );
2601 RegCloseKey( key );
2604 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2605 return (*phPrinter != 0);
2608 /******************************************************************
2609 * AddMonitorA [WINSPOOL.@]
2611 * See AddMonitorW.
2614 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2616 LPWSTR nameW = NULL;
2617 INT len;
2618 BOOL res;
2619 LPMONITOR_INFO_2A mi2a;
2620 MONITOR_INFO_2W mi2w;
2622 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2623 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2624 debugstr_a(mi2a ? mi2a->pName : NULL),
2625 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2626 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2628 if (Level != 2) {
2629 SetLastError(ERROR_INVALID_LEVEL);
2630 return FALSE;
2633 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2634 if (mi2a == NULL) {
2635 return FALSE;
2638 if (pName) {
2639 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2640 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2641 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2644 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2645 if (mi2a->pName) {
2646 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2647 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2648 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2650 if (mi2a->pEnvironment) {
2651 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2652 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2653 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2655 if (mi2a->pDLLName) {
2656 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2657 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2658 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2661 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2663 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2664 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2665 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2667 HeapFree(GetProcessHeap(), 0, nameW);
2668 return (res);
2671 /******************************************************************************
2672 * AddMonitorW [WINSPOOL.@]
2674 * Install a Printmonitor
2676 * PARAMS
2677 * pName [I] Servername or NULL (local Computer)
2678 * Level [I] Structure-Level (Must be 2)
2679 * pMonitors [I] PTR to MONITOR_INFO_2
2681 * RETURNS
2682 * Success: TRUE
2683 * Failure: FALSE
2685 * NOTES
2686 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2689 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2691 LPMONITOR_INFO_2W mi2w;
2693 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2694 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2695 debugstr_w(mi2w ? mi2w->pName : NULL),
2696 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2697 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2699 if ((backend == NULL) && !load_backend()) return FALSE;
2701 if (Level != 2) {
2702 SetLastError(ERROR_INVALID_LEVEL);
2703 return FALSE;
2706 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2707 if (mi2w == NULL) {
2708 return FALSE;
2711 return backend->fpAddMonitor(pName, Level, pMonitors);
2714 /******************************************************************
2715 * DeletePrinterDriverA [WINSPOOL.@]
2718 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2720 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2723 /******************************************************************
2724 * DeletePrinterDriverW [WINSPOOL.@]
2727 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2729 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2732 /******************************************************************
2733 * DeleteMonitorA [WINSPOOL.@]
2735 * See DeleteMonitorW.
2738 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2740 LPWSTR nameW = NULL;
2741 LPWSTR EnvironmentW = NULL;
2742 LPWSTR MonitorNameW = NULL;
2743 BOOL res;
2744 INT len;
2746 if (pName) {
2747 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2748 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2749 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2752 if (pEnvironment) {
2753 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2754 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2755 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2757 if (pMonitorName) {
2758 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2759 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2760 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2763 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2765 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2766 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2767 HeapFree(GetProcessHeap(), 0, nameW);
2768 return (res);
2771 /******************************************************************
2772 * DeleteMonitorW [WINSPOOL.@]
2774 * Delete a specific Printmonitor from a Printing-Environment
2776 * PARAMS
2777 * pName [I] Servername or NULL (local Computer)
2778 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2779 * pMonitorName [I] Name of the Monitor, that should be deleted
2781 * RETURNS
2782 * Success: TRUE
2783 * Failure: FALSE
2785 * NOTES
2786 * pEnvironment is ignored in Windows for the local Computer.
2789 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2792 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2793 debugstr_w(pMonitorName));
2795 if ((backend == NULL) && !load_backend()) return FALSE;
2797 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2801 /******************************************************************
2802 * DeletePortA [WINSPOOL.@]
2804 * See DeletePortW.
2807 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2809 LPWSTR nameW = NULL;
2810 LPWSTR portW = NULL;
2811 INT len;
2812 DWORD res;
2814 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2816 /* convert servername to unicode */
2817 if (pName) {
2818 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2819 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2820 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2823 /* convert portname to unicode */
2824 if (pPortName) {
2825 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2826 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2827 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2830 res = DeletePortW(nameW, hWnd, portW);
2831 HeapFree(GetProcessHeap(), 0, nameW);
2832 HeapFree(GetProcessHeap(), 0, portW);
2833 return res;
2836 /******************************************************************
2837 * DeletePortW [WINSPOOL.@]
2839 * Delete a specific Port
2841 * PARAMS
2842 * pName [I] Servername or NULL (local Computer)
2843 * hWnd [I] Handle to parent Window for the Dialog-Box
2844 * pPortName [I] Name of the Port, that should be deleted
2846 * RETURNS
2847 * Success: TRUE
2848 * Failure: FALSE
2851 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2853 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2855 if ((backend == NULL) && !load_backend()) return FALSE;
2857 if (!pPortName) {
2858 SetLastError(RPC_X_NULL_REF_POINTER);
2859 return FALSE;
2862 return backend->fpDeletePort(pName, hWnd, pPortName);
2865 /******************************************************************************
2866 * WritePrinter [WINSPOOL.@]
2868 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2870 opened_printer_t *printer;
2871 BOOL ret = FALSE;
2873 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2875 EnterCriticalSection(&printer_handles_cs);
2876 printer = get_opened_printer(hPrinter);
2877 if(!printer)
2879 SetLastError(ERROR_INVALID_HANDLE);
2880 goto end;
2883 if(!printer->doc)
2885 SetLastError(ERROR_SPL_NO_STARTDOC);
2886 goto end;
2889 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2890 end:
2891 LeaveCriticalSection(&printer_handles_cs);
2892 return ret;
2895 /*****************************************************************************
2896 * AddFormA [WINSPOOL.@]
2898 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2900 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2901 return TRUE;
2904 /*****************************************************************************
2905 * AddFormW [WINSPOOL.@]
2907 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2909 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2910 return TRUE;
2913 /*****************************************************************************
2914 * AddJobA [WINSPOOL.@]
2916 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2918 BOOL ret;
2919 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2920 DWORD needed;
2922 if(Level != 1) {
2923 SetLastError(ERROR_INVALID_LEVEL);
2924 return FALSE;
2927 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2929 if(ret) {
2930 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2931 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2932 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2933 if(*pcbNeeded > cbBuf) {
2934 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2935 ret = FALSE;
2936 } else {
2937 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2938 addjobA->JobId = addjobW->JobId;
2939 addjobA->Path = (char *)(addjobA + 1);
2940 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2943 return ret;
2946 /*****************************************************************************
2947 * AddJobW [WINSPOOL.@]
2949 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2951 opened_printer_t *printer;
2952 job_t *job;
2953 BOOL ret = FALSE;
2954 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2955 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2956 WCHAR path[MAX_PATH], filename[MAX_PATH];
2957 DWORD len;
2958 ADDJOB_INFO_1W *addjob;
2960 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2962 EnterCriticalSection(&printer_handles_cs);
2964 printer = get_opened_printer(hPrinter);
2966 if(!printer) {
2967 SetLastError(ERROR_INVALID_HANDLE);
2968 goto end;
2971 if(Level != 1) {
2972 SetLastError(ERROR_INVALID_LEVEL);
2973 goto end;
2976 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2977 if(!job)
2978 goto end;
2980 job->job_id = InterlockedIncrement(&next_job_id);
2982 len = GetSystemDirectoryW(path, ARRAY_SIZE(path));
2983 if(path[len - 1] != '\\')
2984 path[len++] = '\\';
2985 memcpy(path + len, spool_path, sizeof(spool_path));
2986 sprintfW(filename, fmtW, path, job->job_id);
2988 len = strlenW(filename);
2989 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2990 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2991 job->portname = NULL;
2992 job->document_title = strdupW(default_doc_title);
2993 job->printer_name = strdupW(printer->name);
2994 job->devmode = dup_devmode( printer->devmode );
2995 list_add_tail(&printer->queue->jobs, &job->entry);
2997 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2998 if(*pcbNeeded <= cbBuf) {
2999 addjob = (ADDJOB_INFO_1W*)pData;
3000 addjob->JobId = job->job_id;
3001 addjob->Path = (WCHAR *)(addjob + 1);
3002 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
3003 ret = TRUE;
3004 } else
3005 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3007 end:
3008 LeaveCriticalSection(&printer_handles_cs);
3009 return ret;
3012 /*****************************************************************************
3013 * GetPrintProcessorDirectoryA [WINSPOOL.@]
3015 * Return the PATH for the Print-Processors
3017 * See GetPrintProcessorDirectoryW.
3021 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
3022 DWORD level, LPBYTE Info,
3023 DWORD cbBuf, LPDWORD pcbNeeded)
3025 LPWSTR serverW = NULL;
3026 LPWSTR envW = NULL;
3027 BOOL ret;
3028 INT len;
3030 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
3031 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
3034 if (server) {
3035 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
3036 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3037 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
3040 if (env) {
3041 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
3042 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3043 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
3046 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
3047 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
3049 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
3050 cbBuf, pcbNeeded);
3052 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
3053 cbBuf, NULL, NULL) > 0;
3056 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3057 HeapFree(GetProcessHeap(), 0, envW);
3058 HeapFree(GetProcessHeap(), 0, serverW);
3059 return ret;
3062 /*****************************************************************************
3063 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3065 * Return the PATH for the Print-Processors
3067 * PARAMS
3068 * server [I] Servername (NT only) or NULL (local Computer)
3069 * env [I] Printing-Environment (see below) or NULL (Default)
3070 * level [I] Structure-Level (must be 1)
3071 * Info [O] PTR to Buffer that receives the Result
3072 * cbBuf [I] Size of Buffer at "Info"
3073 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3074 * required for the Buffer at "Info"
3076 * RETURNS
3077 * Success: TRUE and in pcbNeeded the Bytes used in Info
3078 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3079 * if cbBuf is too small
3081 * Native Values returned in Info on Success:
3082 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3083 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3084 *| win9x(Windows 4.0): "%winsysdir%"
3086 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3088 * BUGS
3089 * Only NULL or "" is supported for server
3092 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3093 DWORD level, LPBYTE Info,
3094 DWORD cbBuf, LPDWORD pcbNeeded)
3097 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3098 Info, cbBuf, pcbNeeded);
3100 if ((backend == NULL) && !load_backend()) return FALSE;
3102 if (level != 1) {
3103 /* (Level != 1) is ignored in win9x */
3104 SetLastError(ERROR_INVALID_LEVEL);
3105 return FALSE;
3108 if (pcbNeeded == NULL) {
3109 /* (pcbNeeded == NULL) is ignored in win9x */
3110 SetLastError(RPC_X_NULL_REF_POINTER);
3111 return FALSE;
3114 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3117 /*****************************************************************************
3118 * WINSPOOL_OpenDriverReg [internal]
3120 * opens the registry for the printer drivers depending on the given input
3121 * variable pEnvironment
3123 * RETURNS:
3124 * the opened hkey on success
3125 * NULL on error
3127 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3129 HKEY retval = NULL;
3130 LPWSTR buffer;
3131 const printenv_t * env;
3133 TRACE("(%s)\n", debugstr_w(pEnvironment));
3135 env = validate_envW(pEnvironment);
3136 if (!env) return NULL;
3138 buffer = HeapAlloc( GetProcessHeap(), 0,
3139 (strlenW(DriversW) + strlenW(env->envname) +
3140 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3141 if(buffer) {
3142 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3143 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3144 HeapFree(GetProcessHeap(), 0, buffer);
3146 return retval;
3149 /*****************************************************************************
3150 * set_devices_and_printerports [internal]
3152 * set the [Devices] and [PrinterPorts] entries for a printer.
3155 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3157 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3158 WCHAR *devline;
3159 HKEY hkey;
3161 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3163 /* FIXME: the driver must change to "winspool" */
3164 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3165 if (devline) {
3166 lstrcpyW(devline, driver_nt);
3167 lstrcatW(devline, commaW);
3168 lstrcatW(devline, pi->pPortName);
3170 TRACE("using %s\n", debugstr_w(devline));
3171 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3172 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3173 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3174 RegCloseKey(hkey);
3177 lstrcatW(devline, timeout_15_45);
3178 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3179 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3180 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3181 RegCloseKey(hkey);
3183 HeapFree(GetProcessHeap(), 0, devline);
3187 /*****************************************************************************
3188 * AddPrinterW [WINSPOOL.@]
3190 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3192 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3193 LPDEVMODEW dm;
3194 HANDLE retval;
3195 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3196 LONG size;
3198 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3200 if(pName && *pName) {
3201 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3202 SetLastError(ERROR_INVALID_PARAMETER);
3203 return 0;
3205 if(Level != 2) {
3206 ERR("Level = %d, unsupported!\n", Level);
3207 SetLastError(ERROR_INVALID_LEVEL);
3208 return 0;
3210 if(!pPrinter) {
3211 SetLastError(ERROR_INVALID_PARAMETER);
3212 return 0;
3214 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3215 ERROR_SUCCESS) {
3216 ERR("Can't create Printers key\n");
3217 return 0;
3219 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3220 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3221 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3222 RegCloseKey(hkeyPrinter);
3223 RegCloseKey(hkeyPrinters);
3224 return 0;
3226 RegCloseKey(hkeyPrinter);
3228 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3229 if(!hkeyDrivers) {
3230 ERR("Can't create Drivers key\n");
3231 RegCloseKey(hkeyPrinters);
3232 return 0;
3234 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3235 ERROR_SUCCESS) {
3236 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3237 RegCloseKey(hkeyPrinters);
3238 RegCloseKey(hkeyDrivers);
3239 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3240 return 0;
3242 RegCloseKey(hkeyDriver);
3243 RegCloseKey(hkeyDrivers);
3245 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3246 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3247 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3248 RegCloseKey(hkeyPrinters);
3249 return 0;
3252 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3253 ERROR_SUCCESS) {
3254 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3255 SetLastError(ERROR_INVALID_PRINTER_NAME);
3256 RegCloseKey(hkeyPrinters);
3257 return 0;
3260 set_devices_and_printerports(pi);
3262 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3263 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3264 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3265 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3266 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3267 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3268 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3269 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3270 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3271 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3272 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3273 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3274 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3275 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3276 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3277 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3278 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3279 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3281 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3283 if (size < 0)
3285 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3286 size = sizeof(DEVMODEW);
3288 if(pi->pDevMode)
3289 dm = pi->pDevMode;
3290 else
3292 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3293 dm->dmSize = size;
3294 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3296 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3297 HeapFree( GetProcessHeap(), 0, dm );
3298 dm = NULL;
3300 else
3302 /* set devmode to printer name */
3303 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3307 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3308 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3310 RegCloseKey(hkeyPrinter);
3311 RegCloseKey(hkeyPrinters);
3312 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3313 ERR("OpenPrinter failing\n");
3314 return 0;
3316 return retval;
3319 /*****************************************************************************
3320 * AddPrinterA [WINSPOOL.@]
3322 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3324 UNICODE_STRING pNameW;
3325 PWSTR pwstrNameW;
3326 PRINTER_INFO_2W *piW;
3327 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3328 HANDLE ret;
3330 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3331 if(Level != 2) {
3332 ERR("Level = %d, unsupported!\n", Level);
3333 SetLastError(ERROR_INVALID_LEVEL);
3334 return 0;
3336 pwstrNameW = asciitounicode(&pNameW,pName);
3337 piW = printer_info_AtoW( piA, Level );
3339 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3341 free_printer_info( piW, Level );
3342 RtlFreeUnicodeString(&pNameW);
3343 return ret;
3347 /*****************************************************************************
3348 * ClosePrinter [WINSPOOL.@]
3350 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3352 UINT_PTR i = (UINT_PTR)hPrinter;
3353 opened_printer_t *printer = NULL;
3355 TRACE("(%p)\n", hPrinter);
3357 EnterCriticalSection(&printer_handles_cs);
3359 if ((i > 0) && (i <= nb_printer_handles))
3360 printer = printer_handles[i - 1];
3363 if(printer)
3365 struct list *cursor, *cursor2;
3367 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3369 if(printer->doc)
3370 EndDocPrinter(hPrinter);
3372 if(InterlockedDecrement(&printer->queue->ref) == 0)
3374 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3376 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3377 ScheduleJob(hPrinter, job->job_id);
3379 HeapFree(GetProcessHeap(), 0, printer->queue);
3382 if (printer->backend_printer) {
3383 backend->fpClosePrinter(printer->backend_printer);
3386 free_printer_entry( printer );
3387 printer_handles[i - 1] = NULL;
3388 LeaveCriticalSection(&printer_handles_cs);
3389 return TRUE;
3392 LeaveCriticalSection(&printer_handles_cs);
3393 SetLastError(ERROR_INVALID_HANDLE);
3394 return FALSE;
3397 /*****************************************************************************
3398 * DeleteFormA [WINSPOOL.@]
3400 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3402 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3403 return TRUE;
3406 /*****************************************************************************
3407 * DeleteFormW [WINSPOOL.@]
3409 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3411 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3412 return TRUE;
3415 /*****************************************************************************
3416 * DeletePrinter [WINSPOOL.@]
3418 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3420 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3421 HKEY hkeyPrinters, hkey;
3422 WCHAR def[MAX_PATH];
3423 DWORD size = ARRAY_SIZE(def);
3425 if(!lpNameW) {
3426 SetLastError(ERROR_INVALID_HANDLE);
3427 return FALSE;
3429 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3430 RegDeleteTreeW(hkeyPrinters, lpNameW);
3431 RegCloseKey(hkeyPrinters);
3434 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3435 RegDeleteValueW(hkey, lpNameW);
3436 RegCloseKey(hkey);
3439 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3440 RegDeleteValueW(hkey, lpNameW);
3441 RegCloseKey(hkey);
3444 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3446 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3448 RegDeleteValueW( hkey, deviceW );
3449 RegCloseKey( hkey );
3451 SetDefaultPrinterW( NULL );
3454 return TRUE;
3457 /*****************************************************************************
3458 * SetPrinterA [WINSPOOL.@]
3460 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3462 BYTE *dataW = data;
3463 BOOL ret;
3465 if (level != 0)
3467 dataW = printer_info_AtoW( data, level );
3468 if (!dataW) return FALSE;
3471 ret = SetPrinterW( printer, level, dataW, command );
3473 if (dataW != data) free_printer_info( dataW, level );
3475 return ret;
3478 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3480 set_reg_szW( key, NameW, pi->pPrinterName );
3481 set_reg_szW( key, Share_NameW, pi->pShareName );
3482 set_reg_szW( key, PortW, pi->pPortName );
3483 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3484 set_reg_szW( key, DescriptionW, pi->pComment );
3485 set_reg_szW( key, LocationW, pi->pLocation );
3487 if (pi->pDevMode)
3488 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3490 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3491 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3492 set_reg_szW( key, DatatypeW, pi->pDatatype );
3493 set_reg_szW( key, ParametersW, pi->pParameters );
3495 set_reg_DWORD( key, AttributesW, pi->Attributes );
3496 set_reg_DWORD( key, PriorityW, pi->Priority );
3497 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3498 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3499 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3502 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3504 if (!pi->pDevMode) return FALSE;
3506 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3507 return TRUE;
3510 /******************************************************************************
3511 * SetPrinterW [WINSPOOL.@]
3513 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3515 HKEY key;
3516 BOOL ret = FALSE;
3518 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3520 if (command != 0) FIXME( "Ignoring command %d\n", command );
3522 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3523 return FALSE;
3525 switch (level)
3527 case 2:
3529 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3530 set_printer_2( key, pi2 );
3531 ret = TRUE;
3532 break;
3535 case 8:
3536 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
3537 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3538 /* fall through */
3539 case 9:
3541 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3542 ret = set_printer_9( key, pi );
3543 break;
3546 default:
3547 FIXME( "Unimplemented level %d\n", level );
3548 SetLastError( ERROR_INVALID_LEVEL );
3551 RegCloseKey( key );
3552 return ret;
3555 /*****************************************************************************
3556 * SetJobA [WINSPOOL.@]
3558 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3559 LPBYTE pJob, DWORD Command)
3561 BOOL ret;
3562 LPBYTE JobW;
3563 UNICODE_STRING usBuffer;
3565 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3567 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3568 are all ignored by SetJob, so we don't bother copying them */
3569 switch(Level)
3571 case 0:
3572 JobW = NULL;
3573 break;
3574 case 1:
3576 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3577 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3579 JobW = (LPBYTE)info1W;
3580 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3581 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3582 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3583 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3584 info1W->Status = info1A->Status;
3585 info1W->Priority = info1A->Priority;
3586 info1W->Position = info1A->Position;
3587 info1W->PagesPrinted = info1A->PagesPrinted;
3588 break;
3590 case 2:
3592 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3593 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3595 JobW = (LPBYTE)info2W;
3596 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3597 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3598 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3599 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3600 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3601 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3602 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3603 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3604 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3605 info2W->Status = info2A->Status;
3606 info2W->Priority = info2A->Priority;
3607 info2W->Position = info2A->Position;
3608 info2W->StartTime = info2A->StartTime;
3609 info2W->UntilTime = info2A->UntilTime;
3610 info2W->PagesPrinted = info2A->PagesPrinted;
3611 break;
3613 case 3:
3614 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3615 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3616 break;
3617 default:
3618 SetLastError(ERROR_INVALID_LEVEL);
3619 return FALSE;
3622 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3624 switch(Level)
3626 case 1:
3628 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3629 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3630 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3631 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3632 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3633 break;
3635 case 2:
3637 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3638 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3639 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3640 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3641 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3642 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3643 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3644 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3645 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3646 break;
3649 HeapFree(GetProcessHeap(), 0, JobW);
3651 return ret;
3654 /*****************************************************************************
3655 * SetJobW [WINSPOOL.@]
3657 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3658 LPBYTE pJob, DWORD Command)
3660 BOOL ret = FALSE;
3661 job_t *job;
3663 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3664 FIXME("Ignoring everything other than document title\n");
3666 EnterCriticalSection(&printer_handles_cs);
3667 job = get_job(hPrinter, JobId);
3668 if(!job)
3669 goto end;
3671 switch(Level)
3673 case 0:
3674 break;
3675 case 1:
3677 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3678 HeapFree(GetProcessHeap(), 0, job->document_title);
3679 job->document_title = strdupW(info1->pDocument);
3680 break;
3682 case 2:
3684 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3685 HeapFree(GetProcessHeap(), 0, job->document_title);
3686 job->document_title = strdupW(info2->pDocument);
3687 HeapFree(GetProcessHeap(), 0, job->devmode);
3688 job->devmode = dup_devmode( info2->pDevMode );
3689 break;
3691 case 3:
3692 break;
3693 default:
3694 SetLastError(ERROR_INVALID_LEVEL);
3695 goto end;
3697 ret = TRUE;
3698 end:
3699 LeaveCriticalSection(&printer_handles_cs);
3700 return ret;
3703 /*****************************************************************************
3704 * EndDocPrinter [WINSPOOL.@]
3706 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3708 opened_printer_t *printer;
3709 BOOL ret = FALSE;
3710 TRACE("(%p)\n", hPrinter);
3712 EnterCriticalSection(&printer_handles_cs);
3714 printer = get_opened_printer(hPrinter);
3715 if(!printer)
3717 SetLastError(ERROR_INVALID_HANDLE);
3718 goto end;
3721 if(!printer->doc)
3723 SetLastError(ERROR_SPL_NO_STARTDOC);
3724 goto end;
3727 CloseHandle(printer->doc->hf);
3728 ScheduleJob(hPrinter, printer->doc->job_id);
3729 HeapFree(GetProcessHeap(), 0, printer->doc);
3730 printer->doc = NULL;
3731 ret = TRUE;
3732 end:
3733 LeaveCriticalSection(&printer_handles_cs);
3734 return ret;
3737 /*****************************************************************************
3738 * EndPagePrinter [WINSPOOL.@]
3740 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3742 FIXME("(%p): stub\n", hPrinter);
3743 return TRUE;
3746 /*****************************************************************************
3747 * StartDocPrinterA [WINSPOOL.@]
3749 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3751 UNICODE_STRING usBuffer;
3752 DOC_INFO_2W doc2W;
3753 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3754 DWORD ret;
3756 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3757 or one (DOC_INFO_3) extra DWORDs */
3759 switch(Level) {
3760 case 2:
3761 doc2W.JobId = doc2->JobId;
3762 /* fall through */
3763 case 3:
3764 doc2W.dwMode = doc2->dwMode;
3765 /* fall through */
3766 case 1:
3767 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3768 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3769 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3770 break;
3772 default:
3773 SetLastError(ERROR_INVALID_LEVEL);
3774 return FALSE;
3777 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3779 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3780 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3781 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3783 return ret;
3786 /*****************************************************************************
3787 * StartDocPrinterW [WINSPOOL.@]
3789 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3791 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3792 opened_printer_t *printer;
3793 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3794 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3795 JOB_INFO_1W job_info;
3796 DWORD needed, ret = 0;
3797 HANDLE hf;
3798 WCHAR *filename;
3799 job_t *job;
3801 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3802 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3803 debugstr_w(doc->pDatatype));
3805 if(Level < 1 || Level > 3)
3807 SetLastError(ERROR_INVALID_LEVEL);
3808 return 0;
3811 EnterCriticalSection(&printer_handles_cs);
3812 printer = get_opened_printer(hPrinter);
3813 if(!printer)
3815 SetLastError(ERROR_INVALID_HANDLE);
3816 goto end;
3819 if(printer->doc)
3821 SetLastError(ERROR_INVALID_PRINTER_STATE);
3822 goto end;
3825 /* Even if we're printing to a file we still add a print job, we'll
3826 just ignore the spool file name */
3828 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3830 ERR("AddJob failed gle %u\n", GetLastError());
3831 goto end;
3834 /* use pOutputFile only, when it is a real filename */
3835 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3836 filename = doc->pOutputFile;
3837 else
3838 filename = addjob->Path;
3840 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3841 if(hf == INVALID_HANDLE_VALUE)
3842 goto end;
3844 memset(&job_info, 0, sizeof(job_info));
3845 job_info.pDocument = doc->pDocName;
3846 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3848 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3849 printer->doc->hf = hf;
3850 ret = printer->doc->job_id = addjob->JobId;
3851 job = get_job(hPrinter, ret);
3852 job->portname = strdupW(doc->pOutputFile);
3854 end:
3855 LeaveCriticalSection(&printer_handles_cs);
3857 return ret;
3860 /*****************************************************************************
3861 * StartPagePrinter [WINSPOOL.@]
3863 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3865 FIXME("(%p): stub\n", hPrinter);
3866 return TRUE;
3869 /*****************************************************************************
3870 * GetFormA [WINSPOOL.@]
3872 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3873 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3875 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3876 Level,pForm,cbBuf,pcbNeeded);
3877 return FALSE;
3880 /*****************************************************************************
3881 * GetFormW [WINSPOOL.@]
3883 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3884 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3886 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3887 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3888 return FALSE;
3891 /*****************************************************************************
3892 * SetFormA [WINSPOOL.@]
3894 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3895 LPBYTE pForm)
3897 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3898 return FALSE;
3901 /*****************************************************************************
3902 * SetFormW [WINSPOOL.@]
3904 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3905 LPBYTE pForm)
3907 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3908 return FALSE;
3911 /*****************************************************************************
3912 * ReadPrinter [WINSPOOL.@]
3914 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3915 LPDWORD pNoBytesRead)
3917 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3918 return FALSE;
3921 /*****************************************************************************
3922 * ResetPrinterA [WINSPOOL.@]
3924 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3926 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3927 return FALSE;
3930 /*****************************************************************************
3931 * ResetPrinterW [WINSPOOL.@]
3933 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3935 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3936 return FALSE;
3939 /*****************************************************************************
3940 * get_filename_from_reg [internal]
3942 * Get ValueName from hkey storing result in out
3943 * when the Value in the registry has only a filename, use driverdir as prefix
3944 * outlen is space left in out
3945 * String is stored either as unicode or ascii
3949 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3950 LPBYTE out, DWORD outlen, LPDWORD needed)
3952 WCHAR filename[MAX_PATH];
3953 DWORD size;
3954 DWORD type;
3955 LONG ret;
3956 LPWSTR buffer = filename;
3957 LPWSTR ptr;
3959 *needed = 0;
3960 size = sizeof(filename);
3961 buffer[0] = '\0';
3962 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3963 if (ret == ERROR_MORE_DATA) {
3964 TRACE("need dynamic buffer: %u\n", size);
3965 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3966 if (!buffer) {
3967 /* No Memory is bad */
3968 return FALSE;
3970 buffer[0] = '\0';
3971 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3974 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3975 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3976 return FALSE;
3979 ptr = buffer;
3980 while (ptr) {
3981 /* do we have a full path ? */
3982 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3983 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3985 if (!ret) {
3986 /* we must build the full Path */
3987 *needed += dirlen;
3988 if ((out) && (outlen > dirlen)) {
3989 lstrcpyW((LPWSTR)out, driverdir);
3990 out += dirlen;
3991 outlen -= dirlen;
3993 else
3994 out = NULL;
3997 /* write the filename */
3998 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3999 if ((out) && (outlen >= size)) {
4000 lstrcpyW((LPWSTR)out, ptr);
4001 out += size;
4002 outlen -= size;
4004 else
4005 out = NULL;
4006 *needed += size;
4007 ptr += lstrlenW(ptr)+1;
4008 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
4011 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
4013 /* write the multisz-termination */
4014 if (type == REG_MULTI_SZ) {
4015 size = sizeof(WCHAR);
4017 *needed += size;
4018 if (out && (outlen >= size)) {
4019 memset (out, 0, size);
4022 return TRUE;
4025 /*****************************************************************************
4026 * WINSPOOL_GetStringFromReg
4028 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4029 * String is stored as unicode.
4031 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
4032 DWORD buflen, DWORD *needed)
4034 DWORD sz = buflen, type;
4035 LONG ret;
4037 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4038 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
4039 WARN("Got ret = %d\n", ret);
4040 *needed = 0;
4041 return FALSE;
4043 /* add space for terminating '\0' */
4044 sz += sizeof(WCHAR);
4045 *needed = sz;
4047 if (ptr)
4048 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
4050 return TRUE;
4053 /*****************************************************************************
4054 * WINSPOOL_GetDefaultDevMode
4056 * Get a default DevMode values for wineps.
4058 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr, DWORD buflen, DWORD *needed)
4060 static const WCHAR winepsW[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4062 if (buflen >= sizeof(DEVMODEW))
4064 DEVMODEW *dm = (DEVMODEW *)ptr;
4066 /* the driver will update registry with real values */
4067 memset(dm, 0, sizeof(*dm));
4068 dm->dmSize = sizeof(*dm);
4069 lstrcpyW(dm->dmDeviceName, winepsW);
4071 *needed = sizeof(DEVMODEW);
4074 /*****************************************************************************
4075 * WINSPOOL_GetDevModeFromReg
4077 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4078 * DevMode is stored either as unicode or ascii.
4080 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4081 LPBYTE ptr,
4082 DWORD buflen, DWORD *needed)
4084 DWORD sz = buflen, type;
4085 LONG ret;
4087 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4088 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4089 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4090 if (sz < sizeof(DEVMODEA))
4092 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4093 return FALSE;
4095 /* ensures that dmSize is not erratically bogus if registry is invalid */
4096 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4097 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4098 sz += (CCHDEVICENAME + CCHFORMNAME);
4099 if (ptr && (buflen >= sz)) {
4100 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4101 memcpy(ptr, dmW, sz);
4102 HeapFree(GetProcessHeap(),0,dmW);
4104 *needed = sz;
4105 return TRUE;
4108 /*********************************************************************
4109 * WINSPOOL_GetPrinter_1
4111 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4113 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4114 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4116 DWORD size, left = cbBuf;
4117 BOOL space = (cbBuf > 0);
4118 LPBYTE ptr = buf;
4120 *pcbNeeded = 0;
4122 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4123 if(space && size <= left) {
4124 pi1->pName = (LPWSTR)ptr;
4125 ptr += size;
4126 left -= size;
4127 } else
4128 space = FALSE;
4129 *pcbNeeded += size;
4132 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4133 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4134 if(space && size <= left) {
4135 pi1->pDescription = (LPWSTR)ptr;
4136 ptr += size;
4137 left -= size;
4138 } else
4139 space = FALSE;
4140 *pcbNeeded += size;
4143 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4144 if(space && size <= left) {
4145 pi1->pComment = (LPWSTR)ptr;
4146 ptr += size;
4147 left -= size;
4148 } else
4149 space = FALSE;
4150 *pcbNeeded += size;
4153 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4155 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4156 memset(pi1, 0, sizeof(*pi1));
4158 return space;
4160 /*********************************************************************
4161 * WINSPOOL_GetPrinter_2
4163 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4165 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4166 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4168 DWORD size, left = cbBuf;
4169 BOOL space = (cbBuf > 0);
4170 LPBYTE ptr = buf;
4172 *pcbNeeded = 0;
4174 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4175 if(space && size <= left) {
4176 pi2->pPrinterName = (LPWSTR)ptr;
4177 ptr += size;
4178 left -= size;
4179 } else
4180 space = FALSE;
4181 *pcbNeeded += size;
4183 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4184 if(space && size <= left) {
4185 pi2->pShareName = (LPWSTR)ptr;
4186 ptr += size;
4187 left -= size;
4188 } else
4189 space = FALSE;
4190 *pcbNeeded += size;
4192 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4193 if(space && size <= left) {
4194 pi2->pPortName = (LPWSTR)ptr;
4195 ptr += size;
4196 left -= size;
4197 } else
4198 space = FALSE;
4199 *pcbNeeded += size;
4201 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4202 if(space && size <= left) {
4203 pi2->pDriverName = (LPWSTR)ptr;
4204 ptr += size;
4205 left -= size;
4206 } else
4207 space = FALSE;
4208 *pcbNeeded += size;
4210 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4211 if(space && size <= left) {
4212 pi2->pComment = (LPWSTR)ptr;
4213 ptr += size;
4214 left -= size;
4215 } else
4216 space = FALSE;
4217 *pcbNeeded += size;
4219 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4220 if(space && size <= left) {
4221 pi2->pLocation = (LPWSTR)ptr;
4222 ptr += size;
4223 left -= size;
4224 } else
4225 space = FALSE;
4226 *pcbNeeded += size;
4228 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4229 if(space && size <= left) {
4230 pi2->pDevMode = (LPDEVMODEW)ptr;
4231 ptr += size;
4232 left -= size;
4233 } else
4234 space = FALSE;
4235 *pcbNeeded += size;
4237 else
4239 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4240 if(space && size <= left) {
4241 pi2->pDevMode = (LPDEVMODEW)ptr;
4242 ptr += size;
4243 left -= size;
4244 } else
4245 space = FALSE;
4246 *pcbNeeded += size;
4248 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4249 if(space && size <= left) {
4250 pi2->pSepFile = (LPWSTR)ptr;
4251 ptr += size;
4252 left -= size;
4253 } else
4254 space = FALSE;
4255 *pcbNeeded += size;
4257 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4258 if(space && size <= left) {
4259 pi2->pPrintProcessor = (LPWSTR)ptr;
4260 ptr += size;
4261 left -= size;
4262 } else
4263 space = FALSE;
4264 *pcbNeeded += size;
4266 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4267 if(space && size <= left) {
4268 pi2->pDatatype = (LPWSTR)ptr;
4269 ptr += size;
4270 left -= size;
4271 } else
4272 space = FALSE;
4273 *pcbNeeded += size;
4275 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4276 if(space && size <= left) {
4277 pi2->pParameters = (LPWSTR)ptr;
4278 ptr += size;
4279 left -= size;
4280 } else
4281 space = FALSE;
4282 *pcbNeeded += size;
4284 if(pi2) {
4285 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4286 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4287 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4288 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4289 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4292 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4293 memset(pi2, 0, sizeof(*pi2));
4295 return space;
4298 /*********************************************************************
4299 * WINSPOOL_GetPrinter_4
4301 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4303 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
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 pi4->pPrinterName = (LPWSTR)ptr;
4315 ptr += size;
4316 left -= size;
4317 } else
4318 space = FALSE;
4319 *pcbNeeded += size;
4321 if(pi4) {
4322 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4325 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4326 memset(pi4, 0, sizeof(*pi4));
4328 return space;
4331 /*********************************************************************
4332 * WINSPOOL_GetPrinter_5
4334 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4336 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4337 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4339 DWORD size, left = cbBuf;
4340 BOOL space = (cbBuf > 0);
4341 LPBYTE ptr = buf;
4343 *pcbNeeded = 0;
4345 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4346 if(space && size <= left) {
4347 pi5->pPrinterName = (LPWSTR)ptr;
4348 ptr += size;
4349 left -= size;
4350 } else
4351 space = FALSE;
4352 *pcbNeeded += size;
4354 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4355 if(space && size <= left) {
4356 pi5->pPortName = (LPWSTR)ptr;
4357 ptr += size;
4358 left -= size;
4359 } else
4360 space = FALSE;
4361 *pcbNeeded += size;
4363 if(pi5) {
4364 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4365 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4366 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4369 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4370 memset(pi5, 0, sizeof(*pi5));
4372 return space;
4375 /*********************************************************************
4376 * WINSPOOL_GetPrinter_7
4378 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4380 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4381 DWORD cbBuf, LPDWORD pcbNeeded)
4383 DWORD size, left = cbBuf;
4384 BOOL space = (cbBuf > 0);
4385 LPBYTE ptr = buf;
4387 *pcbNeeded = 0;
4389 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4391 ptr = NULL;
4392 size = sizeof(pi7->pszObjectGUID);
4394 if (space && size <= left) {
4395 pi7->pszObjectGUID = (LPWSTR)ptr;
4396 ptr += size;
4397 left -= size;
4398 } else
4399 space = FALSE;
4400 *pcbNeeded += size;
4401 if (pi7) {
4402 /* We do not have a Directory Service */
4403 pi7->dwAction = DSPRINT_UNPUBLISH;
4406 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4407 memset(pi7, 0, sizeof(*pi7));
4409 return space;
4412 /*********************************************************************
4413 * WINSPOOL_GetPrinter_9
4415 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4417 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4418 DWORD cbBuf, LPDWORD pcbNeeded)
4420 DWORD size;
4421 BOOL space = (cbBuf > 0);
4423 *pcbNeeded = 0;
4425 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4426 if(space && size <= cbBuf) {
4427 pi9->pDevMode = (LPDEVMODEW)buf;
4428 } else
4429 space = FALSE;
4430 *pcbNeeded += size;
4432 else
4434 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4435 if(space && size <= cbBuf) {
4436 pi9->pDevMode = (LPDEVMODEW)buf;
4437 } else
4438 space = FALSE;
4439 *pcbNeeded += size;
4442 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4443 memset(pi9, 0, sizeof(*pi9));
4445 return space;
4448 /*****************************************************************************
4449 * GetPrinterW [WINSPOOL.@]
4451 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4452 DWORD cbBuf, LPDWORD pcbNeeded)
4454 DWORD size, needed = 0, err;
4455 LPBYTE ptr = NULL;
4456 HKEY hkeyPrinter;
4457 BOOL ret;
4459 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4461 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4462 if (err)
4464 SetLastError( err );
4465 return FALSE;
4468 switch(Level) {
4469 case 1:
4471 PRINTER_INFO_1W *pi1 = (PRINTER_INFO_1W *)pPrinter;
4473 size = sizeof(PRINTER_INFO_1W);
4474 if (size <= cbBuf) {
4475 ptr = pPrinter + size;
4476 cbBuf -= size;
4477 memset(pPrinter, 0, size);
4478 } else {
4479 pi1 = NULL;
4480 cbBuf = 0;
4482 ret = WINSPOOL_GetPrinter_1(hkeyPrinter, pi1, ptr, cbBuf, &needed);
4483 needed += size;
4484 break;
4487 case 2:
4489 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4491 size = sizeof(PRINTER_INFO_2W);
4492 if(size <= cbBuf) {
4493 ptr = pPrinter + size;
4494 cbBuf -= size;
4495 memset(pPrinter, 0, size);
4496 } else {
4497 pi2 = NULL;
4498 cbBuf = 0;
4500 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4501 needed += size;
4502 break;
4505 case 4:
4507 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4509 size = sizeof(PRINTER_INFO_4W);
4510 if(size <= cbBuf) {
4511 ptr = pPrinter + size;
4512 cbBuf -= size;
4513 memset(pPrinter, 0, size);
4514 } else {
4515 pi4 = NULL;
4516 cbBuf = 0;
4518 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4519 needed += size;
4520 break;
4524 case 5:
4526 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4528 size = sizeof(PRINTER_INFO_5W);
4529 if(size <= cbBuf) {
4530 ptr = pPrinter + size;
4531 cbBuf -= size;
4532 memset(pPrinter, 0, size);
4533 } else {
4534 pi5 = NULL;
4535 cbBuf = 0;
4538 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4539 needed += size;
4540 break;
4544 case 6:
4546 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4548 size = sizeof(PRINTER_INFO_6);
4549 if (size <= cbBuf) {
4550 /* FIXME: We do not update the status yet */
4551 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4552 ret = TRUE;
4553 } else {
4554 ret = FALSE;
4557 needed += size;
4558 break;
4561 case 7:
4563 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4565 size = sizeof(PRINTER_INFO_7W);
4566 if (size <= cbBuf) {
4567 ptr = pPrinter + size;
4568 cbBuf -= size;
4569 memset(pPrinter, 0, size);
4570 } else {
4571 pi7 = NULL;
4572 cbBuf = 0;
4575 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4576 needed += size;
4577 break;
4581 case 8:
4582 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4583 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4584 /* fall through */
4585 case 9:
4587 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4589 size = sizeof(PRINTER_INFO_9W);
4590 if(size <= cbBuf) {
4591 ptr = pPrinter + size;
4592 cbBuf -= size;
4593 memset(pPrinter, 0, size);
4594 } else {
4595 pi9 = NULL;
4596 cbBuf = 0;
4599 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4600 needed += size;
4601 break;
4605 default:
4606 FIXME("Unimplemented level %d\n", Level);
4607 SetLastError(ERROR_INVALID_LEVEL);
4608 RegCloseKey(hkeyPrinter);
4609 return FALSE;
4612 RegCloseKey(hkeyPrinter);
4614 TRACE("returning %d needed = %d\n", ret, needed);
4615 if(pcbNeeded) *pcbNeeded = needed;
4616 if(!ret)
4617 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4618 return ret;
4621 /*****************************************************************************
4622 * GetPrinterA [WINSPOOL.@]
4624 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4625 DWORD cbBuf, LPDWORD pcbNeeded)
4627 BOOL ret;
4628 LPBYTE buf = NULL;
4630 if (cbBuf)
4631 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4633 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4634 if (ret)
4635 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4636 HeapFree(GetProcessHeap(), 0, buf);
4638 return ret;
4641 /*****************************************************************************
4642 * WINSPOOL_EnumPrintersW
4644 * Implementation of EnumPrintersW
4646 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4647 DWORD dwLevel, LPBYTE lpbPrinters,
4648 DWORD cbBuf, LPDWORD lpdwNeeded,
4649 LPDWORD lpdwReturned)
4652 HKEY hkeyPrinters, hkeyPrinter;
4653 WCHAR PrinterName[255];
4654 DWORD needed = 0, number = 0;
4655 DWORD used, i, left;
4656 PBYTE pi, buf;
4658 if(lpbPrinters)
4659 memset(lpbPrinters, 0, cbBuf);
4660 if(lpdwReturned)
4661 *lpdwReturned = 0;
4662 if(lpdwNeeded)
4663 *lpdwNeeded = 0;
4665 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4666 if(dwType == PRINTER_ENUM_DEFAULT)
4667 return TRUE;
4669 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4670 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4671 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4672 if (!dwType) {
4673 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4674 return TRUE;
4679 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4680 FIXME("dwType = %08x\n", dwType);
4681 SetLastError(ERROR_INVALID_FLAGS);
4682 return FALSE;
4685 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4686 ERROR_SUCCESS) {
4687 ERR("Can't create Printers key\n");
4688 return FALSE;
4691 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4692 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4693 RegCloseKey(hkeyPrinters);
4694 ERR("Can't query Printers key\n");
4695 return FALSE;
4697 TRACE("Found %d printers\n", number);
4699 switch(dwLevel) {
4700 case 1:
4701 used = number * sizeof(PRINTER_INFO_1W);
4702 break;
4703 case 2:
4704 used = number * sizeof(PRINTER_INFO_2W);
4705 break;
4706 case 4:
4707 used = number * sizeof(PRINTER_INFO_4W);
4708 break;
4709 case 5:
4710 used = number * sizeof(PRINTER_INFO_5W);
4711 break;
4713 default:
4714 SetLastError(ERROR_INVALID_LEVEL);
4715 RegCloseKey(hkeyPrinters);
4716 return FALSE;
4718 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4720 for(i = 0; i < number; i++) {
4721 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, ARRAY_SIZE(PrinterName)) != ERROR_SUCCESS) {
4722 ERR("Can't enum key number %d\n", i);
4723 RegCloseKey(hkeyPrinters);
4724 return FALSE;
4726 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4727 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4728 ERROR_SUCCESS) {
4729 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4730 RegCloseKey(hkeyPrinters);
4731 return FALSE;
4734 if(cbBuf > used) {
4735 buf = lpbPrinters + used;
4736 left = cbBuf - used;
4737 } else {
4738 buf = NULL;
4739 left = 0;
4742 switch(dwLevel) {
4743 case 1:
4744 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4745 left, &needed);
4746 used += needed;
4747 if(pi) pi += sizeof(PRINTER_INFO_1W);
4748 break;
4749 case 2:
4750 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4751 left, &needed);
4752 used += needed;
4753 if(pi) pi += sizeof(PRINTER_INFO_2W);
4754 break;
4755 case 4:
4756 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4757 left, &needed);
4758 used += needed;
4759 if(pi) pi += sizeof(PRINTER_INFO_4W);
4760 break;
4761 case 5:
4762 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4763 left, &needed);
4764 used += needed;
4765 if(pi) pi += sizeof(PRINTER_INFO_5W);
4766 break;
4767 default:
4768 ERR("Shouldn't be here!\n");
4769 RegCloseKey(hkeyPrinter);
4770 RegCloseKey(hkeyPrinters);
4771 return FALSE;
4773 RegCloseKey(hkeyPrinter);
4775 RegCloseKey(hkeyPrinters);
4777 if(lpdwNeeded)
4778 *lpdwNeeded = used;
4780 if(used > cbBuf) {
4781 if(lpbPrinters)
4782 memset(lpbPrinters, 0, cbBuf);
4783 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4784 return FALSE;
4786 if(lpdwReturned)
4787 *lpdwReturned = number;
4788 SetLastError(ERROR_SUCCESS);
4789 return TRUE;
4793 /******************************************************************
4794 * EnumPrintersW [WINSPOOL.@]
4796 * Enumerates the available printers, print servers and print
4797 * providers, depending on the specified flags, name and level.
4799 * RETURNS:
4801 * If level is set to 1:
4802 * Returns an array of PRINTER_INFO_1 data structures in the
4803 * lpbPrinters buffer.
4805 * If level is set to 2:
4806 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4807 * Returns an array of PRINTER_INFO_2 data structures in the
4808 * lpbPrinters buffer. Note that according to MSDN also an
4809 * OpenPrinter should be performed on every remote printer.
4811 * If level is set to 4 (officially WinNT only):
4812 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4813 * Fast: Only the registry is queried to retrieve printer names,
4814 * no connection to the driver is made.
4815 * Returns an array of PRINTER_INFO_4 data structures in the
4816 * lpbPrinters buffer.
4818 * If level is set to 5 (officially WinNT4/Win9x only):
4819 * Fast: Only the registry is queried to retrieve printer names,
4820 * no connection to the driver is made.
4821 * Returns an array of PRINTER_INFO_5 data structures in the
4822 * lpbPrinters buffer.
4824 * If level set to 3 or 6+:
4825 * returns zero (failure!)
4827 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4828 * for information.
4830 * BUGS:
4831 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4832 * - Only levels 2, 4 and 5 are implemented at the moment.
4833 * - 16-bit printer drivers are not enumerated.
4834 * - Returned amount of bytes used/needed does not match the real Windoze
4835 * implementation (as in this implementation, all strings are part
4836 * of the buffer, whereas Win32 keeps them somewhere else)
4837 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4839 * NOTE:
4840 * - In a regular Wine installation, no registry settings for printers
4841 * exist, which makes this function return an empty list.
4843 BOOL WINAPI EnumPrintersW(
4844 DWORD dwType, /* [in] Types of print objects to enumerate */
4845 LPWSTR lpszName, /* [in] name of objects to enumerate */
4846 DWORD dwLevel, /* [in] type of printer info structure */
4847 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4848 DWORD cbBuf, /* [in] max size of buffer in bytes */
4849 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4850 LPDWORD lpdwReturned /* [out] number of entries returned */
4853 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4854 lpdwNeeded, lpdwReturned);
4857 /******************************************************************
4858 * EnumPrintersA [WINSPOOL.@]
4860 * See EnumPrintersW
4863 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4864 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4866 BOOL ret;
4867 UNICODE_STRING pNameU;
4868 LPWSTR pNameW;
4869 LPBYTE pPrintersW;
4871 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4872 pPrinters, cbBuf, pcbNeeded, pcReturned);
4874 pNameW = asciitounicode(&pNameU, pName);
4876 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4877 MS Office need this */
4878 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4880 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4882 RtlFreeUnicodeString(&pNameU);
4883 if (ret) {
4884 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4886 HeapFree(GetProcessHeap(), 0, pPrintersW);
4887 return ret;
4890 /*****************************************************************************
4891 * WINSPOOL_GetDriverInfoFromReg [internal]
4893 * Enters the information from the registry into the DRIVER_INFO struct
4895 * RETURNS
4896 * zero if the printer driver does not exist in the registry
4897 * (only if Level > 1) otherwise nonzero
4899 static BOOL WINSPOOL_GetDriverInfoFromReg(
4900 HKEY hkeyDrivers,
4901 LPWSTR DriverName,
4902 const printenv_t * env,
4903 DWORD Level,
4904 LPBYTE ptr, /* DRIVER_INFO */
4905 LPBYTE pDriverStrings, /* strings buffer */
4906 DWORD cbBuf, /* size of string buffer */
4907 LPDWORD pcbNeeded) /* space needed for str. */
4909 DWORD size, tmp;
4910 HKEY hkeyDriver;
4911 WCHAR driverdir[MAX_PATH];
4912 DWORD dirlen;
4913 LPBYTE strPtr = pDriverStrings;
4914 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4916 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4917 debugstr_w(DriverName), env,
4918 Level, di, pDriverStrings, cbBuf);
4920 if (di) ZeroMemory(di, di_sizeof[Level]);
4922 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4923 if (*pcbNeeded <= cbBuf)
4924 strcpyW((LPWSTR)strPtr, DriverName);
4926 /* pName for level 1 has a different offset! */
4927 if (Level == 1) {
4928 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4929 return TRUE;
4932 /* .cVersion and .pName for level > 1 */
4933 if (di) {
4934 di->cVersion = env->driverversion;
4935 di->pName = (LPWSTR) strPtr;
4936 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4939 /* Reserve Space for the largest subdir and a Backslash*/
4940 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4941 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4942 /* Should never Fail */
4943 return FALSE;
4945 lstrcatW(driverdir, env->versionsubdir);
4946 lstrcatW(driverdir, backslashW);
4948 /* dirlen must not include the terminating zero */
4949 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4951 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4952 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4953 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4954 return FALSE;
4957 /* pEnvironment */
4958 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4960 *pcbNeeded += size;
4961 if (*pcbNeeded <= cbBuf) {
4962 lstrcpyW((LPWSTR)strPtr, env->envname);
4963 if (di) di->pEnvironment = (LPWSTR)strPtr;
4964 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4967 /* .pDriverPath is the Graphics rendering engine.
4968 The full Path is required to avoid a crash in some apps */
4969 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4970 *pcbNeeded += size;
4971 if (*pcbNeeded <= cbBuf)
4972 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4974 if (di) di->pDriverPath = (LPWSTR)strPtr;
4975 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4978 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4979 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4980 *pcbNeeded += size;
4981 if (*pcbNeeded <= cbBuf)
4982 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4984 if (di) di->pDataFile = (LPWSTR)strPtr;
4985 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4988 /* .pConfigFile is the Driver user Interface */
4989 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4990 *pcbNeeded += size;
4991 if (*pcbNeeded <= cbBuf)
4992 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4994 if (di) di->pConfigFile = (LPWSTR)strPtr;
4995 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4998 if (Level == 2 ) {
4999 RegCloseKey(hkeyDriver);
5000 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5001 return TRUE;
5004 if (Level == 5 ) {
5005 RegCloseKey(hkeyDriver);
5006 FIXME("level 5: incomplete\n");
5007 return TRUE;
5010 /* .pHelpFile */
5011 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
5012 *pcbNeeded += size;
5013 if (*pcbNeeded <= cbBuf)
5014 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
5016 if (di) di->pHelpFile = (LPWSTR)strPtr;
5017 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5020 /* .pDependentFiles */
5021 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
5022 *pcbNeeded += size;
5023 if (*pcbNeeded <= cbBuf)
5024 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
5026 if (di) di->pDependentFiles = (LPWSTR)strPtr;
5027 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5029 else if (GetVersion() & 0x80000000) {
5030 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
5031 size = 2 * sizeof(WCHAR);
5032 *pcbNeeded += size;
5033 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
5035 if (di) di->pDependentFiles = (LPWSTR)strPtr;
5036 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5039 /* .pMonitorName is the optional Language Monitor */
5040 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
5041 *pcbNeeded += size;
5042 if (*pcbNeeded <= cbBuf)
5043 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
5045 if (di) di->pMonitorName = (LPWSTR)strPtr;
5046 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5049 /* .pDefaultDataType */
5050 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
5051 *pcbNeeded += size;
5052 if(*pcbNeeded <= cbBuf)
5053 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
5055 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
5056 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5059 if (Level == 3 ) {
5060 RegCloseKey(hkeyDriver);
5061 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5062 return TRUE;
5065 /* .pszzPreviousNames */
5066 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
5067 *pcbNeeded += size;
5068 if(*pcbNeeded <= cbBuf)
5069 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
5071 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
5072 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5075 if (Level == 4 ) {
5076 RegCloseKey(hkeyDriver);
5077 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5078 return TRUE;
5081 /* support is missing, but not important enough for a FIXME */
5082 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5084 /* .pszMfgName */
5085 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5086 *pcbNeeded += size;
5087 if(*pcbNeeded <= cbBuf)
5088 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5090 if (di) di->pszMfgName = (LPWSTR)strPtr;
5091 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5094 /* .pszOEMUrl */
5095 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5096 *pcbNeeded += size;
5097 if(*pcbNeeded <= cbBuf)
5098 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5100 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5101 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5104 /* .pszHardwareID */
5105 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5106 *pcbNeeded += size;
5107 if(*pcbNeeded <= cbBuf)
5108 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5110 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5111 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5114 /* .pszProvider */
5115 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5116 *pcbNeeded += size;
5117 if(*pcbNeeded <= cbBuf)
5118 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5120 if (di) di->pszProvider = (LPWSTR)strPtr;
5121 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5124 if (Level == 6 ) {
5125 RegCloseKey(hkeyDriver);
5126 return TRUE;
5129 /* support is missing, but not important enough for a FIXME */
5130 TRACE("level 8: incomplete\n");
5132 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5133 RegCloseKey(hkeyDriver);
5134 return TRUE;
5137 /*****************************************************************************
5138 * GetPrinterDriverW [WINSPOOL.@]
5140 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5141 DWORD Level, LPBYTE pDriverInfo,
5142 DWORD cbBuf, LPDWORD pcbNeeded)
5144 LPCWSTR name;
5145 WCHAR DriverName[100];
5146 DWORD ret, type, size, needed = 0;
5147 LPBYTE ptr = NULL;
5148 HKEY hkeyPrinter, hkeyDrivers;
5149 const printenv_t * env;
5151 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5152 Level,pDriverInfo,cbBuf, pcbNeeded);
5154 if (cbBuf > 0)
5155 ZeroMemory(pDriverInfo, cbBuf);
5157 if (!(name = get_opened_printer_name(hPrinter))) {
5158 SetLastError(ERROR_INVALID_HANDLE);
5159 return FALSE;
5162 if (Level < 1 || Level == 7 || Level > 8) {
5163 SetLastError(ERROR_INVALID_LEVEL);
5164 return FALSE;
5167 env = validate_envW(pEnvironment);
5168 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5170 ret = open_printer_reg_key( name, &hkeyPrinter );
5171 if (ret)
5173 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5174 SetLastError( ret );
5175 return FALSE;
5178 size = sizeof(DriverName);
5179 DriverName[0] = 0;
5180 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5181 (LPBYTE)DriverName, &size);
5182 RegCloseKey(hkeyPrinter);
5183 if(ret != ERROR_SUCCESS) {
5184 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5185 return FALSE;
5188 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5189 if(!hkeyDrivers) {
5190 ERR("Can't create Drivers key\n");
5191 return FALSE;
5194 size = di_sizeof[Level];
5195 if ((size <= cbBuf) && pDriverInfo)
5196 ptr = pDriverInfo + size;
5198 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5199 env, Level, pDriverInfo, ptr,
5200 (cbBuf < size) ? 0 : cbBuf - size,
5201 &needed)) {
5202 RegCloseKey(hkeyDrivers);
5203 return FALSE;
5206 RegCloseKey(hkeyDrivers);
5208 if(pcbNeeded) *pcbNeeded = size + needed;
5209 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5210 if(cbBuf >= size + needed) return TRUE;
5211 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5212 return FALSE;
5215 /*****************************************************************************
5216 * GetPrinterDriverA [WINSPOOL.@]
5218 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5219 DWORD Level, LPBYTE pDriverInfo,
5220 DWORD cbBuf, LPDWORD pcbNeeded)
5222 BOOL ret;
5223 UNICODE_STRING pEnvW;
5224 PWSTR pwstrEnvW;
5225 LPBYTE buf = NULL;
5227 if (cbBuf)
5229 ZeroMemory(pDriverInfo, cbBuf);
5230 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5233 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5234 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5235 cbBuf, pcbNeeded);
5236 if (ret)
5237 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5239 HeapFree(GetProcessHeap(), 0, buf);
5241 RtlFreeUnicodeString(&pEnvW);
5242 return ret;
5245 /*****************************************************************************
5246 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5248 * Return the PATH for the Printer-Drivers (UNICODE)
5250 * PARAMS
5251 * pName [I] Servername (NT only) or NULL (local Computer)
5252 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5253 * Level [I] Structure-Level (must be 1)
5254 * pDriverDirectory [O] PTR to Buffer that receives the Result
5255 * cbBuf [I] Size of Buffer at pDriverDirectory
5256 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5257 * required for pDriverDirectory
5259 * RETURNS
5260 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5261 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5262 * if cbBuf is too small
5264 * Native Values returned in pDriverDirectory on Success:
5265 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5266 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5267 *| win9x(Windows 4.0): "%winsysdir%"
5269 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5271 * FIXME
5272 *- Only NULL or "" is supported for pName
5275 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5276 DWORD Level, LPBYTE pDriverDirectory,
5277 DWORD cbBuf, LPDWORD pcbNeeded)
5279 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5280 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5282 if ((backend == NULL) && !load_backend()) return FALSE;
5284 if (Level != 1) {
5285 /* (Level != 1) is ignored in win9x */
5286 SetLastError(ERROR_INVALID_LEVEL);
5287 return FALSE;
5289 if (pcbNeeded == NULL) {
5290 /* (pcbNeeded == NULL) is ignored in win9x */
5291 SetLastError(RPC_X_NULL_REF_POINTER);
5292 return FALSE;
5295 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5296 pDriverDirectory, cbBuf, pcbNeeded);
5301 /*****************************************************************************
5302 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5304 * Return the PATH for the Printer-Drivers (ANSI)
5306 * See GetPrinterDriverDirectoryW.
5308 * NOTES
5309 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5312 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5313 DWORD Level, LPBYTE pDriverDirectory,
5314 DWORD cbBuf, LPDWORD pcbNeeded)
5316 UNICODE_STRING nameW, environmentW;
5317 BOOL ret;
5318 DWORD pcbNeededW;
5319 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5320 WCHAR *driverDirectoryW = NULL;
5322 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5323 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5325 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5327 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5328 else nameW.Buffer = NULL;
5329 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5330 else environmentW.Buffer = NULL;
5332 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5333 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5334 if (ret) {
5335 DWORD needed;
5336 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5337 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5338 if(pcbNeeded)
5339 *pcbNeeded = needed;
5340 ret = needed <= cbBuf;
5341 } else
5342 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5344 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5346 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5347 RtlFreeUnicodeString(&environmentW);
5348 RtlFreeUnicodeString(&nameW);
5350 return ret;
5353 /*****************************************************************************
5354 * AddPrinterDriverA [WINSPOOL.@]
5356 * See AddPrinterDriverW.
5359 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5361 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5362 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5365 /******************************************************************************
5366 * AddPrinterDriverW (WINSPOOL.@)
5368 * Install a Printer Driver
5370 * PARAMS
5371 * pName [I] Servername or NULL (local Computer)
5372 * level [I] Level for the supplied DRIVER_INFO_*W struct
5373 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5375 * RESULTS
5376 * Success: TRUE
5377 * Failure: FALSE
5380 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5382 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5383 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5386 /*****************************************************************************
5387 * AddPrintProcessorA [WINSPOOL.@]
5389 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5390 LPSTR pPrintProcessorName)
5392 UNICODE_STRING NameW, EnvW, PathW, ProcessorW;
5393 BOOL ret;
5395 TRACE("(%s,%s,%s,%s)\n", debugstr_a(pName), debugstr_a(pEnvironment),
5396 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5398 asciitounicode(&NameW, pName);
5399 asciitounicode(&EnvW, pEnvironment);
5400 asciitounicode(&PathW, pPathName);
5401 asciitounicode(&ProcessorW, pPrintProcessorName);
5403 ret = AddPrintProcessorW(NameW.Buffer, EnvW.Buffer, PathW.Buffer, ProcessorW.Buffer);
5405 RtlFreeUnicodeString(&ProcessorW);
5406 RtlFreeUnicodeString(&PathW);
5407 RtlFreeUnicodeString(&EnvW);
5408 RtlFreeUnicodeString(&NameW);
5410 return ret;
5413 /*****************************************************************************
5414 * AddPrintProcessorW [WINSPOOL.@]
5416 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5417 LPWSTR pPrintProcessorName)
5419 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5420 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5421 return TRUE;
5424 /*****************************************************************************
5425 * AddPrintProvidorA [WINSPOOL.@]
5427 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5429 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5430 return FALSE;
5433 /*****************************************************************************
5434 * AddPrintProvidorW [WINSPOOL.@]
5436 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5438 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5439 return FALSE;
5442 /*****************************************************************************
5443 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5445 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5446 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5448 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5449 pDevModeOutput, pDevModeInput);
5450 return 0;
5453 /*****************************************************************************
5454 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5456 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5457 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5459 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5460 pDevModeOutput, pDevModeInput);
5461 return 0;
5464 /*****************************************************************************
5465 * PrinterProperties [WINSPOOL.@]
5467 * Displays a dialog to set the properties of the printer.
5469 * RETURNS
5470 * nonzero on success or zero on failure
5472 * BUGS
5473 * implemented as stub only
5475 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5476 HANDLE hPrinter /* [in] handle to printer object */
5478 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5479 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5480 return FALSE;
5483 /*****************************************************************************
5484 * EnumJobsA [WINSPOOL.@]
5487 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5488 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5489 LPDWORD pcReturned)
5491 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5492 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5494 if(pcbNeeded) *pcbNeeded = 0;
5495 if(pcReturned) *pcReturned = 0;
5496 return FALSE;
5500 /*****************************************************************************
5501 * EnumJobsW [WINSPOOL.@]
5504 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5505 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5506 LPDWORD pcReturned)
5508 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5509 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5511 if(pcbNeeded) *pcbNeeded = 0;
5512 if(pcReturned) *pcReturned = 0;
5513 return FALSE;
5516 /*****************************************************************************
5517 * WINSPOOL_EnumPrinterDrivers [internal]
5519 * Delivers information about all printer drivers installed on the
5520 * localhost or a given server
5522 * RETURNS
5523 * nonzero on success or zero on failure. If the buffer for the returned
5524 * information is too small the function will return an error
5526 * BUGS
5527 * - only implemented for localhost, foreign hosts will return an error
5529 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5530 DWORD Level, LPBYTE pDriverInfo,
5531 DWORD driver_index,
5532 DWORD cbBuf, LPDWORD pcbNeeded,
5533 LPDWORD pcFound, DWORD data_offset)
5535 { HKEY hkeyDrivers;
5536 DWORD i, size = 0;
5537 const printenv_t * env;
5539 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5540 debugstr_w(pName), debugstr_w(pEnvironment),
5541 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5543 env = validate_envW(pEnvironment);
5544 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5546 *pcFound = 0;
5548 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5549 if(!hkeyDrivers) {
5550 ERR("Can't open Drivers key\n");
5551 return FALSE;
5554 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5555 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5556 RegCloseKey(hkeyDrivers);
5557 ERR("Can't query Drivers key\n");
5558 return FALSE;
5560 TRACE("Found %d Drivers\n", *pcFound);
5562 /* get size of single struct
5563 * unicode and ascii structure have the same size
5565 size = di_sizeof[Level];
5567 if (data_offset == 0)
5568 data_offset = size * (*pcFound);
5569 *pcbNeeded = data_offset;
5571 for( i = 0; i < *pcFound; i++) {
5572 WCHAR DriverNameW[255];
5573 PBYTE table_ptr = NULL;
5574 PBYTE data_ptr = NULL;
5575 DWORD needed = 0;
5577 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, ARRAY_SIZE(DriverNameW)) != ERROR_SUCCESS) {
5578 ERR("Can't enum key number %d\n", i);
5579 RegCloseKey(hkeyDrivers);
5580 return FALSE;
5583 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5584 table_ptr = pDriverInfo + (driver_index + i) * size;
5585 if (pDriverInfo && *pcbNeeded <= cbBuf)
5586 data_ptr = pDriverInfo + *pcbNeeded;
5588 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5589 env, Level, table_ptr, data_ptr,
5590 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5591 &needed)) {
5592 RegCloseKey(hkeyDrivers);
5593 return FALSE;
5596 *pcbNeeded += needed;
5599 RegCloseKey(hkeyDrivers);
5601 if(cbBuf < *pcbNeeded){
5602 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5603 return FALSE;
5606 return TRUE;
5609 /*****************************************************************************
5610 * EnumPrinterDriversW [WINSPOOL.@]
5612 * see function EnumPrinterDrivers for RETURNS, BUGS
5614 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5615 LPBYTE pDriverInfo, DWORD cbBuf,
5616 LPDWORD pcbNeeded, LPDWORD pcReturned)
5618 static const WCHAR allW[] = {'a','l','l',0};
5619 BOOL ret;
5620 DWORD found;
5622 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5624 SetLastError(RPC_X_NULL_REF_POINTER);
5625 return FALSE;
5628 /* check for local drivers */
5629 if((pName) && (pName[0])) {
5630 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5631 SetLastError(ERROR_ACCESS_DENIED);
5632 return FALSE;
5635 /* check input parameter */
5636 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5637 SetLastError(ERROR_INVALID_LEVEL);
5638 return FALSE;
5641 if(pDriverInfo && cbBuf > 0)
5642 memset( pDriverInfo, 0, cbBuf);
5644 /* Exception: pull all printers */
5645 if (pEnvironment && !strcmpW(pEnvironment, allW))
5647 DWORD i, needed, bufsize = cbBuf;
5648 DWORD total_found = 0;
5649 DWORD data_offset;
5651 /* Precompute the overall total; we need this to know
5652 where pointers end and data begins (i.e. data_offset) */
5653 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
5655 needed = found = 0;
5656 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5657 NULL, 0, 0, &needed, &found, 0);
5658 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5659 total_found += found;
5662 data_offset = di_sizeof[Level] * total_found;
5664 *pcReturned = 0;
5665 *pcbNeeded = 0;
5666 total_found = 0;
5667 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
5669 needed = found = 0;
5670 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5671 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5672 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5673 else if (ret)
5674 *pcReturned += found;
5675 *pcbNeeded = needed;
5676 data_offset = needed;
5677 total_found += found;
5679 return ret;
5682 /* Normal behavior */
5683 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5684 0, cbBuf, pcbNeeded, &found, 0);
5685 if (ret)
5686 *pcReturned = found;
5688 return ret;
5691 /*****************************************************************************
5692 * EnumPrinterDriversA [WINSPOOL.@]
5694 * see function EnumPrinterDrivers for RETURNS, BUGS
5696 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5697 LPBYTE pDriverInfo, DWORD cbBuf,
5698 LPDWORD pcbNeeded, LPDWORD pcReturned)
5700 BOOL ret;
5701 UNICODE_STRING pNameW, pEnvironmentW;
5702 PWSTR pwstrNameW, pwstrEnvironmentW;
5703 LPBYTE buf = NULL;
5705 if (cbBuf)
5706 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5708 pwstrNameW = asciitounicode(&pNameW, pName);
5709 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5711 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5712 buf, cbBuf, pcbNeeded, pcReturned);
5713 if (ret)
5714 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5716 HeapFree(GetProcessHeap(), 0, buf);
5718 RtlFreeUnicodeString(&pNameW);
5719 RtlFreeUnicodeString(&pEnvironmentW);
5721 return ret;
5724 /******************************************************************************
5725 * EnumPortsA (WINSPOOL.@)
5727 * See EnumPortsW.
5730 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5731 LPDWORD pcbNeeded, LPDWORD pcReturned)
5733 BOOL res;
5734 LPBYTE bufferW = NULL;
5735 LPWSTR nameW = NULL;
5736 DWORD needed = 0;
5737 DWORD numentries = 0;
5738 INT len;
5740 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5741 cbBuf, pcbNeeded, pcReturned);
5743 /* convert servername to unicode */
5744 if (pName) {
5745 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5746 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5747 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5749 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5750 needed = cbBuf * sizeof(WCHAR);
5751 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5752 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5754 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5755 if (pcbNeeded) needed = *pcbNeeded;
5756 /* HeapReAlloc return NULL, when bufferW was NULL */
5757 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5758 HeapAlloc(GetProcessHeap(), 0, needed);
5760 /* Try again with the large Buffer */
5761 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5763 needed = pcbNeeded ? *pcbNeeded : 0;
5764 numentries = pcReturned ? *pcReturned : 0;
5767 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5768 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5770 if (res) {
5771 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5772 DWORD entrysize = 0;
5773 DWORD index;
5774 LPSTR ptr;
5775 LPPORT_INFO_2W pi2w;
5776 LPPORT_INFO_2A pi2a;
5778 needed = 0;
5779 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5781 /* First pass: calculate the size for all Entries */
5782 pi2w = (LPPORT_INFO_2W) bufferW;
5783 pi2a = (LPPORT_INFO_2A) pPorts;
5784 index = 0;
5785 while (index < numentries) {
5786 index++;
5787 needed += entrysize; /* PORT_INFO_?A */
5788 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5790 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5791 NULL, 0, NULL, NULL);
5792 if (Level > 1) {
5793 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5794 NULL, 0, NULL, NULL);
5795 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5796 NULL, 0, NULL, NULL);
5798 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5799 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5800 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5803 /* check for errors and quit on failure */
5804 if (cbBuf < needed) {
5805 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5806 res = FALSE;
5807 goto cleanup;
5809 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5810 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5811 cbBuf -= len ; /* free Bytes in the user-Buffer */
5812 pi2w = (LPPORT_INFO_2W) bufferW;
5813 pi2a = (LPPORT_INFO_2A) pPorts;
5814 index = 0;
5815 /* Second Pass: Fill the User Buffer (if we have one) */
5816 while ((index < numentries) && pPorts) {
5817 index++;
5818 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5819 pi2a->pPortName = ptr;
5820 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5821 ptr, cbBuf , NULL, NULL);
5822 ptr += len;
5823 cbBuf -= len;
5824 if (Level > 1) {
5825 pi2a->pMonitorName = ptr;
5826 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5827 ptr, cbBuf, NULL, NULL);
5828 ptr += len;
5829 cbBuf -= len;
5831 pi2a->pDescription = ptr;
5832 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5833 ptr, cbBuf, NULL, NULL);
5834 ptr += len;
5835 cbBuf -= len;
5837 pi2a->fPortType = pi2w->fPortType;
5838 pi2a->Reserved = 0; /* documented: "must be zero" */
5841 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5842 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5843 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5847 cleanup:
5848 if (pcbNeeded) *pcbNeeded = needed;
5849 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5851 HeapFree(GetProcessHeap(), 0, nameW);
5852 HeapFree(GetProcessHeap(), 0, bufferW);
5854 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5855 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5857 return (res);
5861 /******************************************************************************
5862 * EnumPortsW (WINSPOOL.@)
5864 * Enumerate available Ports
5866 * PARAMS
5867 * pName [I] Servername or NULL (local Computer)
5868 * Level [I] Structure-Level (1 or 2)
5869 * pPorts [O] PTR to Buffer that receives the Result
5870 * cbBuf [I] Size of Buffer at pPorts
5871 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5872 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5874 * RETURNS
5875 * Success: TRUE
5876 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5879 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5882 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5883 cbBuf, pcbNeeded, pcReturned);
5885 if ((backend == NULL) && !load_backend()) return FALSE;
5887 /* Level is not checked in win9x */
5888 if (!Level || (Level > 2)) {
5889 WARN("level (%d) is ignored in win9x\n", Level);
5890 SetLastError(ERROR_INVALID_LEVEL);
5891 return FALSE;
5893 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5894 SetLastError(RPC_X_NULL_REF_POINTER);
5895 return FALSE;
5898 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5901 /******************************************************************************
5902 * GetDefaultPrinterW (WINSPOOL.@)
5904 * FIXME
5905 * This function must read the value from data 'device' of key
5906 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5908 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5910 BOOL retval = TRUE;
5911 DWORD insize, len;
5912 WCHAR *buffer, *ptr;
5914 if (!namesize)
5916 SetLastError(ERROR_INVALID_PARAMETER);
5917 return FALSE;
5920 /* make the buffer big enough for the stuff from the profile/registry,
5921 * the content must fit into the local buffer to compute the correct
5922 * size even if the extern buffer is too small or not given.
5923 * (20 for ,driver,port) */
5924 insize = *namesize;
5925 len = max(100, (insize + 20));
5926 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5928 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5930 SetLastError (ERROR_FILE_NOT_FOUND);
5931 retval = FALSE;
5932 goto end;
5934 TRACE("%s\n", debugstr_w(buffer));
5936 if ((ptr = strchrW(buffer, ',')) == NULL)
5938 SetLastError(ERROR_INVALID_NAME);
5939 retval = FALSE;
5940 goto end;
5943 *ptr = 0;
5944 *namesize = strlenW(buffer) + 1;
5945 if(!name || (*namesize > insize))
5947 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5948 retval = FALSE;
5949 goto end;
5951 strcpyW(name, buffer);
5953 end:
5954 HeapFree( GetProcessHeap(), 0, buffer);
5955 return retval;
5959 /******************************************************************************
5960 * GetDefaultPrinterA (WINSPOOL.@)
5962 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5964 BOOL retval = TRUE;
5965 DWORD insize = 0;
5966 WCHAR *bufferW = NULL;
5968 if (!namesize)
5970 SetLastError(ERROR_INVALID_PARAMETER);
5971 return FALSE;
5974 if(name && *namesize) {
5975 insize = *namesize;
5976 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5979 if(!GetDefaultPrinterW( bufferW, namesize)) {
5980 retval = FALSE;
5981 goto end;
5984 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5985 NULL, NULL);
5986 if (!*namesize)
5988 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5989 retval = FALSE;
5991 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5993 end:
5994 HeapFree( GetProcessHeap(), 0, bufferW);
5995 return retval;
5999 /******************************************************************************
6000 * SetDefaultPrinterW (WINSPOOL.204)
6002 * Set the Name of the Default Printer
6004 * PARAMS
6005 * pszPrinter [I] Name of the Printer or NULL
6007 * RETURNS
6008 * Success: True
6009 * Failure: FALSE
6011 * NOTES
6012 * When the Parameter is NULL or points to an Empty String and
6013 * a Default Printer was already present, then this Function changes nothing.
6014 * Without a Default Printer and NULL (or an Empty String) as Parameter,
6015 * the First enumerated local Printer is used.
6018 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
6020 WCHAR default_printer[MAX_PATH];
6021 LPWSTR buffer = NULL;
6022 HKEY hreg;
6023 DWORD size;
6024 DWORD namelen;
6025 LONG lres;
6027 TRACE("(%s)\n", debugstr_w(pszPrinter));
6028 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
6030 default_printer[0] = '\0';
6031 size = ARRAY_SIZE(default_printer);
6033 /* if we have a default Printer, do nothing. */
6034 if (GetDefaultPrinterW(default_printer, &size))
6035 return TRUE;
6037 pszPrinter = NULL;
6038 /* we have no default Printer: search local Printers and use the first */
6039 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
6041 default_printer[0] = '\0';
6042 size = ARRAY_SIZE(default_printer);
6043 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
6045 pszPrinter = default_printer;
6046 TRACE("using %s\n", debugstr_w(pszPrinter));
6048 RegCloseKey(hreg);
6051 if (pszPrinter == NULL) {
6052 TRACE("no local printer found\n");
6053 SetLastError(ERROR_FILE_NOT_FOUND);
6054 return FALSE;
6058 /* "pszPrinter" is never empty or NULL here. */
6059 namelen = lstrlenW(pszPrinter);
6060 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
6061 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
6062 if (!buffer ||
6063 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
6064 HeapFree(GetProcessHeap(), 0, buffer);
6065 SetLastError(ERROR_FILE_NOT_FOUND);
6066 return FALSE;
6069 /* read the devices entry for the printer (driver,port) to build the string for the
6070 default device entry (printer,driver,port) */
6071 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
6072 buffer[namelen] = ',';
6073 namelen++; /* move index to the start of the driver */
6075 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
6076 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
6077 if (!lres) {
6078 HKEY hdev;
6080 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev))
6082 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (BYTE *)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6083 RegCloseKey(hdev);
6086 else
6088 if (lres != ERROR_FILE_NOT_FOUND)
6089 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6091 SetLastError(ERROR_INVALID_PRINTER_NAME);
6094 RegCloseKey(hreg);
6095 HeapFree(GetProcessHeap(), 0, buffer);
6096 return (lres == ERROR_SUCCESS);
6099 /******************************************************************************
6100 * SetDefaultPrinterA (WINSPOOL.202)
6102 * See SetDefaultPrinterW.
6105 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6107 LPWSTR bufferW = NULL;
6108 BOOL res;
6110 TRACE("(%s)\n", debugstr_a(pszPrinter));
6111 if(pszPrinter) {
6112 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6113 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6114 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6116 res = SetDefaultPrinterW(bufferW);
6117 HeapFree(GetProcessHeap(), 0, bufferW);
6118 return res;
6121 /******************************************************************************
6122 * SetPrinterDataExA (WINSPOOL.@)
6124 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6125 LPCSTR pValueName, DWORD Type,
6126 LPBYTE pData, DWORD cbData)
6128 HKEY hkeyPrinter, hkeySubkey;
6129 DWORD ret;
6131 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6132 debugstr_a(pValueName), Type, pData, cbData);
6134 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6135 != ERROR_SUCCESS)
6136 return ret;
6138 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6139 != ERROR_SUCCESS) {
6140 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6141 RegCloseKey(hkeyPrinter);
6142 return ret;
6144 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6145 RegCloseKey(hkeySubkey);
6146 RegCloseKey(hkeyPrinter);
6147 return ret;
6150 /******************************************************************************
6151 * SetPrinterDataExW (WINSPOOL.@)
6153 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6154 LPCWSTR pValueName, DWORD Type,
6155 LPBYTE pData, DWORD cbData)
6157 HKEY hkeyPrinter, hkeySubkey;
6158 DWORD ret;
6160 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6161 debugstr_w(pValueName), Type, pData, cbData);
6163 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6164 != ERROR_SUCCESS)
6165 return ret;
6167 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6168 != ERROR_SUCCESS) {
6169 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6170 RegCloseKey(hkeyPrinter);
6171 return ret;
6173 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6174 RegCloseKey(hkeySubkey);
6175 RegCloseKey(hkeyPrinter);
6176 return ret;
6179 /******************************************************************************
6180 * SetPrinterDataA (WINSPOOL.@)
6182 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6183 LPBYTE pData, DWORD cbData)
6185 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6186 pData, cbData);
6189 /******************************************************************************
6190 * SetPrinterDataW (WINSPOOL.@)
6192 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6193 LPBYTE pData, DWORD cbData)
6195 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6196 pData, cbData);
6199 /******************************************************************************
6200 * GetPrinterDataExA (WINSPOOL.@)
6202 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6203 LPCSTR pValueName, LPDWORD pType,
6204 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6206 opened_printer_t *printer;
6207 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6208 DWORD ret;
6210 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6211 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6213 printer = get_opened_printer(hPrinter);
6214 if(!printer) return ERROR_INVALID_HANDLE;
6216 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6217 if (ret) return ret;
6219 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6221 if (printer->name) {
6223 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6224 if (ret) {
6225 RegCloseKey(hkeyPrinters);
6226 return ret;
6228 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6229 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6230 RegCloseKey(hkeyPrinter);
6231 RegCloseKey(hkeyPrinters);
6232 return ret;
6235 *pcbNeeded = nSize;
6236 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6237 0, pType, pData, pcbNeeded);
6239 if (!ret && !pData) ret = ERROR_MORE_DATA;
6241 RegCloseKey(hkeySubkey);
6242 RegCloseKey(hkeyPrinter);
6243 RegCloseKey(hkeyPrinters);
6245 TRACE("--> %d\n", ret);
6246 return ret;
6249 /******************************************************************************
6250 * GetPrinterDataExW (WINSPOOL.@)
6252 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6253 LPCWSTR pValueName, LPDWORD pType,
6254 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6256 opened_printer_t *printer;
6257 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6258 DWORD ret;
6260 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6261 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6263 printer = get_opened_printer(hPrinter);
6264 if(!printer) return ERROR_INVALID_HANDLE;
6266 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6267 if (ret) return ret;
6269 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6271 if (printer->name) {
6273 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6274 if (ret) {
6275 RegCloseKey(hkeyPrinters);
6276 return ret;
6278 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6279 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6280 RegCloseKey(hkeyPrinter);
6281 RegCloseKey(hkeyPrinters);
6282 return ret;
6285 *pcbNeeded = nSize;
6286 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6287 0, pType, pData, pcbNeeded);
6289 if (!ret && !pData) ret = ERROR_MORE_DATA;
6291 RegCloseKey(hkeySubkey);
6292 RegCloseKey(hkeyPrinter);
6293 RegCloseKey(hkeyPrinters);
6295 TRACE("--> %d\n", ret);
6296 return ret;
6299 /******************************************************************************
6300 * GetPrinterDataA (WINSPOOL.@)
6302 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6303 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6305 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6306 pData, nSize, pcbNeeded);
6309 /******************************************************************************
6310 * GetPrinterDataW (WINSPOOL.@)
6312 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6313 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6315 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6316 pData, nSize, pcbNeeded);
6319 /*******************************************************************************
6320 * EnumPrinterDataExW [WINSPOOL.@]
6322 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6323 LPBYTE pEnumValues, DWORD cbEnumValues,
6324 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6326 HKEY hkPrinter, hkSubKey;
6327 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6328 cbValueNameLen, cbMaxValueLen, cbValueLen,
6329 cbBufSize, dwType;
6330 LPWSTR lpValueName;
6331 HANDLE hHeap;
6332 PBYTE lpValue;
6333 PPRINTER_ENUM_VALUESW ppev;
6335 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6337 if (pKeyName == NULL || *pKeyName == 0)
6338 return ERROR_INVALID_PARAMETER;
6340 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6341 if (ret != ERROR_SUCCESS)
6343 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6344 hPrinter, ret);
6345 return ret;
6348 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6349 if (ret != ERROR_SUCCESS)
6351 r = RegCloseKey (hkPrinter);
6352 if (r != ERROR_SUCCESS)
6353 WARN ("RegCloseKey returned %i\n", r);
6354 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6355 debugstr_w (pKeyName), ret);
6356 return ret;
6359 ret = RegCloseKey (hkPrinter);
6360 if (ret != ERROR_SUCCESS)
6362 ERR ("RegCloseKey returned %i\n", ret);
6363 r = RegCloseKey (hkSubKey);
6364 if (r != ERROR_SUCCESS)
6365 WARN ("RegCloseKey returned %i\n", r);
6366 return ret;
6369 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6370 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6371 if (ret != ERROR_SUCCESS)
6373 r = RegCloseKey (hkSubKey);
6374 if (r != ERROR_SUCCESS)
6375 WARN ("RegCloseKey returned %i\n", r);
6376 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6377 return ret;
6380 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6381 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6383 if (cValues == 0) /* empty key */
6385 r = RegCloseKey (hkSubKey);
6386 if (r != ERROR_SUCCESS)
6387 WARN ("RegCloseKey returned %i\n", r);
6388 *pcbEnumValues = *pnEnumValues = 0;
6389 return ERROR_SUCCESS;
6392 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6394 hHeap = GetProcessHeap ();
6395 if (hHeap == NULL)
6397 ERR ("GetProcessHeap failed\n");
6398 r = RegCloseKey (hkSubKey);
6399 if (r != ERROR_SUCCESS)
6400 WARN ("RegCloseKey returned %i\n", r);
6401 return ERROR_OUTOFMEMORY;
6404 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6405 if (lpValueName == NULL)
6407 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6408 r = RegCloseKey (hkSubKey);
6409 if (r != ERROR_SUCCESS)
6410 WARN ("RegCloseKey returned %i\n", r);
6411 return ERROR_OUTOFMEMORY;
6414 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6415 if (lpValue == NULL)
6417 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6418 if (HeapFree (hHeap, 0, lpValueName) == 0)
6419 WARN ("HeapFree failed with code %i\n", GetLastError ());
6420 r = RegCloseKey (hkSubKey);
6421 if (r != ERROR_SUCCESS)
6422 WARN ("RegCloseKey returned %i\n", r);
6423 return ERROR_OUTOFMEMORY;
6426 TRACE ("pass 1: calculating buffer required for all names and values\n");
6428 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6430 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6432 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6434 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6435 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6436 NULL, NULL, lpValue, &cbValueLen);
6437 if (ret != ERROR_SUCCESS)
6439 if (HeapFree (hHeap, 0, lpValue) == 0)
6440 WARN ("HeapFree failed with code %i\n", GetLastError ());
6441 if (HeapFree (hHeap, 0, lpValueName) == 0)
6442 WARN ("HeapFree failed with code %i\n", GetLastError ());
6443 r = RegCloseKey (hkSubKey);
6444 if (r != ERROR_SUCCESS)
6445 WARN ("RegCloseKey returned %i\n", r);
6446 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6447 return ret;
6450 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6451 debugstr_w (lpValueName), dwIndex,
6452 cbValueNameLen + 1, cbValueLen);
6454 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6455 cbBufSize += cbValueLen;
6458 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6460 *pcbEnumValues = cbBufSize;
6461 *pnEnumValues = cValues;
6463 if (cbEnumValues < cbBufSize) /* buffer too small */
6465 if (HeapFree (hHeap, 0, lpValue) == 0)
6466 WARN ("HeapFree failed with code %i\n", GetLastError ());
6467 if (HeapFree (hHeap, 0, lpValueName) == 0)
6468 WARN ("HeapFree failed with code %i\n", GetLastError ());
6469 r = RegCloseKey (hkSubKey);
6470 if (r != ERROR_SUCCESS)
6471 WARN ("RegCloseKey returned %i\n", r);
6472 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6473 return ERROR_MORE_DATA;
6476 TRACE ("pass 2: copying all names and values to buffer\n");
6478 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6479 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6481 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6483 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6484 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6485 NULL, &dwType, lpValue, &cbValueLen);
6486 if (ret != ERROR_SUCCESS)
6488 if (HeapFree (hHeap, 0, lpValue) == 0)
6489 WARN ("HeapFree failed with code %i\n", GetLastError ());
6490 if (HeapFree (hHeap, 0, lpValueName) == 0)
6491 WARN ("HeapFree failed with code %i\n", GetLastError ());
6492 r = RegCloseKey (hkSubKey);
6493 if (r != ERROR_SUCCESS)
6494 WARN ("RegCloseKey returned %i\n", r);
6495 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6496 return ret;
6499 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6500 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6501 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6502 pEnumValues += cbValueNameLen;
6504 /* return # of *bytes* (including trailing \0), not # of chars */
6505 ppev[dwIndex].cbValueName = cbValueNameLen;
6507 ppev[dwIndex].dwType = dwType;
6509 memcpy (pEnumValues, lpValue, cbValueLen);
6510 ppev[dwIndex].pData = pEnumValues;
6511 pEnumValues += cbValueLen;
6513 ppev[dwIndex].cbData = cbValueLen;
6515 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6516 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6519 if (HeapFree (hHeap, 0, lpValue) == 0)
6521 ret = GetLastError ();
6522 ERR ("HeapFree failed with code %i\n", ret);
6523 if (HeapFree (hHeap, 0, lpValueName) == 0)
6524 WARN ("HeapFree failed with code %i\n", GetLastError ());
6525 r = RegCloseKey (hkSubKey);
6526 if (r != ERROR_SUCCESS)
6527 WARN ("RegCloseKey returned %i\n", r);
6528 return ret;
6531 if (HeapFree (hHeap, 0, lpValueName) == 0)
6533 ret = GetLastError ();
6534 ERR ("HeapFree failed with code %i\n", ret);
6535 r = RegCloseKey (hkSubKey);
6536 if (r != ERROR_SUCCESS)
6537 WARN ("RegCloseKey returned %i\n", r);
6538 return ret;
6541 ret = RegCloseKey (hkSubKey);
6542 if (ret != ERROR_SUCCESS)
6544 ERR ("RegCloseKey returned %i\n", ret);
6545 return ret;
6548 return ERROR_SUCCESS;
6551 /*******************************************************************************
6552 * EnumPrinterDataExA [WINSPOOL.@]
6554 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6555 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6556 * what Windows 2000 SP1 does.
6559 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6560 LPBYTE pEnumValues, DWORD cbEnumValues,
6561 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6563 INT len;
6564 LPWSTR pKeyNameW;
6565 DWORD ret, dwIndex, dwBufSize;
6566 HANDLE hHeap;
6567 LPSTR pBuffer;
6569 TRACE ("%p %s\n", hPrinter, pKeyName);
6571 if (pKeyName == NULL || *pKeyName == 0)
6572 return ERROR_INVALID_PARAMETER;
6574 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6575 if (len == 0)
6577 ret = GetLastError ();
6578 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6579 return ret;
6582 hHeap = GetProcessHeap ();
6583 if (hHeap == NULL)
6585 ERR ("GetProcessHeap failed\n");
6586 return ERROR_OUTOFMEMORY;
6589 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6590 if (pKeyNameW == NULL)
6592 ERR ("Failed to allocate %i bytes from process heap\n",
6593 (LONG)(len * sizeof (WCHAR)));
6594 return ERROR_OUTOFMEMORY;
6597 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6599 ret = GetLastError ();
6600 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6601 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6602 WARN ("HeapFree failed with code %i\n", GetLastError ());
6603 return ret;
6606 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6607 pcbEnumValues, pnEnumValues);
6608 if (ret != ERROR_SUCCESS)
6610 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6611 WARN ("HeapFree failed with code %i\n", GetLastError ());
6612 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6613 return ret;
6616 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6618 ret = GetLastError ();
6619 ERR ("HeapFree failed with code %i\n", ret);
6620 return ret;
6623 if (*pnEnumValues == 0) /* empty key */
6624 return ERROR_SUCCESS;
6626 dwBufSize = 0;
6627 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6629 PPRINTER_ENUM_VALUESW ppev =
6630 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6632 if (dwBufSize < ppev->cbValueName)
6633 dwBufSize = ppev->cbValueName;
6635 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6636 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6637 dwBufSize = ppev->cbData;
6640 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6642 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6643 if (pBuffer == NULL)
6645 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6646 return ERROR_OUTOFMEMORY;
6649 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6651 PPRINTER_ENUM_VALUESW ppev =
6652 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6654 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6655 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6656 NULL);
6657 if (len == 0)
6659 ret = GetLastError ();
6660 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6661 if (HeapFree (hHeap, 0, pBuffer) == 0)
6662 WARN ("HeapFree failed with code %i\n", GetLastError ());
6663 return ret;
6666 memcpy (ppev->pValueName, pBuffer, len);
6668 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6670 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6671 ppev->dwType != REG_MULTI_SZ)
6672 continue;
6674 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6675 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6676 if (len == 0)
6678 ret = GetLastError ();
6679 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6680 if (HeapFree (hHeap, 0, pBuffer) == 0)
6681 WARN ("HeapFree failed with code %i\n", GetLastError ());
6682 return ret;
6685 memcpy (ppev->pData, pBuffer, len);
6687 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6688 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6691 if (HeapFree (hHeap, 0, pBuffer) == 0)
6693 ret = GetLastError ();
6694 ERR ("HeapFree failed with code %i\n", ret);
6695 return ret;
6698 return ERROR_SUCCESS;
6701 /******************************************************************************
6702 * AbortPrinter (WINSPOOL.@)
6704 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6706 FIXME("(%p), stub!\n", hPrinter);
6707 return TRUE;
6710 /******************************************************************************
6711 * AddPortA (WINSPOOL.@)
6713 * See AddPortW.
6716 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6718 LPWSTR nameW = NULL;
6719 LPWSTR monitorW = NULL;
6720 DWORD len;
6721 BOOL res;
6723 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6725 if (pName) {
6726 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6727 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6728 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6731 if (pMonitorName) {
6732 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6733 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6734 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6736 res = AddPortW(nameW, hWnd, monitorW);
6737 HeapFree(GetProcessHeap(), 0, nameW);
6738 HeapFree(GetProcessHeap(), 0, monitorW);
6739 return res;
6742 /******************************************************************************
6743 * AddPortW (WINSPOOL.@)
6745 * Add a Port for a specific Monitor
6747 * PARAMS
6748 * pName [I] Servername or NULL (local Computer)
6749 * hWnd [I] Handle to parent Window for the Dialog-Box
6750 * pMonitorName [I] Name of the Monitor that manage the Port
6752 * RETURNS
6753 * Success: TRUE
6754 * Failure: FALSE
6757 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6759 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6761 if ((backend == NULL) && !load_backend()) return FALSE;
6763 if (!pMonitorName) {
6764 SetLastError(RPC_X_NULL_REF_POINTER);
6765 return FALSE;
6768 return backend->fpAddPort(pName, hWnd, pMonitorName);
6771 /******************************************************************************
6772 * AddPortExA (WINSPOOL.@)
6774 * See AddPortExW.
6777 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6779 PORT_INFO_2W pi2W;
6780 PORT_INFO_2A * pi2A;
6781 LPWSTR nameW = NULL;
6782 LPWSTR monitorW = NULL;
6783 DWORD len;
6784 BOOL res;
6786 pi2A = (PORT_INFO_2A *) pBuffer;
6788 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6789 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6791 if ((level < 1) || (level > 2)) {
6792 SetLastError(ERROR_INVALID_LEVEL);
6793 return FALSE;
6796 if (!pi2A) {
6797 SetLastError(ERROR_INVALID_PARAMETER);
6798 return FALSE;
6801 if (pName) {
6802 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6803 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6804 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6807 if (pMonitorName) {
6808 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6809 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6810 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6813 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6815 if (pi2A->pPortName) {
6816 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6817 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6818 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6821 if (level > 1) {
6822 if (pi2A->pMonitorName) {
6823 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6824 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6825 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6828 if (pi2A->pDescription) {
6829 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6830 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6831 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6833 pi2W.fPortType = pi2A->fPortType;
6834 pi2W.Reserved = pi2A->Reserved;
6837 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6839 HeapFree(GetProcessHeap(), 0, nameW);
6840 HeapFree(GetProcessHeap(), 0, monitorW);
6841 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6842 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6843 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6844 return res;
6848 /******************************************************************************
6849 * AddPortExW (WINSPOOL.@)
6851 * Add a Port for a specific Monitor, without presenting a user interface
6853 * PARAMS
6854 * pName [I] Servername or NULL (local Computer)
6855 * level [I] Structure-Level (1 or 2) for pBuffer
6856 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6857 * pMonitorName [I] Name of the Monitor that manage the Port
6859 * RETURNS
6860 * Success: TRUE
6861 * Failure: FALSE
6864 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6866 PORT_INFO_2W * pi2;
6868 pi2 = (PORT_INFO_2W *) pBuffer;
6870 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6871 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6872 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6873 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6875 if ((backend == NULL) && !load_backend()) return FALSE;
6877 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6878 SetLastError(ERROR_INVALID_PARAMETER);
6879 return FALSE;
6882 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6885 /******************************************************************************
6886 * AddPrinterConnectionA (WINSPOOL.@)
6888 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6890 FIXME("%s\n", debugstr_a(pName));
6891 return FALSE;
6894 /******************************************************************************
6895 * AddPrinterConnectionW (WINSPOOL.@)
6897 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6899 FIXME("%s\n", debugstr_w(pName));
6900 return FALSE;
6903 /******************************************************************************
6904 * AddPrinterDriverExW (WINSPOOL.@)
6906 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6908 * PARAMS
6909 * pName [I] Servername or NULL (local Computer)
6910 * level [I] Level for the supplied DRIVER_INFO_*W struct
6911 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6912 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6914 * RESULTS
6915 * Success: TRUE
6916 * Failure: FALSE
6919 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6921 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6923 if ((backend == NULL) && !load_backend()) return FALSE;
6925 if (level < 2 || level == 5 || level == 7 || level > 8) {
6926 SetLastError(ERROR_INVALID_LEVEL);
6927 return FALSE;
6930 if (!pDriverInfo) {
6931 SetLastError(ERROR_INVALID_PARAMETER);
6932 return FALSE;
6935 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6938 /******************************************************************************
6939 * AddPrinterDriverExA (WINSPOOL.@)
6941 * See AddPrinterDriverExW.
6944 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6946 DRIVER_INFO_8A *diA;
6947 DRIVER_INFO_8W diW;
6948 LPWSTR nameW = NULL;
6949 DWORD lenA;
6950 DWORD len;
6951 BOOL res = FALSE;
6953 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6955 diA = (DRIVER_INFO_8A *) pDriverInfo;
6956 ZeroMemory(&diW, sizeof(diW));
6958 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6959 SetLastError(ERROR_INVALID_LEVEL);
6960 return FALSE;
6963 if (diA == NULL) {
6964 SetLastError(ERROR_INVALID_PARAMETER);
6965 return FALSE;
6968 /* convert servername to unicode */
6969 if (pName) {
6970 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6971 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6972 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6975 /* common fields */
6976 diW.cVersion = diA->cVersion;
6978 if (diA->pName) {
6979 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6980 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6981 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6984 if (diA->pEnvironment) {
6985 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6986 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6987 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6990 if (diA->pDriverPath) {
6991 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6992 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6993 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6996 if (diA->pDataFile) {
6997 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6998 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6999 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
7002 if (diA->pConfigFile) {
7003 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
7004 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7005 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
7008 if ((Level > 2) && diA->pHelpFile) {
7009 len = MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, NULL, 0);
7010 diW.pHelpFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7011 MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, diW.pHelpFile, len);
7014 if ((Level > 2) && diA->pDependentFiles) {
7015 lenA = multi_sz_lenA(diA->pDependentFiles);
7016 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
7017 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7018 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
7021 if ((Level > 2) && diA->pMonitorName) {
7022 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
7023 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7024 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
7027 if ((Level > 2) && diA->pDefaultDataType) {
7028 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
7029 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7030 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
7033 if ((Level > 3) && diA->pszzPreviousNames) {
7034 lenA = multi_sz_lenA(diA->pszzPreviousNames);
7035 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
7036 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7037 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
7040 if (Level > 5) {
7041 diW.ftDriverDate = diA->ftDriverDate;
7042 diW.dwlDriverVersion = diA->dwlDriverVersion;
7045 if ((Level > 5) && diA->pszMfgName) {
7046 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
7047 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7048 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
7051 if ((Level > 5) && diA->pszOEMUrl) {
7052 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
7053 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7054 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
7057 if ((Level > 5) && diA->pszHardwareID) {
7058 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
7059 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7060 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
7063 if ((Level > 5) && diA->pszProvider) {
7064 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
7065 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7066 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
7069 if ((Level > 7) && diA->pszPrintProcessor) {
7070 len = MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, NULL, 0);
7071 diW.pszPrintProcessor = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7072 MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, diW.pszPrintProcessor, len);
7075 if ((Level > 7) && diA->pszVendorSetup) {
7076 len = MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, NULL, 0);
7077 diW.pszVendorSetup = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7078 MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, diW.pszVendorSetup, len);
7081 if ((Level > 7) && diA->pszzColorProfiles) {
7082 lenA = multi_sz_lenA(diA->pszzColorProfiles);
7083 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, NULL, 0);
7084 diW.pszzColorProfiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7085 MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, diW.pszzColorProfiles, len);
7088 if ((Level > 7) && diA->pszInfPath) {
7089 len = MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, NULL, 0);
7090 diW.pszInfPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7091 MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, diW.pszInfPath, len);
7094 if ((Level > 7) && diA->pszzCoreDriverDependencies) {
7095 lenA = multi_sz_lenA(diA->pszzCoreDriverDependencies);
7096 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, NULL, 0);
7097 diW.pszzCoreDriverDependencies = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7098 MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, diW.pszzCoreDriverDependencies, len);
7101 if (Level > 7) {
7102 diW.dwPrinterDriverAttributes = diA->dwPrinterDriverAttributes;
7103 diW.ftMinInboxDriverVerDate = diA->ftMinInboxDriverVerDate;
7104 diW.dwlMinInboxDriverVerVersion = diA->dwlMinInboxDriverVerVersion;
7107 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
7108 TRACE("got %u with %u\n", res, GetLastError());
7109 HeapFree(GetProcessHeap(), 0, nameW);
7110 HeapFree(GetProcessHeap(), 0, diW.pName);
7111 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
7112 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
7113 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
7114 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
7115 HeapFree(GetProcessHeap(), 0, diW.pHelpFile);
7116 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
7117 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
7118 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
7119 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
7120 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
7121 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
7122 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
7123 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
7124 HeapFree(GetProcessHeap(), 0, diW.pszPrintProcessor);
7125 HeapFree(GetProcessHeap(), 0, diW.pszVendorSetup);
7126 HeapFree(GetProcessHeap(), 0, diW.pszzColorProfiles);
7127 HeapFree(GetProcessHeap(), 0, diW.pszInfPath);
7128 HeapFree(GetProcessHeap(), 0, diW.pszzCoreDriverDependencies);
7130 TRACE("=> %u with %u\n", res, GetLastError());
7131 return res;
7134 /******************************************************************************
7135 * ConfigurePortA (WINSPOOL.@)
7137 * See ConfigurePortW.
7140 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7142 LPWSTR nameW = NULL;
7143 LPWSTR portW = NULL;
7144 INT len;
7145 DWORD res;
7147 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7149 /* convert servername to unicode */
7150 if (pName) {
7151 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7152 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7153 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7156 /* convert portname to unicode */
7157 if (pPortName) {
7158 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7159 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7160 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7163 res = ConfigurePortW(nameW, hWnd, portW);
7164 HeapFree(GetProcessHeap(), 0, nameW);
7165 HeapFree(GetProcessHeap(), 0, portW);
7166 return res;
7169 /******************************************************************************
7170 * ConfigurePortW (WINSPOOL.@)
7172 * Display the Configuration-Dialog for a specific Port
7174 * PARAMS
7175 * pName [I] Servername or NULL (local Computer)
7176 * hWnd [I] Handle to parent Window for the Dialog-Box
7177 * pPortName [I] Name of the Port, that should be configured
7179 * RETURNS
7180 * Success: TRUE
7181 * Failure: FALSE
7184 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7187 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7189 if ((backend == NULL) && !load_backend()) return FALSE;
7191 if (!pPortName) {
7192 SetLastError(RPC_X_NULL_REF_POINTER);
7193 return FALSE;
7196 return backend->fpConfigurePort(pName, hWnd, pPortName);
7199 /******************************************************************************
7200 * ConnectToPrinterDlg (WINSPOOL.@)
7202 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7204 FIXME("%p %x\n", hWnd, Flags);
7205 return NULL;
7208 /******************************************************************************
7209 * DeletePrinterConnectionA (WINSPOOL.@)
7211 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7213 FIXME("%s\n", debugstr_a(pName));
7214 return TRUE;
7217 /******************************************************************************
7218 * DeletePrinterConnectionW (WINSPOOL.@)
7220 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7222 FIXME("%s\n", debugstr_w(pName));
7223 return TRUE;
7226 /******************************************************************************
7227 * DeletePrinterDriverExW (WINSPOOL.@)
7229 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7230 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7232 HKEY hkey_drivers;
7233 BOOL ret = FALSE;
7235 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7236 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7238 if(pName && pName[0])
7240 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7241 SetLastError(ERROR_INVALID_PARAMETER);
7242 return FALSE;
7245 if(dwDeleteFlag)
7247 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7248 SetLastError(ERROR_INVALID_PARAMETER);
7249 return FALSE;
7252 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7254 if(!hkey_drivers)
7256 ERR("Can't open drivers key\n");
7257 return FALSE;
7260 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7261 ret = TRUE;
7263 RegCloseKey(hkey_drivers);
7265 return ret;
7268 /******************************************************************************
7269 * DeletePrinterDriverExA (WINSPOOL.@)
7271 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7272 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7274 UNICODE_STRING NameW, EnvW, DriverW;
7275 BOOL ret;
7277 asciitounicode(&NameW, pName);
7278 asciitounicode(&EnvW, pEnvironment);
7279 asciitounicode(&DriverW, pDriverName);
7281 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7283 RtlFreeUnicodeString(&DriverW);
7284 RtlFreeUnicodeString(&EnvW);
7285 RtlFreeUnicodeString(&NameW);
7287 return ret;
7290 /******************************************************************************
7291 * DeletePrinterDataExW (WINSPOOL.@)
7293 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7294 LPCWSTR pValueName)
7296 FIXME("%p %s %s\n", hPrinter,
7297 debugstr_w(pKeyName), debugstr_w(pValueName));
7298 return ERROR_INVALID_PARAMETER;
7301 /******************************************************************************
7302 * DeletePrinterDataExA (WINSPOOL.@)
7304 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7305 LPCSTR pValueName)
7307 FIXME("%p %s %s\n", hPrinter,
7308 debugstr_a(pKeyName), debugstr_a(pValueName));
7309 return ERROR_INVALID_PARAMETER;
7312 /******************************************************************************
7313 * DeletePrintProcessorA (WINSPOOL.@)
7315 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7317 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7318 debugstr_a(pPrintProcessorName));
7319 return TRUE;
7322 /******************************************************************************
7323 * DeletePrintProcessorW (WINSPOOL.@)
7325 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7327 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7328 debugstr_w(pPrintProcessorName));
7329 return TRUE;
7332 /******************************************************************************
7333 * DeletePrintProvidorA (WINSPOOL.@)
7335 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7337 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7338 debugstr_a(pPrintProviderName));
7339 return TRUE;
7342 /******************************************************************************
7343 * DeletePrintProvidorW (WINSPOOL.@)
7345 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7347 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7348 debugstr_w(pPrintProviderName));
7349 return TRUE;
7352 /******************************************************************************
7353 * EnumFormsA (WINSPOOL.@)
7355 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7356 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7358 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7359 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7360 return FALSE;
7363 /******************************************************************************
7364 * EnumFormsW (WINSPOOL.@)
7366 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7367 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7369 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7370 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7371 return FALSE;
7374 /*****************************************************************************
7375 * EnumMonitorsA [WINSPOOL.@]
7377 * See EnumMonitorsW.
7380 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7381 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7383 BOOL res;
7384 LPBYTE bufferW = NULL;
7385 LPWSTR nameW = NULL;
7386 DWORD needed = 0;
7387 DWORD numentries = 0;
7388 INT len;
7390 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7391 cbBuf, pcbNeeded, pcReturned);
7393 /* convert servername to unicode */
7394 if (pName) {
7395 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7396 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7397 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7399 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7400 needed = cbBuf * sizeof(WCHAR);
7401 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7402 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7404 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7405 if (pcbNeeded) needed = *pcbNeeded;
7406 /* HeapReAlloc return NULL, when bufferW was NULL */
7407 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7408 HeapAlloc(GetProcessHeap(), 0, needed);
7410 /* Try again with the large Buffer */
7411 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7413 numentries = pcReturned ? *pcReturned : 0;
7414 needed = 0;
7416 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7417 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7419 if (res) {
7420 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7421 DWORD entrysize = 0;
7422 DWORD index;
7423 LPSTR ptr;
7424 LPMONITOR_INFO_2W mi2w;
7425 LPMONITOR_INFO_2A mi2a;
7427 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7428 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7430 /* First pass: calculate the size for all Entries */
7431 mi2w = (LPMONITOR_INFO_2W) bufferW;
7432 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7433 index = 0;
7434 while (index < numentries) {
7435 index++;
7436 needed += entrysize; /* MONITOR_INFO_?A */
7437 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7439 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7440 NULL, 0, NULL, NULL);
7441 if (Level > 1) {
7442 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7443 NULL, 0, NULL, NULL);
7444 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7445 NULL, 0, NULL, NULL);
7447 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7448 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7449 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7452 /* check for errors and quit on failure */
7453 if (cbBuf < needed) {
7454 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7455 res = FALSE;
7456 goto emA_cleanup;
7458 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7459 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7460 cbBuf -= len ; /* free Bytes in the user-Buffer */
7461 mi2w = (LPMONITOR_INFO_2W) bufferW;
7462 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7463 index = 0;
7464 /* Second Pass: Fill the User Buffer (if we have one) */
7465 while ((index < numentries) && pMonitors) {
7466 index++;
7467 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7468 mi2a->pName = ptr;
7469 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7470 ptr, cbBuf , NULL, NULL);
7471 ptr += len;
7472 cbBuf -= len;
7473 if (Level > 1) {
7474 mi2a->pEnvironment = ptr;
7475 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7476 ptr, cbBuf, NULL, NULL);
7477 ptr += len;
7478 cbBuf -= len;
7480 mi2a->pDLLName = ptr;
7481 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7482 ptr, cbBuf, NULL, NULL);
7483 ptr += len;
7484 cbBuf -= len;
7486 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7487 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7488 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7491 emA_cleanup:
7492 if (pcbNeeded) *pcbNeeded = needed;
7493 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7495 HeapFree(GetProcessHeap(), 0, nameW);
7496 HeapFree(GetProcessHeap(), 0, bufferW);
7498 TRACE("returning %d with %d (%d byte for %d entries)\n",
7499 (res), GetLastError(), needed, numentries);
7501 return (res);
7505 /*****************************************************************************
7506 * EnumMonitorsW [WINSPOOL.@]
7508 * Enumerate available Port-Monitors
7510 * PARAMS
7511 * pName [I] Servername or NULL (local Computer)
7512 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7513 * pMonitors [O] PTR to Buffer that receives the Result
7514 * cbBuf [I] Size of Buffer at pMonitors
7515 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7516 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7518 * RETURNS
7519 * Success: TRUE
7520 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7523 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7524 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7527 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7528 cbBuf, pcbNeeded, pcReturned);
7530 if ((backend == NULL) && !load_backend()) return FALSE;
7532 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7533 SetLastError(RPC_X_NULL_REF_POINTER);
7534 return FALSE;
7537 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7540 /******************************************************************************
7541 * SpoolerInit (WINSPOOL.@)
7543 * Initialize the Spooler
7545 * RETURNS
7546 * Success: TRUE
7547 * Failure: FALSE
7549 * NOTES
7550 * The function fails on windows, when the spooler service is not running
7553 BOOL WINAPI SpoolerInit(void)
7556 if ((backend == NULL) && !load_backend()) return FALSE;
7557 return TRUE;
7560 /******************************************************************************
7561 * XcvDataW (WINSPOOL.@)
7563 * Execute commands in the Printmonitor DLL
7565 * PARAMS
7566 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7567 * pszDataName [i] Name of the command to execute
7568 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7569 * cbInputData [i] Size in Bytes of Buffer at pInputData
7570 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7571 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7572 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7573 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7575 * RETURNS
7576 * Success: TRUE
7577 * Failure: FALSE
7579 * NOTES
7580 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7581 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7583 * Minimal List of commands, that a Printmonitor DLL should support:
7585 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7586 *| "AddPort" : Add a Port
7587 *| "DeletePort": Delete a Port
7589 * Many Printmonitors support additional commands. Examples for localspl.dll:
7590 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7591 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7594 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7595 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7596 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7598 opened_printer_t *printer;
7600 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7601 pInputData, cbInputData, pOutputData,
7602 cbOutputData, pcbOutputNeeded, pdwStatus);
7604 if ((backend == NULL) && !load_backend()) return FALSE;
7606 printer = get_opened_printer(hXcv);
7607 if (!printer || (!printer->backend_printer)) {
7608 SetLastError(ERROR_INVALID_HANDLE);
7609 return FALSE;
7612 if (!pcbOutputNeeded) {
7613 SetLastError(ERROR_INVALID_PARAMETER);
7614 return FALSE;
7617 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7618 SetLastError(RPC_X_NULL_REF_POINTER);
7619 return FALSE;
7622 *pcbOutputNeeded = 0;
7624 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7625 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7629 /*****************************************************************************
7630 * EnumPrinterDataA [WINSPOOL.@]
7633 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7634 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7635 DWORD cbData, LPDWORD pcbData )
7637 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7638 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7639 return ERROR_NO_MORE_ITEMS;
7642 /*****************************************************************************
7643 * EnumPrinterDataW [WINSPOOL.@]
7646 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7647 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7648 DWORD cbData, LPDWORD pcbData )
7650 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7651 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7652 return ERROR_NO_MORE_ITEMS;
7655 /*****************************************************************************
7656 * EnumPrinterKeyA [WINSPOOL.@]
7659 DWORD WINAPI EnumPrinterKeyA(HANDLE printer, const CHAR *key, CHAR *subkey, DWORD size, DWORD *needed)
7661 FIXME("%p %s %p %x %p\n", printer, debugstr_a(key), subkey, size, needed);
7662 return ERROR_CALL_NOT_IMPLEMENTED;
7665 /*****************************************************************************
7666 * EnumPrinterKeyW [WINSPOOL.@]
7669 DWORD WINAPI EnumPrinterKeyW(HANDLE printer, const WCHAR *key, WCHAR *subkey, DWORD size, DWORD *needed)
7671 FIXME("%p %s %p %x %p\n", printer, debugstr_w(key), subkey, size, needed);
7672 return ERROR_CALL_NOT_IMPLEMENTED;
7675 /*****************************************************************************
7676 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7679 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7680 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7681 LPDWORD pcbNeeded, LPDWORD pcReturned)
7683 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7684 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7685 pcbNeeded, pcReturned);
7686 return FALSE;
7689 /*****************************************************************************
7690 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7693 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7694 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7695 LPDWORD pcbNeeded, LPDWORD pcReturned)
7697 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7698 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7699 pcbNeeded, pcReturned);
7700 return FALSE;
7703 /*****************************************************************************
7704 * EnumPrintProcessorsA [WINSPOOL.@]
7706 * See EnumPrintProcessorsW.
7709 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7710 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7712 BOOL res;
7713 LPBYTE bufferW = NULL;
7714 LPWSTR nameW = NULL;
7715 LPWSTR envW = NULL;
7716 DWORD needed = 0;
7717 DWORD numentries = 0;
7718 INT len;
7720 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7721 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7723 /* convert names to unicode */
7724 if (pName) {
7725 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7726 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7727 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7729 if (pEnvironment) {
7730 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7731 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7732 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7735 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7736 needed = cbBuf * sizeof(WCHAR);
7737 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7738 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7740 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7741 if (pcbNeeded) needed = *pcbNeeded;
7742 /* HeapReAlloc return NULL, when bufferW was NULL */
7743 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7744 HeapAlloc(GetProcessHeap(), 0, needed);
7746 /* Try again with the large Buffer */
7747 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7749 numentries = pcReturned ? *pcReturned : 0;
7750 needed = 0;
7752 if (res) {
7753 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7754 DWORD index;
7755 LPSTR ptr;
7756 PPRINTPROCESSOR_INFO_1W ppiw;
7757 PPRINTPROCESSOR_INFO_1A ppia;
7759 /* First pass: calculate the size for all Entries */
7760 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7761 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7762 index = 0;
7763 while (index < numentries) {
7764 index++;
7765 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7766 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7768 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7769 NULL, 0, NULL, NULL);
7771 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7772 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7775 /* check for errors and quit on failure */
7776 if (cbBuf < needed) {
7777 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7778 res = FALSE;
7779 goto epp_cleanup;
7782 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7783 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7784 cbBuf -= len ; /* free Bytes in the user-Buffer */
7785 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7786 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7787 index = 0;
7788 /* Second Pass: Fill the User Buffer (if we have one) */
7789 while ((index < numentries) && pPPInfo) {
7790 index++;
7791 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7792 ppia->pName = ptr;
7793 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7794 ptr, cbBuf , NULL, NULL);
7795 ptr += len;
7796 cbBuf -= len;
7798 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7799 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7803 epp_cleanup:
7804 if (pcbNeeded) *pcbNeeded = needed;
7805 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7807 HeapFree(GetProcessHeap(), 0, nameW);
7808 HeapFree(GetProcessHeap(), 0, envW);
7809 HeapFree(GetProcessHeap(), 0, bufferW);
7811 TRACE("returning %d with %d (%d byte for %d entries)\n",
7812 (res), GetLastError(), needed, numentries);
7814 return (res);
7817 /*****************************************************************************
7818 * EnumPrintProcessorsW [WINSPOOL.@]
7820 * Enumerate available Print Processors
7822 * PARAMS
7823 * pName [I] Servername or NULL (local Computer)
7824 * pEnvironment [I] Printing-Environment or NULL (Default)
7825 * Level [I] Structure-Level (Only 1 is allowed)
7826 * pPPInfo [O] PTR to Buffer that receives the Result
7827 * cbBuf [I] Size of Buffer at pPPInfo
7828 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7829 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7831 * RETURNS
7832 * Success: TRUE
7833 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7836 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7837 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7840 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7841 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7843 if ((backend == NULL) && !load_backend()) return FALSE;
7845 if (!pcbNeeded || !pcReturned) {
7846 SetLastError(RPC_X_NULL_REF_POINTER);
7847 return FALSE;
7850 if (!pPPInfo && (cbBuf > 0)) {
7851 SetLastError(ERROR_INVALID_USER_BUFFER);
7852 return FALSE;
7855 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7856 cbBuf, pcbNeeded, pcReturned);
7859 /*****************************************************************************
7860 * ExtDeviceMode [WINSPOOL.@]
7863 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7864 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7865 DWORD fMode)
7867 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7868 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7869 debugstr_a(pProfile), fMode);
7870 return -1;
7873 /*****************************************************************************
7874 * FindClosePrinterChangeNotification [WINSPOOL.@]
7877 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7879 FIXME("Stub: %p\n", hChange);
7880 return TRUE;
7883 /*****************************************************************************
7884 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7887 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7888 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7890 FIXME("Stub: %p %x %x %p\n",
7891 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7892 return INVALID_HANDLE_VALUE;
7895 /*****************************************************************************
7896 * FindNextPrinterChangeNotification [WINSPOOL.@]
7899 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7900 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7902 FIXME("Stub: %p %p %p %p\n",
7903 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7904 return FALSE;
7907 /*****************************************************************************
7908 * FreePrinterNotifyInfo [WINSPOOL.@]
7911 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7913 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7914 return TRUE;
7917 /*****************************************************************************
7918 * string_to_buf
7920 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7921 * ansi depending on the unicode parameter.
7923 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7925 if(!str)
7927 *size = 0;
7928 return TRUE;
7931 if(unicode)
7933 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7934 if(*size <= cb)
7936 memcpy(ptr, str, *size);
7937 return TRUE;
7939 return FALSE;
7941 else
7943 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7944 if(*size <= cb)
7946 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7947 return TRUE;
7949 return FALSE;
7953 /*****************************************************************************
7954 * get_job_info_1
7956 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7957 LPDWORD pcbNeeded, BOOL unicode)
7959 DWORD size, left = cbBuf;
7960 BOOL space = (cbBuf > 0);
7961 LPBYTE ptr = buf;
7963 *pcbNeeded = 0;
7965 if(space)
7967 ji1->JobId = job->job_id;
7970 string_to_buf(job->document_title, ptr, left, &size, unicode);
7971 if(space && size <= left)
7973 ji1->pDocument = (LPWSTR)ptr;
7974 ptr += size;
7975 left -= size;
7977 else
7978 space = FALSE;
7979 *pcbNeeded += size;
7981 if (job->printer_name)
7983 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7984 if(space && size <= left)
7986 ji1->pPrinterName = (LPWSTR)ptr;
7987 ptr += size;
7988 left -= size;
7990 else
7991 space = FALSE;
7992 *pcbNeeded += size;
7995 return space;
7998 /*****************************************************************************
7999 * get_job_info_2
8001 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
8002 LPDWORD pcbNeeded, BOOL unicode)
8004 DWORD size, left = cbBuf;
8005 DWORD shift;
8006 BOOL space = (cbBuf > 0);
8007 LPBYTE ptr = buf;
8008 LPDEVMODEA dmA = NULL;
8009 LPDEVMODEW devmode;
8011 *pcbNeeded = 0;
8013 if(space)
8015 ji2->JobId = job->job_id;
8018 string_to_buf(job->document_title, ptr, left, &size, unicode);
8019 if(space && size <= left)
8021 ji2->pDocument = (LPWSTR)ptr;
8022 ptr += size;
8023 left -= size;
8025 else
8026 space = FALSE;
8027 *pcbNeeded += size;
8029 if (job->printer_name)
8031 string_to_buf(job->printer_name, ptr, left, &size, unicode);
8032 if(space && size <= left)
8034 ji2->pPrinterName = (LPWSTR)ptr;
8035 ptr += size;
8036 left -= size;
8038 else
8039 space = FALSE;
8040 *pcbNeeded += size;
8043 if (job->devmode)
8045 if (!unicode)
8047 dmA = DEVMODEdupWtoA(job->devmode);
8048 devmode = (LPDEVMODEW) dmA;
8049 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
8051 else
8053 devmode = job->devmode;
8054 size = devmode->dmSize + devmode->dmDriverExtra;
8057 if (!devmode)
8058 FIXME("Can't convert DEVMODE W to A\n");
8059 else
8061 /* align DEVMODE to a DWORD boundary */
8062 shift = (4 - (*pcbNeeded & 3)) & 3;
8063 size += shift;
8065 if (size <= left)
8067 ptr += shift;
8068 memcpy(ptr, devmode, size-shift);
8069 ji2->pDevMode = (LPDEVMODEW)ptr;
8070 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
8071 ptr += size-shift;
8072 left -= size;
8074 else
8075 space = FALSE;
8076 *pcbNeeded +=size;
8080 return space;
8083 /*****************************************************************************
8084 * get_job_info
8086 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8087 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
8089 BOOL ret = FALSE;
8090 DWORD needed = 0, size;
8091 job_t *job;
8092 LPBYTE ptr = pJob;
8094 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
8096 EnterCriticalSection(&printer_handles_cs);
8097 job = get_job(hPrinter, JobId);
8098 if(!job)
8099 goto end;
8101 switch(Level)
8103 case 1:
8104 size = sizeof(JOB_INFO_1W);
8105 if(cbBuf >= size)
8107 cbBuf -= size;
8108 ptr += size;
8109 memset(pJob, 0, size);
8111 else
8112 cbBuf = 0;
8113 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
8114 needed += size;
8115 break;
8117 case 2:
8118 size = sizeof(JOB_INFO_2W);
8119 if(cbBuf >= size)
8121 cbBuf -= size;
8122 ptr += size;
8123 memset(pJob, 0, size);
8125 else
8126 cbBuf = 0;
8127 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
8128 needed += size;
8129 break;
8131 case 3:
8132 size = sizeof(JOB_INFO_3);
8133 if(cbBuf >= size)
8135 cbBuf -= size;
8136 memset(pJob, 0, size);
8137 ret = TRUE;
8139 else
8140 cbBuf = 0;
8141 needed = size;
8142 break;
8144 default:
8145 SetLastError(ERROR_INVALID_LEVEL);
8146 goto end;
8148 if(pcbNeeded)
8149 *pcbNeeded = needed;
8150 end:
8151 LeaveCriticalSection(&printer_handles_cs);
8152 return ret;
8155 /*****************************************************************************
8156 * GetJobA [WINSPOOL.@]
8159 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8160 DWORD cbBuf, LPDWORD pcbNeeded)
8162 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8165 /*****************************************************************************
8166 * GetJobW [WINSPOOL.@]
8169 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8170 DWORD cbBuf, LPDWORD pcbNeeded)
8172 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8175 /*****************************************************************************
8176 * schedule_pipe
8178 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8180 #ifdef HAVE_FORK
8181 char *unixname, *cmdA;
8182 DWORD len;
8183 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8184 BOOL ret = FALSE;
8185 char buf[1024];
8186 pid_t pid, wret;
8187 int status;
8189 if(!(unixname = wine_get_unix_file_name(filename)))
8190 return FALSE;
8192 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8193 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8194 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8196 TRACE("printing with: %s\n", cmdA);
8198 if((file_fd = open(unixname, O_RDONLY)) == -1)
8199 goto end;
8201 if (pipe(fds))
8203 ERR("pipe() failed!\n");
8204 goto end;
8207 if ((pid = fork()) == 0)
8209 close(0);
8210 dup2(fds[0], 0);
8211 close(fds[1]);
8213 /* reset signals that we previously set to SIG_IGN */
8214 signal(SIGPIPE, SIG_DFL);
8216 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8217 _exit(1);
8219 else if (pid == -1)
8221 ERR("fork() failed!\n");
8222 goto end;
8225 close(fds[0]);
8226 fds[0] = -1;
8227 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8228 write(fds[1], buf, no_read);
8230 close(fds[1]);
8231 fds[1] = -1;
8233 /* reap child */
8234 do {
8235 wret = waitpid(pid, &status, 0);
8236 } while (wret < 0 && errno == EINTR);
8237 if (wret < 0)
8239 ERR("waitpid() failed!\n");
8240 goto end;
8242 if (!WIFEXITED(status) || WEXITSTATUS(status))
8244 ERR("child process failed! %d\n", status);
8245 goto end;
8248 ret = TRUE;
8250 end:
8251 if(file_fd != -1) close(file_fd);
8252 if(fds[0] != -1) close(fds[0]);
8253 if(fds[1] != -1) close(fds[1]);
8255 HeapFree(GetProcessHeap(), 0, cmdA);
8256 HeapFree(GetProcessHeap(), 0, unixname);
8257 return ret;
8258 #else
8259 return FALSE;
8260 #endif
8263 /*****************************************************************************
8264 * schedule_lpr
8266 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8268 static const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8269 WCHAR *cmd;
8270 BOOL r;
8272 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8273 sprintfW(cmd, fmtW, printer_name);
8275 r = schedule_pipe(cmd, filename);
8277 HeapFree(GetProcessHeap(), 0, cmd);
8278 return r;
8281 #ifdef SONAME_LIBCUPS
8282 /*****************************************************************************
8283 * get_cups_jobs_ticket_options
8285 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8286 * The CUPS scheduler only looks for these in Print-File requests, and since
8287 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8288 * parsed.
8290 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8292 FILE *fp = fopen( file, "r" );
8293 char buf[257]; /* DSC max of 256 + '\0' */
8294 const char *ps_adobe = "%!PS-Adobe-";
8295 const char *cups_job = "%cupsJobTicket:";
8297 if (!fp) return num_options;
8298 if (!fgets( buf, sizeof(buf), fp )) goto end;
8299 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8300 while (fgets( buf, sizeof(buf), fp ))
8302 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8303 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8306 end:
8307 fclose( fp );
8308 return num_options;
8311 static int get_cups_default_options( const char *printer, int num_options, cups_option_t **options )
8313 cups_dest_t *dest;
8314 int i;
8316 if (!pcupsGetNamedDest) return num_options;
8318 dest = pcupsGetNamedDest( NULL, printer, NULL );
8319 if (!dest) return num_options;
8321 for (i = 0; i < dest->num_options; i++)
8323 if (!pcupsGetOption( dest->options[i].name, num_options, *options ))
8324 num_options = pcupsAddOption( dest->options[i].name, dest->options[i].value,
8325 num_options, options );
8328 pcupsFreeDests( 1, dest );
8329 return num_options;
8331 #endif
8333 /*****************************************************************************
8334 * schedule_cups
8336 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8338 #ifdef SONAME_LIBCUPS
8339 if(pcupsPrintFile)
8341 char *unixname, *queue, *unix_doc_title;
8342 DWORD len;
8343 BOOL ret;
8344 int num_options = 0, i;
8345 cups_option_t *options = NULL;
8347 if(!(unixname = wine_get_unix_file_name(filename)))
8348 return FALSE;
8350 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8351 queue = HeapAlloc(GetProcessHeap(), 0, len);
8352 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8354 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8355 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8356 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8358 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8359 num_options = get_cups_default_options( queue, num_options, &options );
8361 TRACE( "printing via cups with options:\n" );
8362 for (i = 0; i < num_options; i++)
8363 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8365 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8366 if (ret == 0 && pcupsLastErrorString)
8367 WARN("cupsPrintFile failed with error %s\n", debugstr_a(pcupsLastErrorString()));
8369 pcupsFreeOptions( num_options, options );
8371 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8372 HeapFree(GetProcessHeap(), 0, queue);
8373 HeapFree(GetProcessHeap(), 0, unixname);
8374 return ret;
8376 else
8377 #endif
8379 return schedule_lpr(printer_name, filename);
8383 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8385 LPWSTR filename;
8387 switch(msg)
8389 case WM_INITDIALOG:
8390 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8391 return TRUE;
8393 case WM_COMMAND:
8394 if(HIWORD(wparam) == BN_CLICKED)
8396 if(LOWORD(wparam) == IDOK)
8398 HANDLE hf;
8399 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8400 LPWSTR *output;
8402 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8403 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8405 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8407 WCHAR caption[200], message[200];
8408 int mb_ret;
8410 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, ARRAY_SIZE(caption));
8411 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, ARRAY_SIZE(message));
8412 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8413 if(mb_ret == IDCANCEL)
8415 HeapFree(GetProcessHeap(), 0, filename);
8416 return TRUE;
8419 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8420 if(hf == INVALID_HANDLE_VALUE)
8422 WCHAR caption[200], message[200];
8424 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, ARRAY_SIZE(caption));
8425 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, ARRAY_SIZE(message));
8426 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8427 HeapFree(GetProcessHeap(), 0, filename);
8428 return TRUE;
8430 CloseHandle(hf);
8431 DeleteFileW(filename);
8432 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8433 *output = filename;
8434 EndDialog(hwnd, IDOK);
8435 return TRUE;
8437 if(LOWORD(wparam) == IDCANCEL)
8439 EndDialog(hwnd, IDCANCEL);
8440 return TRUE;
8443 return FALSE;
8445 return FALSE;
8448 /*****************************************************************************
8449 * get_filename
8451 static BOOL get_filename(LPWSTR *filename)
8453 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8454 file_dlg_proc, (LPARAM)filename) == IDOK;
8457 /*****************************************************************************
8458 * schedule_file
8460 static BOOL schedule_file(LPCWSTR filename)
8462 LPWSTR output = NULL;
8464 if(get_filename(&output))
8466 BOOL r;
8467 TRACE("copy to %s\n", debugstr_w(output));
8468 r = CopyFileW(filename, output, FALSE);
8469 HeapFree(GetProcessHeap(), 0, output);
8470 return r;
8472 return FALSE;
8475 /*****************************************************************************
8476 * schedule_unixfile
8478 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8480 int in_fd, out_fd, no_read;
8481 char buf[1024];
8482 BOOL ret = FALSE;
8483 char *unixname, *outputA;
8484 DWORD len;
8486 if(!(unixname = wine_get_unix_file_name(filename)))
8487 return FALSE;
8489 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8490 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8491 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8493 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8494 in_fd = open(unixname, O_RDONLY);
8495 if(out_fd == -1 || in_fd == -1)
8496 goto end;
8498 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8499 write(out_fd, buf, no_read);
8501 ret = TRUE;
8502 end:
8503 if(in_fd != -1) close(in_fd);
8504 if(out_fd != -1) close(out_fd);
8505 HeapFree(GetProcessHeap(), 0, outputA);
8506 HeapFree(GetProcessHeap(), 0, unixname);
8507 return ret;
8510 /*****************************************************************************
8511 * ScheduleJob [WINSPOOL.@]
8514 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8516 opened_printer_t *printer;
8517 BOOL ret = FALSE;
8518 struct list *cursor, *cursor2;
8520 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8521 EnterCriticalSection(&printer_handles_cs);
8522 printer = get_opened_printer(hPrinter);
8523 if(!printer)
8524 goto end;
8526 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8528 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8529 HANDLE hf;
8531 if(job->job_id != dwJobID) continue;
8533 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8534 if(hf != INVALID_HANDLE_VALUE)
8536 PRINTER_INFO_5W *pi5 = NULL;
8537 LPWSTR portname = job->portname;
8538 DWORD needed;
8539 HKEY hkey;
8540 WCHAR output[1024];
8541 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8542 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8544 if (!portname)
8546 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8547 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8548 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8549 portname = pi5->pPortName;
8551 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8552 debugstr_w(portname));
8554 output[0] = 0;
8556 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8557 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8559 DWORD type, count = sizeof(output);
8560 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8561 RegCloseKey(hkey);
8563 if(output[0] == '|')
8565 ret = schedule_pipe(output + 1, job->filename);
8567 else if(output[0])
8569 ret = schedule_unixfile(output, job->filename);
8571 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8573 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8575 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8577 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8579 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8581 ret = schedule_file(job->filename);
8583 else if(isalpha(portname[0]) && portname[1] == ':')
8585 TRACE("copying to %s\n", debugstr_w(portname));
8586 ret = CopyFileW(job->filename, portname, FALSE);
8588 else
8590 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8592 HeapFree(GetProcessHeap(), 0, pi5);
8593 CloseHandle(hf);
8594 DeleteFileW(job->filename);
8596 list_remove(cursor);
8597 HeapFree(GetProcessHeap(), 0, job->document_title);
8598 HeapFree(GetProcessHeap(), 0, job->printer_name);
8599 HeapFree(GetProcessHeap(), 0, job->portname);
8600 HeapFree(GetProcessHeap(), 0, job->filename);
8601 HeapFree(GetProcessHeap(), 0, job->devmode);
8602 HeapFree(GetProcessHeap(), 0, job);
8603 break;
8605 end:
8606 LeaveCriticalSection(&printer_handles_cs);
8607 return ret;
8610 /*****************************************************************************
8611 * StartDocDlgA [WINSPOOL.@]
8613 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8615 UNICODE_STRING usBuffer;
8616 DOCINFOW docW = { 0 };
8617 LPWSTR retW;
8618 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8619 LPSTR ret = NULL;
8621 docW.cbSize = sizeof(docW);
8622 if (doc->lpszDocName)
8624 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8625 if (!(docW.lpszDocName = docnameW)) goto failed;
8627 if (doc->lpszOutput)
8629 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8630 if (!(docW.lpszOutput = outputW)) goto failed;
8632 if (doc->lpszDatatype)
8634 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8635 if (!(docW.lpszDatatype = datatypeW)) goto failed;
8637 docW.fwType = doc->fwType;
8639 retW = StartDocDlgW(hPrinter, &docW);
8641 if(retW)
8643 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8644 ret = HeapAlloc(GetProcessHeap(), 0, len);
8645 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8646 HeapFree(GetProcessHeap(), 0, retW);
8649 failed:
8650 HeapFree(GetProcessHeap(), 0, datatypeW);
8651 HeapFree(GetProcessHeap(), 0, outputW);
8652 HeapFree(GetProcessHeap(), 0, docnameW);
8654 return ret;
8657 /*****************************************************************************
8658 * StartDocDlgW [WINSPOOL.@]
8660 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8661 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8662 * port is "FILE:". Also returns the full path if passed a relative path.
8664 * The caller should free the returned string from the process heap.
8666 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8668 LPWSTR ret = NULL;
8669 DWORD len, attr;
8671 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8673 PRINTER_INFO_5W *pi5;
8674 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8675 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8676 return NULL;
8677 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8678 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8679 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8681 HeapFree(GetProcessHeap(), 0, pi5);
8682 return NULL;
8684 HeapFree(GetProcessHeap(), 0, pi5);
8687 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8689 LPWSTR name;
8691 if (get_filename(&name))
8693 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8695 HeapFree(GetProcessHeap(), 0, name);
8696 return NULL;
8698 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8699 GetFullPathNameW(name, len, ret, NULL);
8700 HeapFree(GetProcessHeap(), 0, name);
8702 return ret;
8705 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8706 return NULL;
8708 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8709 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8711 attr = GetFileAttributesW(ret);
8712 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8714 HeapFree(GetProcessHeap(), 0, ret);
8715 ret = NULL;
8717 return ret;
8720 /*****************************************************************************
8721 * UploadPrinterDriverPackageA [WINSPOOL.@]
8723 HRESULT WINAPI UploadPrinterDriverPackageA( LPCSTR server, LPCSTR path, LPCSTR env,
8724 DWORD flags, HWND hwnd, LPSTR dst, PULONG dstlen )
8726 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server), debugstr_a(path), debugstr_a(env),
8727 flags, hwnd, dst, dstlen);
8728 return E_NOTIMPL;
8731 /*****************************************************************************
8732 * UploadPrinterDriverPackageW [WINSPOOL.@]
8734 HRESULT WINAPI UploadPrinterDriverPackageW( LPCWSTR server, LPCWSTR path, LPCWSTR env,
8735 DWORD flags, HWND hwnd, LPWSTR dst, PULONG dstlen )
8737 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server), debugstr_w(path), debugstr_w(env),
8738 flags, hwnd, dst, dstlen);
8739 return E_NOTIMPL;
8742 /*****************************************************************************
8743 * PerfOpen [WINSPOOL.@]
8745 DWORD WINAPI PerfOpen(LPWSTR context)
8747 FIXME("%s: stub\n", debugstr_w(context));
8748 return ERROR_SUCCESS;
8751 /*****************************************************************************
8752 * PerfClose [WINSPOOL.@]
8754 DWORD WINAPI PerfClose(void)
8756 FIXME("stub\n");
8757 return ERROR_SUCCESS;
8760 /*****************************************************************************
8761 * PerfCollect [WINSPOOL.@]
8763 DWORD WINAPI PerfCollect(LPWSTR query, LPVOID *data, LPDWORD size, LPDWORD obj_count)
8765 FIXME("%s, %p, %p, %p: stub\n", debugstr_w(query), data, size, obj_count);
8766 *size = 0;
8767 *obj_count = 0;
8768 return ERROR_SUCCESS;