d2d1/tests: Add return value test (Coverity).
[wine/zf.git] / dlls / winspool.drv / info.c
blobfb9c1599d38027eea4d7530f0d9a2f920651688e
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 int len = (strlenW( dir ) + strlenW( file_name )) * sizeof(WCHAR) + sizeof(dot_ppd);
725 WCHAR *ppd = HeapAlloc( GetProcessHeap(), 0, len );
727 if (!ppd) return NULL;
728 strcpyW( ppd, dir );
729 strcatW( ppd, file_name );
730 strcatW( ppd, dot_ppd );
732 return ppd;
735 static WCHAR *get_ppd_dir( void )
737 static const WCHAR wine_ppds[] = {'w','i','n','e','_','p','p','d','s','\\',0};
738 DWORD len;
739 WCHAR *dir, tmp_path[MAX_PATH];
740 BOOL res;
742 len = GetTempPathW( ARRAY_SIZE( tmp_path ), tmp_path );
743 if (!len) return NULL;
744 dir = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
745 if (!dir) return NULL;
747 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
748 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
749 res = CreateDirectoryW( dir, NULL );
750 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
752 HeapFree( GetProcessHeap(), 0, dir );
753 dir = NULL;
755 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
756 return dir;
759 static void unlink_ppd( const WCHAR *ppd )
761 char *unix_name = wine_get_unix_file_name( ppd );
762 unlink( unix_name );
763 HeapFree( GetProcessHeap(), 0, unix_name );
766 #ifdef SONAME_LIBCUPS
768 static void *cupshandle;
770 #define CUPS_FUNCS \
771 DO_FUNC(cupsAddOption); \
772 DO_FUNC(cupsFreeDests); \
773 DO_FUNC(cupsFreeOptions); \
774 DO_FUNC(cupsGetDests); \
775 DO_FUNC(cupsGetOption); \
776 DO_FUNC(cupsParseOptions); \
777 DO_FUNC(cupsPrintFile)
778 #define CUPS_OPT_FUNCS \
779 DO_FUNC(cupsGetNamedDest); \
780 DO_FUNC(cupsGetPPD); \
781 DO_FUNC(cupsGetPPD3); \
782 DO_FUNC(cupsLastErrorString)
784 #define DO_FUNC(f) static typeof(f) *p##f
785 CUPS_FUNCS;
786 #undef DO_FUNC
787 static cups_dest_t * (*pcupsGetNamedDest)(http_t *, const char *, const char *);
788 static const char * (*pcupsGetPPD)(const char *);
789 static http_status_t (*pcupsGetPPD3)(http_t *, const char *, time_t *, char *, size_t);
790 static const char * (*pcupsLastErrorString)(void);
792 static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name,
793 time_t *modtime, char *buffer,
794 size_t bufsize )
796 const char *ppd;
798 if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
800 if (!pcupsGetPPD) return HTTP_NOT_FOUND;
802 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
804 *modtime = 0;
805 ppd = pcupsGetPPD( name );
807 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
809 if (!ppd) return HTTP_NOT_FOUND;
811 if (rename( ppd, buffer ) == -1)
813 BOOL res = copy_file( ppd, buffer );
814 unlink( ppd );
815 if (!res) return HTTP_NOT_FOUND;
817 return HTTP_OK;
820 static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
822 time_t modtime = 0;
823 http_status_t http_status;
824 char *unix_name = wine_get_unix_file_name( ppd );
826 TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
828 if (!unix_name) return FALSE;
830 http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
831 unix_name, strlen( unix_name ) + 1 );
833 if (http_status != HTTP_OK) unlink( unix_name );
834 HeapFree( GetProcessHeap(), 0, unix_name );
836 if (http_status == HTTP_OK) return TRUE;
838 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
839 debugstr_a(printer_name), http_status );
840 return get_fallback_ppd( printer_name, ppd );
843 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
845 const char *value;
846 WCHAR *ret;
847 int len;
849 value = pcupsGetOption( name, num_options, options );
850 if (!value) return NULL;
852 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
853 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
854 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
856 return ret;
859 static cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
861 WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
862 cups_ptype_t ret = 0;
864 if (type && *type)
866 ret = (cups_ptype_t)strtoulW( type, &end, 10 );
867 if (*end) ret = 0;
869 HeapFree( GetProcessHeap(), 0, type );
870 return ret;
873 static void load_cups(void)
875 cupshandle = dlopen( SONAME_LIBCUPS, RTLD_NOW );
876 if (!cupshandle) return;
878 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
880 #define DO_FUNC(x) \
881 p##x = dlsym( cupshandle, #x ); \
882 if (!p##x) \
884 ERR("failed to load symbol %s\n", #x); \
885 cupshandle = NULL; \
886 return; \
888 CUPS_FUNCS;
889 #undef DO_FUNC
890 #define DO_FUNC(x) p##x = dlsym( cupshandle, #x )
891 CUPS_OPT_FUNCS;
892 #undef DO_FUNC
895 static BOOL CUPS_LoadPrinters(void)
897 int i, nrofdests;
898 BOOL hadprinter = FALSE, haddefault = FALSE;
899 cups_dest_t *dests;
900 PRINTER_INFO_2W pi2;
901 WCHAR *port, *ppd_dir = NULL, *ppd;
902 HKEY hkeyPrinter, hkeyPrinters;
903 WCHAR nameW[MAX_PATH];
904 HANDLE added_printer;
905 cups_ptype_t printer_type;
907 if (!cupshandle) return FALSE;
909 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
910 ERROR_SUCCESS) {
911 ERR("Can't create Printers key\n");
912 return FALSE;
915 nrofdests = pcupsGetDests(&dests);
916 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
917 for (i=0;i<nrofdests;i++) {
918 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, ARRAY_SIZE(nameW));
919 printer_type = get_cups_printer_type( dests + i );
921 TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
923 if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
925 TRACE( "skipping scanner-only device\n" );
926 continue;
929 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
930 lstrcpyW(port, CUPS_Port);
931 lstrcatW(port, nameW);
933 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
934 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
935 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
936 and continue */
937 TRACE("Printer already exists\n");
938 /* overwrite old LPR:* port */
939 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
940 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
941 /* flag that the PPD file should be checked for an update */
942 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
943 RegCloseKey(hkeyPrinter);
944 } else {
945 BOOL added_driver = FALSE;
947 if (!ppd_dir && !(ppd_dir = get_ppd_dir()))
949 HeapFree( GetProcessHeap(), 0, port );
950 break;
952 ppd = get_ppd_filename( ppd_dir, nameW );
953 if (get_cups_ppd( dests[i].name, ppd ))
955 added_driver = add_printer_driver( nameW, ppd );
956 unlink_ppd( ppd );
958 HeapFree( GetProcessHeap(), 0, ppd );
959 if (!added_driver)
961 HeapFree( GetProcessHeap(), 0, port );
962 continue;
965 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
966 pi2.pPrinterName = nameW;
967 pi2.pDatatype = rawW;
968 pi2.pPrintProcessor = WinPrintW;
969 pi2.pDriverName = nameW;
970 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
971 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
972 pi2.pPortName = port;
973 pi2.pParameters = emptyStringW;
974 pi2.pShareName = emptyStringW;
975 pi2.pSepFile = emptyStringW;
977 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
978 if (added_printer) ClosePrinter( added_printer );
979 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
980 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
982 HeapFree( GetProcessHeap(), 0, pi2.pComment );
983 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
985 HeapFree( GetProcessHeap(), 0, port );
987 hadprinter = TRUE;
988 if (dests[i].is_default) {
989 SetDefaultPrinterW(nameW);
990 haddefault = TRUE;
994 if (ppd_dir)
996 RemoveDirectoryW( ppd_dir );
997 HeapFree( GetProcessHeap(), 0, ppd_dir );
1000 if (hadprinter && !haddefault) {
1001 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, ARRAY_SIZE(nameW));
1002 SetDefaultPrinterW(nameW);
1004 pcupsFreeDests(nrofdests, dests);
1005 RegCloseKey(hkeyPrinters);
1006 return TRUE;
1009 #endif
1011 static char *get_queue_name( HANDLE printer, BOOL *cups )
1013 WCHAR *port, *name = NULL;
1014 DWORD err, needed, type;
1015 char *ret = NULL;
1016 HKEY key;
1018 *cups = FALSE;
1020 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1021 if (err) return NULL;
1022 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1023 if (err) goto end;
1024 port = HeapAlloc( GetProcessHeap(), 0, needed );
1025 if (!port) goto end;
1026 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1028 if (!strncmpW( port, CUPS_Port, ARRAY_SIZE( CUPS_Port ) -1 ))
1030 name = port + ARRAY_SIZE( CUPS_Port ) - 1;
1031 *cups = TRUE;
1033 else if (!strncmpW( port, LPR_Port, ARRAY_SIZE( LPR_Port ) -1 ))
1034 name = port + ARRAY_SIZE( LPR_Port ) - 1;
1035 if (name)
1037 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1038 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1039 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1041 HeapFree( GetProcessHeap(), 0, port );
1042 end:
1043 RegCloseKey( key );
1044 return ret;
1048 static void set_ppd_overrides( HANDLE printer )
1050 WCHAR *wstr = NULL;
1051 int size = 0;
1052 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1053 OSStatus status;
1054 PMPrintSession session = NULL;
1055 PMPageFormat format = NULL;
1056 PMPaper paper;
1057 CFStringRef paper_name;
1058 CFRange range;
1060 status = PMCreateSession( &session );
1061 if (status) goto end;
1063 status = PMCreatePageFormat( &format );
1064 if (status) goto end;
1066 status = PMSessionDefaultPageFormat( session, format );
1067 if (status) goto end;
1069 status = PMGetPageFormatPaper( format, &paper );
1070 if (status) goto end;
1072 status = PMPaperGetPPDPaperName( paper, &paper_name );
1073 if (status) goto end;
1075 range.location = 0;
1076 range.length = CFStringGetLength( paper_name );
1077 size = (range.length + 1) * sizeof(WCHAR);
1079 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1080 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1081 wstr[range.length] = 0;
1083 end:
1084 if (format) PMRelease( format );
1085 if (session) PMRelease( session );
1086 #endif
1088 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1089 HeapFree( GetProcessHeap(), 0, wstr );
1092 static BOOL update_driver( HANDLE printer )
1094 BOOL ret, is_cups;
1095 const WCHAR *name = get_opened_printer_name( printer );
1096 WCHAR *ppd_dir, *ppd;
1097 char *queue_name;
1099 if (!name) return FALSE;
1100 queue_name = get_queue_name( printer, &is_cups );
1101 if (!queue_name) return FALSE;
1103 if (!(ppd_dir = get_ppd_dir()))
1105 HeapFree( GetProcessHeap(), 0, queue_name );
1106 return FALSE;
1108 ppd = get_ppd_filename( ppd_dir, name );
1110 #ifdef SONAME_LIBCUPS
1111 if (is_cups)
1112 ret = get_cups_ppd( queue_name, ppd );
1113 else
1114 #endif
1115 ret = get_fallback_ppd( queue_name, ppd );
1117 if (ret)
1119 TRACE( "updating driver %s\n", debugstr_w( name ) );
1120 ret = add_printer_driver( name, ppd );
1121 unlink_ppd( ppd );
1123 HeapFree( GetProcessHeap(), 0, ppd_dir );
1124 HeapFree( GetProcessHeap(), 0, ppd );
1125 HeapFree( GetProcessHeap(), 0, queue_name );
1127 set_ppd_overrides( printer );
1129 /* call into the driver to update the devmode */
1130 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1132 return ret;
1135 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1137 PRINTER_INFO_2A pinfo2a;
1138 const char *r;
1139 size_t name_len;
1140 char *e,*s,*name,*prettyname,*devname;
1141 BOOL ret = FALSE, set_default = FALSE;
1142 char *port = NULL, *env_default;
1143 HKEY hkeyPrinter, hkeyPrinters = NULL;
1144 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1145 HANDLE added_printer;
1147 while (isspace(*pent)) pent++;
1148 r = strchr(pent,':');
1149 if (r)
1150 name_len = r - pent;
1151 else
1152 name_len = strlen(pent);
1153 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1154 memcpy(name, pent, name_len);
1155 name[name_len] = '\0';
1156 if (r)
1157 pent = r;
1158 else
1159 pent = "";
1161 TRACE("name=%s entry=%s\n",name, pent);
1163 if(ispunct(*name)) { /* a tc entry, not a real printer */
1164 TRACE("skipping tc entry\n");
1165 goto end;
1168 if(strstr(pent,":server")) { /* server only version so skip */
1169 TRACE("skipping server entry\n");
1170 goto end;
1173 /* Determine whether this is a postscript printer. */
1175 ret = TRUE;
1176 env_default = getenv("PRINTER");
1177 prettyname = name;
1178 /* Get longest name, usually the one at the right for later display. */
1179 while((s=strchr(prettyname,'|'))) {
1180 *s = '\0';
1181 e = s;
1182 while(isspace(*--e)) *e = '\0';
1183 TRACE("\t%s\n", debugstr_a(prettyname));
1184 if(env_default && !_strnicmp(prettyname, env_default, -1)) set_default = TRUE;
1185 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1188 e = prettyname + strlen(prettyname);
1189 while(isspace(*--e)) *e = '\0';
1190 TRACE("\t%s\n", debugstr_a(prettyname));
1191 if(env_default && !_strnicmp(prettyname, env_default, -1)) set_default = TRUE;
1193 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1194 * if it is too long, we use it as comment below. */
1195 devname = prettyname;
1196 if (strlen(devname)>=CCHDEVICENAME-1)
1197 devname = name;
1198 if (strlen(devname)>=CCHDEVICENAME-1) {
1199 ret = FALSE;
1200 goto end;
1203 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1204 sprintf(port,"LPR:%s",name);
1206 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1207 ERROR_SUCCESS) {
1208 ERR("Can't create Printers key\n");
1209 ret = FALSE;
1210 goto end;
1213 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, ARRAY_SIZE(devnameW));
1215 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1216 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1217 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1218 and continue */
1219 TRACE("Printer already exists\n");
1220 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1221 /* flag that the PPD file should be checked for an update */
1222 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1223 RegCloseKey(hkeyPrinter);
1224 } else {
1225 static CHAR data_type[] = "RAW",
1226 print_proc[] = "WinPrint",
1227 comment[] = "WINEPS Printer using LPR",
1228 params[] = "<parameters?>",
1229 share_name[] = "<share name?>",
1230 sep_file[] = "<sep file?>";
1231 BOOL added_driver = FALSE;
1233 if (!ppd_dir && !(ppd_dir = get_ppd_dir())) goto end;
1234 ppd = get_ppd_filename( ppd_dir, devnameW );
1235 if (get_fallback_ppd( devname, ppd ))
1237 added_driver = add_printer_driver( devnameW, ppd );
1238 unlink_ppd( ppd );
1240 HeapFree( GetProcessHeap(), 0, ppd );
1241 if (!added_driver) goto end;
1243 memset(&pinfo2a,0,sizeof(pinfo2a));
1244 pinfo2a.pPrinterName = devname;
1245 pinfo2a.pDatatype = data_type;
1246 pinfo2a.pPrintProcessor = print_proc;
1247 pinfo2a.pDriverName = devname;
1248 pinfo2a.pComment = comment;
1249 pinfo2a.pLocation = prettyname;
1250 pinfo2a.pPortName = port;
1251 pinfo2a.pParameters = params;
1252 pinfo2a.pShareName = share_name;
1253 pinfo2a.pSepFile = sep_file;
1255 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1256 if (added_printer) ClosePrinter( added_printer );
1257 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1258 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1261 if (isfirst || set_default)
1262 set_default_printer(devname, name);
1264 end:
1265 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1266 if (ppd_dir)
1268 RemoveDirectoryW( ppd_dir );
1269 HeapFree( GetProcessHeap(), 0, ppd_dir );
1271 HeapFree(GetProcessHeap(), 0, port);
1272 HeapFree(GetProcessHeap(), 0, name);
1273 return ret;
1276 static BOOL
1277 PRINTCAP_LoadPrinters(void) {
1278 BOOL hadprinter = FALSE;
1279 char buf[200];
1280 FILE *f;
1281 char *pent = NULL;
1282 BOOL had_bash = FALSE;
1284 f = fopen("/etc/printcap","r");
1285 if (!f)
1286 return FALSE;
1288 while(fgets(buf,sizeof(buf),f)) {
1289 char *start, *end;
1291 end=strchr(buf,'\n');
1292 if (end) *end='\0';
1294 start = buf;
1295 while(isspace(*start)) start++;
1296 if(*start == '#' || *start == '\0')
1297 continue;
1299 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1300 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1301 HeapFree(GetProcessHeap(),0,pent);
1302 pent = NULL;
1305 if (end && *--end == '\\') {
1306 *end = '\0';
1307 had_bash = TRUE;
1308 } else
1309 had_bash = FALSE;
1311 if (pent) {
1312 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1313 strcat(pent,start);
1314 } else {
1315 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1316 strcpy(pent,start);
1320 if(pent) {
1321 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1322 HeapFree(GetProcessHeap(),0,pent);
1324 fclose(f);
1325 return hadprinter;
1328 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1330 if (value)
1331 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1332 (lstrlenW(value) + 1) * sizeof(WCHAR));
1333 else
1334 return ERROR_FILE_NOT_FOUND;
1337 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1339 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1340 DWORD ret = ERROR_FILE_NOT_FOUND;
1342 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1343 and we support these drivers. NT writes DEVMODEW so somehow
1344 we'll need to distinguish between these when we support NT
1345 drivers */
1347 if (dmA)
1349 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1350 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1351 HeapFree( GetProcessHeap(), 0, dmA );
1354 return ret;
1357 /******************************************************************
1358 * get_servername_from_name (internal)
1360 * for an external server, a copy of the serverpart from the full name is returned
1363 static LPWSTR get_servername_from_name(LPCWSTR name)
1365 LPWSTR server;
1366 LPWSTR ptr;
1367 WCHAR buffer[MAX_PATH];
1368 DWORD len;
1370 if (name == NULL) return NULL;
1371 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1373 server = strdupW(&name[2]); /* skip over both backslash */
1374 if (server == NULL) return NULL;
1376 /* strip '\' and the printername */
1377 ptr = strchrW(server, '\\');
1378 if (ptr) ptr[0] = '\0';
1380 TRACE("found %s\n", debugstr_w(server));
1382 len = ARRAY_SIZE(buffer);
1383 if (GetComputerNameW(buffer, &len)) {
1384 if (lstrcmpW(buffer, server) == 0) {
1385 /* The requested Servername is our computername */
1386 HeapFree(GetProcessHeap(), 0, server);
1387 return NULL;
1390 return server;
1393 /******************************************************************
1394 * get_basename_from_name (internal)
1396 * skip over the serverpart from the full name
1399 static LPCWSTR get_basename_from_name(LPCWSTR name)
1401 if (name == NULL) return NULL;
1402 if ((name[0] == '\\') && (name[1] == '\\')) {
1403 /* skip over the servername and search for the following '\' */
1404 name = strchrW(&name[2], '\\');
1405 if ((name) && (name[1])) {
1406 /* found a separator ('\') followed by a name:
1407 skip over the separator and return the rest */
1408 name++;
1410 else
1412 /* no basename present (we found only a servername) */
1413 return NULL;
1416 return name;
1419 static void free_printer_entry( opened_printer_t *printer )
1421 /* the queue is shared, so don't free that here */
1422 HeapFree( GetProcessHeap(), 0, printer->printername );
1423 HeapFree( GetProcessHeap(), 0, printer->name );
1424 HeapFree( GetProcessHeap(), 0, printer->devmode );
1425 HeapFree( GetProcessHeap(), 0, printer );
1428 /******************************************************************
1429 * get_opened_printer_entry
1430 * Get the first place empty in the opened printer table
1432 * ToDo:
1433 * - pDefault is ignored
1435 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1437 UINT_PTR handle = nb_printer_handles, i;
1438 jobqueue_t *queue = NULL;
1439 opened_printer_t *printer = NULL;
1440 LPWSTR servername;
1441 LPCWSTR printername;
1443 if ((backend == NULL) && !load_backend()) return NULL;
1445 servername = get_servername_from_name(name);
1446 if (servername) {
1447 FIXME("server %s not supported\n", debugstr_w(servername));
1448 HeapFree(GetProcessHeap(), 0, servername);
1449 SetLastError(ERROR_INVALID_PRINTER_NAME);
1450 return NULL;
1453 printername = get_basename_from_name(name);
1454 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1456 /* an empty printername is invalid */
1457 if (printername && (!printername[0])) {
1458 SetLastError(ERROR_INVALID_PARAMETER);
1459 return NULL;
1462 EnterCriticalSection(&printer_handles_cs);
1464 for (i = 0; i < nb_printer_handles; i++)
1466 if (!printer_handles[i])
1468 if(handle == nb_printer_handles)
1469 handle = i;
1471 else
1473 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1474 queue = printer_handles[i]->queue;
1478 if (handle >= nb_printer_handles)
1480 opened_printer_t **new_array;
1481 if (printer_handles)
1482 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1483 (nb_printer_handles + 16) * sizeof(*new_array) );
1484 else
1485 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1486 (nb_printer_handles + 16) * sizeof(*new_array) );
1488 if (!new_array)
1490 handle = 0;
1491 goto end;
1493 printer_handles = new_array;
1494 nb_printer_handles += 16;
1497 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1499 handle = 0;
1500 goto end;
1503 /* get a printer handle from the backend */
1504 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1505 handle = 0;
1506 goto end;
1509 /* clone the base name. This is NULL for the printserver */
1510 printer->printername = strdupW(printername);
1512 /* clone the full name */
1513 printer->name = strdupW(name);
1514 if (name && (!printer->name)) {
1515 handle = 0;
1516 goto end;
1519 if (pDefault && pDefault->pDevMode)
1520 printer->devmode = dup_devmode( pDefault->pDevMode );
1522 if(queue)
1523 printer->queue = queue;
1524 else
1526 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1527 if (!printer->queue) {
1528 handle = 0;
1529 goto end;
1531 list_init(&printer->queue->jobs);
1532 printer->queue->ref = 0;
1534 InterlockedIncrement(&printer->queue->ref);
1536 printer_handles[handle] = printer;
1537 handle++;
1538 end:
1539 LeaveCriticalSection(&printer_handles_cs);
1540 if (!handle && printer) {
1541 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1542 free_printer_entry( printer );
1545 return (HANDLE)handle;
1548 static void old_printer_check( BOOL delete_phase )
1550 PRINTER_INFO_5W* pi;
1551 DWORD needed, type, num, delete, i, size;
1552 const DWORD one = 1;
1553 HKEY key;
1554 HANDLE hprn;
1556 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1557 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1559 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1560 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1561 for (i = 0; i < num; i++)
1563 if (!pi[i].pPortName) continue;
1565 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1566 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1567 continue;
1569 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1571 if (!delete_phase)
1573 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1574 RegCloseKey( key );
1576 else
1578 delete = 0;
1579 size = sizeof( delete );
1580 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1581 RegCloseKey( key );
1582 if (delete)
1584 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1585 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1587 DeletePrinter( hprn );
1588 ClosePrinter( hprn );
1590 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1594 HeapFree(GetProcessHeap(), 0, pi);
1597 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1598 'M','U','T','E','X','_','_','\0'};
1599 static HANDLE init_mutex;
1601 void WINSPOOL_LoadSystemPrinters(void)
1603 HKEY hkey, hkeyPrinters;
1604 DWORD needed, num, i;
1605 WCHAR PrinterName[256];
1606 BOOL done = FALSE;
1608 #ifdef SONAME_LIBCUPS
1609 load_cups();
1610 #endif
1612 /* FIXME: The init code should be moved to spoolsv.exe */
1613 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1614 if (!init_mutex)
1616 ERR( "Failed to create mutex\n" );
1617 return;
1619 if (GetLastError() == ERROR_ALREADY_EXISTS)
1621 WaitForSingleObject( init_mutex, INFINITE );
1622 ReleaseMutex( init_mutex );
1623 TRACE( "Init already done\n" );
1624 return;
1627 /* This ensures that all printer entries have a valid Name value. If causes
1628 problems later if they don't. If one is found to be missed we create one
1629 and set it equal to the name of the key */
1630 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1631 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1632 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1633 for(i = 0; i < num; i++) {
1634 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, ARRAY_SIZE(PrinterName)) == ERROR_SUCCESS) {
1635 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1636 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1637 set_reg_szW(hkey, NameW, PrinterName);
1639 RegCloseKey(hkey);
1644 RegCloseKey(hkeyPrinters);
1647 old_printer_check( FALSE );
1649 #ifdef SONAME_LIBCUPS
1650 done = CUPS_LoadPrinters();
1651 #endif
1653 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1654 PRINTCAP_LoadPrinters();
1656 old_printer_check( TRUE );
1658 ReleaseMutex( init_mutex );
1659 return;
1662 /******************************************************************
1663 * get_job
1665 * Get the pointer to the specified job.
1666 * Should hold the printer_handles_cs before calling.
1668 static job_t *get_job(HANDLE hprn, DWORD JobId)
1670 opened_printer_t *printer = get_opened_printer(hprn);
1671 job_t *job;
1673 if(!printer) return NULL;
1674 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1676 if(job->job_id == JobId)
1677 return job;
1679 return NULL;
1682 /***********************************************************
1683 * DEVMODEcpyAtoW
1685 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1687 BOOL Formname;
1688 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1689 DWORD size;
1691 Formname = (dmA->dmSize > off_formname);
1692 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1693 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1694 dmW->dmDeviceName, CCHDEVICENAME);
1695 if(!Formname) {
1696 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1697 dmA->dmSize - CCHDEVICENAME);
1698 } else {
1699 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1700 off_formname - CCHDEVICENAME);
1701 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1702 dmW->dmFormName, CCHFORMNAME);
1703 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1704 (off_formname + CCHFORMNAME));
1706 dmW->dmSize = size;
1707 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1708 dmA->dmDriverExtra);
1709 return dmW;
1712 /******************************************************************
1713 * convert_printerinfo_W_to_A [internal]
1716 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1717 DWORD level, DWORD outlen, DWORD numentries)
1719 DWORD id = 0;
1720 LPSTR ptr;
1721 INT len;
1723 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1725 len = pi_sizeof[level] * numentries;
1726 ptr = (LPSTR) out + len;
1727 outlen -= len;
1729 /* copy the numbers of all PRINTER_INFO_* first */
1730 memcpy(out, pPrintersW, len);
1732 while (id < numentries) {
1733 switch (level) {
1734 case 1:
1736 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1737 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1739 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1740 if (piW->pDescription) {
1741 piA->pDescription = ptr;
1742 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1743 ptr, outlen, NULL, NULL);
1744 ptr += len;
1745 outlen -= len;
1747 if (piW->pName) {
1748 piA->pName = ptr;
1749 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1750 ptr, outlen, NULL, NULL);
1751 ptr += len;
1752 outlen -= len;
1754 if (piW->pComment) {
1755 piA->pComment = ptr;
1756 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1757 ptr, outlen, NULL, NULL);
1758 ptr += len;
1759 outlen -= len;
1761 break;
1764 case 2:
1766 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1767 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1768 LPDEVMODEA dmA;
1770 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1771 if (piW->pServerName) {
1772 piA->pServerName = ptr;
1773 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1774 ptr, outlen, NULL, NULL);
1775 ptr += len;
1776 outlen -= len;
1778 if (piW->pPrinterName) {
1779 piA->pPrinterName = ptr;
1780 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1781 ptr, outlen, NULL, NULL);
1782 ptr += len;
1783 outlen -= len;
1785 if (piW->pShareName) {
1786 piA->pShareName = ptr;
1787 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1788 ptr, outlen, NULL, NULL);
1789 ptr += len;
1790 outlen -= len;
1792 if (piW->pPortName) {
1793 piA->pPortName = ptr;
1794 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1795 ptr, outlen, NULL, NULL);
1796 ptr += len;
1797 outlen -= len;
1799 if (piW->pDriverName) {
1800 piA->pDriverName = ptr;
1801 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1802 ptr, outlen, NULL, NULL);
1803 ptr += len;
1804 outlen -= len;
1806 if (piW->pComment) {
1807 piA->pComment = ptr;
1808 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1809 ptr, outlen, NULL, NULL);
1810 ptr += len;
1811 outlen -= len;
1813 if (piW->pLocation) {
1814 piA->pLocation = ptr;
1815 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1816 ptr, outlen, NULL, NULL);
1817 ptr += len;
1818 outlen -= len;
1821 dmA = DEVMODEdupWtoA(piW->pDevMode);
1822 if (dmA) {
1823 /* align DEVMODEA to a DWORD boundary */
1824 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1825 ptr += len;
1826 outlen -= len;
1828 piA->pDevMode = (LPDEVMODEA) ptr;
1829 len = dmA->dmSize + dmA->dmDriverExtra;
1830 memcpy(ptr, dmA, len);
1831 HeapFree(GetProcessHeap(), 0, dmA);
1833 ptr += len;
1834 outlen -= len;
1837 if (piW->pSepFile) {
1838 piA->pSepFile = ptr;
1839 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1840 ptr, outlen, NULL, NULL);
1841 ptr += len;
1842 outlen -= len;
1844 if (piW->pPrintProcessor) {
1845 piA->pPrintProcessor = ptr;
1846 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1847 ptr, outlen, NULL, NULL);
1848 ptr += len;
1849 outlen -= len;
1851 if (piW->pDatatype) {
1852 piA->pDatatype = ptr;
1853 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1854 ptr, outlen, NULL, NULL);
1855 ptr += len;
1856 outlen -= len;
1858 if (piW->pParameters) {
1859 piA->pParameters = ptr;
1860 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1861 ptr, outlen, NULL, NULL);
1862 ptr += len;
1863 outlen -= len;
1865 if (piW->pSecurityDescriptor) {
1866 piA->pSecurityDescriptor = NULL;
1867 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1869 break;
1872 case 4:
1874 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1875 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1877 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1879 if (piW->pPrinterName) {
1880 piA->pPrinterName = ptr;
1881 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1882 ptr, outlen, NULL, NULL);
1883 ptr += len;
1884 outlen -= len;
1886 if (piW->pServerName) {
1887 piA->pServerName = ptr;
1888 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1889 ptr, outlen, NULL, NULL);
1890 ptr += len;
1891 outlen -= len;
1893 break;
1896 case 5:
1898 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1899 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1901 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1903 if (piW->pPrinterName) {
1904 piA->pPrinterName = ptr;
1905 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1906 ptr, outlen, NULL, NULL);
1907 ptr += len;
1908 outlen -= len;
1910 if (piW->pPortName) {
1911 piA->pPortName = ptr;
1912 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1913 ptr, outlen, NULL, NULL);
1914 ptr += len;
1915 outlen -= len;
1917 break;
1920 case 6: /* 6A and 6W are the same structure */
1921 break;
1923 case 7:
1925 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1926 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1928 TRACE("(%u) #%u\n", level, id);
1929 if (piW->pszObjectGUID) {
1930 piA->pszObjectGUID = ptr;
1931 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1932 ptr, outlen, NULL, NULL);
1933 ptr += len;
1934 outlen -= len;
1936 break;
1939 case 8:
1940 case 9:
1942 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1943 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1944 LPDEVMODEA dmA;
1946 TRACE("(%u) #%u\n", level, id);
1947 dmA = DEVMODEdupWtoA(piW->pDevMode);
1948 if (dmA) {
1949 /* align DEVMODEA to a DWORD boundary */
1950 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1951 ptr += len;
1952 outlen -= len;
1954 piA->pDevMode = (LPDEVMODEA) ptr;
1955 len = dmA->dmSize + dmA->dmDriverExtra;
1956 memcpy(ptr, dmA, len);
1957 HeapFree(GetProcessHeap(), 0, dmA);
1959 ptr += len;
1960 outlen -= len;
1963 break;
1966 default:
1967 FIXME("for level %u\n", level);
1969 pPrintersW += pi_sizeof[level];
1970 out += pi_sizeof[level];
1971 id++;
1975 /******************************************************************
1976 * convert_driverinfo_W_to_A [internal]
1979 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1980 DWORD level, DWORD outlen, DWORD numentries)
1982 DWORD id = 0;
1983 LPSTR ptr;
1984 INT len;
1986 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1988 len = di_sizeof[level] * numentries;
1989 ptr = (LPSTR) out + len;
1990 outlen -= len;
1992 /* copy the numbers of all PRINTER_INFO_* first */
1993 memcpy(out, pDriversW, len);
1995 #define COPY_STRING(fld) \
1996 { if (diW->fld){ \
1997 diA->fld = ptr; \
1998 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1999 ptr += len; outlen -= len;\
2001 #define COPY_MULTIZ_STRING(fld) \
2002 { LPWSTR p = diW->fld; if (p){ \
2003 diA->fld = ptr; \
2004 do {\
2005 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2006 ptr += len; outlen -= len; p += len;\
2008 while(len > 1 && outlen > 0); \
2011 while (id < numentries)
2013 switch (level)
2015 case 1:
2017 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
2018 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
2020 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2022 COPY_STRING(pName);
2023 break;
2025 case 2:
2027 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2028 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2030 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2032 COPY_STRING(pName);
2033 COPY_STRING(pEnvironment);
2034 COPY_STRING(pDriverPath);
2035 COPY_STRING(pDataFile);
2036 COPY_STRING(pConfigFile);
2037 break;
2039 case 3:
2041 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2042 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2044 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2046 COPY_STRING(pName);
2047 COPY_STRING(pEnvironment);
2048 COPY_STRING(pDriverPath);
2049 COPY_STRING(pDataFile);
2050 COPY_STRING(pConfigFile);
2051 COPY_STRING(pHelpFile);
2052 COPY_MULTIZ_STRING(pDependentFiles);
2053 COPY_STRING(pMonitorName);
2054 COPY_STRING(pDefaultDataType);
2055 break;
2057 case 4:
2059 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2060 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2062 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2064 COPY_STRING(pName);
2065 COPY_STRING(pEnvironment);
2066 COPY_STRING(pDriverPath);
2067 COPY_STRING(pDataFile);
2068 COPY_STRING(pConfigFile);
2069 COPY_STRING(pHelpFile);
2070 COPY_MULTIZ_STRING(pDependentFiles);
2071 COPY_STRING(pMonitorName);
2072 COPY_STRING(pDefaultDataType);
2073 COPY_MULTIZ_STRING(pszzPreviousNames);
2074 break;
2076 case 5:
2078 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2079 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2081 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2083 COPY_STRING(pName);
2084 COPY_STRING(pEnvironment);
2085 COPY_STRING(pDriverPath);
2086 COPY_STRING(pDataFile);
2087 COPY_STRING(pConfigFile);
2088 break;
2090 case 6:
2092 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2093 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2095 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2097 COPY_STRING(pName);
2098 COPY_STRING(pEnvironment);
2099 COPY_STRING(pDriverPath);
2100 COPY_STRING(pDataFile);
2101 COPY_STRING(pConfigFile);
2102 COPY_STRING(pHelpFile);
2103 COPY_MULTIZ_STRING(pDependentFiles);
2104 COPY_STRING(pMonitorName);
2105 COPY_STRING(pDefaultDataType);
2106 COPY_MULTIZ_STRING(pszzPreviousNames);
2107 COPY_STRING(pszMfgName);
2108 COPY_STRING(pszOEMUrl);
2109 COPY_STRING(pszHardwareID);
2110 COPY_STRING(pszProvider);
2111 break;
2113 case 8:
2115 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2116 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2118 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2120 COPY_STRING(pName);
2121 COPY_STRING(pEnvironment);
2122 COPY_STRING(pDriverPath);
2123 COPY_STRING(pDataFile);
2124 COPY_STRING(pConfigFile);
2125 COPY_STRING(pHelpFile);
2126 COPY_MULTIZ_STRING(pDependentFiles);
2127 COPY_STRING(pMonitorName);
2128 COPY_STRING(pDefaultDataType);
2129 COPY_MULTIZ_STRING(pszzPreviousNames);
2130 COPY_STRING(pszMfgName);
2131 COPY_STRING(pszOEMUrl);
2132 COPY_STRING(pszHardwareID);
2133 COPY_STRING(pszProvider);
2134 COPY_STRING(pszPrintProcessor);
2135 COPY_STRING(pszVendorSetup);
2136 COPY_MULTIZ_STRING(pszzColorProfiles);
2137 COPY_STRING(pszInfPath);
2138 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2139 break;
2143 default:
2144 FIXME("for level %u\n", level);
2147 pDriversW += di_sizeof[level];
2148 out += di_sizeof[level];
2149 id++;
2152 #undef COPY_STRING
2153 #undef COPY_MULTIZ_STRING
2157 /***********************************************************
2158 * printer_info_AtoW
2160 static void *printer_info_AtoW( const void *data, DWORD level )
2162 void *ret;
2163 UNICODE_STRING usBuffer;
2165 if (!data) return NULL;
2167 if (level < 1 || level > 9) return NULL;
2169 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2170 if (!ret) return NULL;
2172 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2174 switch (level)
2176 case 2:
2178 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2179 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2181 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2182 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2183 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2184 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2185 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2186 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2187 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2188 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2189 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2190 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2191 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2192 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2193 break;
2196 case 8:
2197 case 9:
2199 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2200 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2202 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2203 break;
2206 default:
2207 FIXME( "Unhandled level %d\n", level );
2208 HeapFree( GetProcessHeap(), 0, ret );
2209 return NULL;
2212 return ret;
2215 /***********************************************************
2216 * free_printer_info
2218 static void free_printer_info( void *data, DWORD level )
2220 if (!data) return;
2222 switch (level)
2224 case 2:
2226 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2228 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2229 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2230 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2231 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2232 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2233 HeapFree( GetProcessHeap(), 0, piW->pComment );
2234 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2235 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2236 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2237 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2238 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2239 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2240 break;
2243 case 8:
2244 case 9:
2246 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2248 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2249 break;
2252 default:
2253 FIXME( "Unhandled level %d\n", level );
2256 HeapFree( GetProcessHeap(), 0, data );
2257 return;
2260 /******************************************************************
2261 * DeviceCapabilities [WINSPOOL.@]
2262 * DeviceCapabilitiesA [WINSPOOL.@]
2265 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2266 LPSTR pOutput, LPDEVMODEA lpdm)
2268 INT ret;
2270 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice), debugstr_a(pPort), cap, pOutput, lpdm);
2272 if (!GDI_CallDeviceCapabilities16)
2274 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2275 (LPCSTR)104 );
2276 if (!GDI_CallDeviceCapabilities16) return -1;
2278 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2280 /* If DC_PAPERSIZE map POINT16s to POINTs */
2281 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2282 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2283 POINT *pt = (POINT *)pOutput;
2284 INT i;
2285 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2286 for(i = 0; i < ret; i++, pt++)
2288 pt->x = tmp[i].x;
2289 pt->y = tmp[i].y;
2291 HeapFree( GetProcessHeap(), 0, tmp );
2293 return ret;
2297 /*****************************************************************************
2298 * DeviceCapabilitiesW [WINSPOOL.@]
2300 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2303 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2304 WORD fwCapability, LPWSTR pOutput,
2305 const DEVMODEW *pDevMode)
2307 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2308 LPSTR pDeviceA = strdupWtoA(pDevice);
2309 LPSTR pPortA = strdupWtoA(pPort);
2310 INT ret;
2312 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability, pOutput, pDevMode);
2314 if(pOutput && (fwCapability == DC_BINNAMES ||
2315 fwCapability == DC_FILEDEPENDENCIES ||
2316 fwCapability == DC_PAPERNAMES)) {
2317 /* These need A -> W translation */
2318 INT size = 0, i;
2319 LPSTR pOutputA;
2320 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2321 dmA);
2322 if(ret == -1)
2323 return ret;
2324 switch(fwCapability) {
2325 case DC_BINNAMES:
2326 size = 24;
2327 break;
2328 case DC_PAPERNAMES:
2329 case DC_FILEDEPENDENCIES:
2330 size = 64;
2331 break;
2333 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2334 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2335 dmA);
2336 for(i = 0; i < ret; i++)
2337 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2338 pOutput + (i * size), size);
2339 HeapFree(GetProcessHeap(), 0, pOutputA);
2340 } else {
2341 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2342 (LPSTR)pOutput, dmA);
2344 HeapFree(GetProcessHeap(),0,pPortA);
2345 HeapFree(GetProcessHeap(),0,pDeviceA);
2346 HeapFree(GetProcessHeap(),0,dmA);
2347 return ret;
2350 /******************************************************************
2351 * DocumentPropertiesA [WINSPOOL.@]
2353 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2355 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2356 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2357 LPDEVMODEA pDevModeInput,DWORD fMode )
2359 LPSTR lpName = pDeviceName, dupname = NULL;
2360 static CHAR port[] = "LPT1:";
2361 LONG ret;
2363 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2364 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2367 if(!pDeviceName || !*pDeviceName) {
2368 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2369 if(!lpNameW) {
2370 ERR("no name from hPrinter?\n");
2371 SetLastError(ERROR_INVALID_HANDLE);
2372 return -1;
2374 lpName = dupname = strdupWtoA(lpNameW);
2377 if (!GDI_CallExtDeviceMode16)
2379 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2380 (LPCSTR)102 );
2381 if (!GDI_CallExtDeviceMode16) {
2382 ERR("No CallExtDeviceMode16?\n");
2383 ret = -1;
2384 goto end;
2387 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2388 pDevModeInput, NULL, fMode);
2390 end:
2391 HeapFree(GetProcessHeap(), 0, dupname);
2392 return ret;
2396 /*****************************************************************************
2397 * DocumentPropertiesW (WINSPOOL.@)
2399 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2401 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2402 LPWSTR pDeviceName,
2403 LPDEVMODEW pDevModeOutput,
2404 LPDEVMODEW pDevModeInput, DWORD fMode)
2407 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2408 LPDEVMODEA pDevModeInputA;
2409 LPDEVMODEA pDevModeOutputA = NULL;
2410 LONG ret;
2412 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2413 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2414 fMode);
2415 if(pDevModeOutput) {
2416 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2417 if(ret < 0) return ret;
2418 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2420 pDevModeInputA = (fMode & DM_IN_BUFFER) ? DEVMODEdupWtoA(pDevModeInput) : NULL;
2421 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2422 pDevModeInputA, fMode);
2423 if(pDevModeOutput) {
2424 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2425 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2427 if(fMode == 0 && ret > 0)
2428 ret += (CCHDEVICENAME + CCHFORMNAME);
2429 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2430 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2431 return ret;
2434 /*****************************************************************************
2435 * IsValidDevmodeA [WINSPOOL.@]
2437 * Validate a DEVMODE structure and fix errors if possible.
2440 BOOL WINAPI IsValidDevmodeA(PDEVMODEA pDevMode, SIZE_T size)
2442 FIXME("(%p,%ld): stub\n", pDevMode, size);
2444 if(!pDevMode)
2445 return FALSE;
2447 return TRUE;
2450 /*****************************************************************************
2451 * IsValidDevmodeW [WINSPOOL.@]
2453 * Validate a DEVMODE structure and fix errors if possible.
2456 BOOL WINAPI IsValidDevmodeW(PDEVMODEW dm, SIZE_T size)
2458 static const struct
2460 DWORD flag;
2461 SIZE_T size;
2462 } map[] =
2464 #define F_SIZE(field) FIELD_OFFSET(DEVMODEW, field) + sizeof(dm->field)
2465 { DM_ORIENTATION, F_SIZE(u1.s1.dmOrientation) },
2466 { DM_PAPERSIZE, F_SIZE(u1.s1.dmPaperSize) },
2467 { DM_PAPERLENGTH, F_SIZE(u1.s1.dmPaperLength) },
2468 { DM_PAPERWIDTH, F_SIZE(u1.s1.dmPaperWidth) },
2469 { DM_SCALE, F_SIZE(u1.s1.dmScale) },
2470 { DM_COPIES, F_SIZE(u1.s1.dmCopies) },
2471 { DM_DEFAULTSOURCE, F_SIZE(u1.s1.dmDefaultSource) },
2472 { DM_PRINTQUALITY, F_SIZE(u1.s1.dmPrintQuality) },
2473 { DM_POSITION, F_SIZE(u1.s2.dmPosition) },
2474 { DM_DISPLAYORIENTATION, F_SIZE(u1.s2.dmDisplayOrientation) },
2475 { DM_DISPLAYFIXEDOUTPUT, F_SIZE(u1.s2.dmDisplayFixedOutput) },
2476 { DM_COLOR, F_SIZE(dmColor) },
2477 { DM_DUPLEX, F_SIZE(dmDuplex) },
2478 { DM_YRESOLUTION, F_SIZE(dmYResolution) },
2479 { DM_TTOPTION, F_SIZE(dmTTOption) },
2480 { DM_COLLATE, F_SIZE(dmCollate) },
2481 { DM_FORMNAME, F_SIZE(dmFormName) },
2482 { DM_LOGPIXELS, F_SIZE(dmLogPixels) },
2483 { DM_BITSPERPEL, F_SIZE(dmBitsPerPel) },
2484 { DM_PELSWIDTH, F_SIZE(dmPelsWidth) },
2485 { DM_PELSHEIGHT, F_SIZE(dmPelsHeight) },
2486 { DM_DISPLAYFLAGS, F_SIZE(u2.dmDisplayFlags) },
2487 { DM_NUP, F_SIZE(u2.dmNup) },
2488 { DM_DISPLAYFREQUENCY, F_SIZE(dmDisplayFrequency) },
2489 { DM_ICMMETHOD, F_SIZE(dmICMMethod) },
2490 { DM_ICMINTENT, F_SIZE(dmICMIntent) },
2491 { DM_MEDIATYPE, F_SIZE(dmMediaType) },
2492 { DM_DITHERTYPE, F_SIZE(dmDitherType) },
2493 { DM_PANNINGWIDTH, F_SIZE(dmPanningWidth) },
2494 { DM_PANNINGHEIGHT, F_SIZE(dmPanningHeight) }
2495 #undef F_SIZE
2497 int i;
2499 if (!dm) return FALSE;
2500 if (size < FIELD_OFFSET(DEVMODEW, dmFields) + sizeof(dm->dmFields)) return FALSE;
2502 for (i = 0; i < ARRAY_SIZE(map); i++)
2503 if ((dm->dmFields & map[i].flag) && size < map[i].size)
2504 return FALSE;
2506 return TRUE;
2509 /******************************************************************
2510 * OpenPrinterA [WINSPOOL.@]
2512 * See OpenPrinterW.
2515 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2516 LPPRINTER_DEFAULTSA pDefault)
2518 UNICODE_STRING lpPrinterNameW;
2519 UNICODE_STRING usBuffer;
2520 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2521 PWSTR pwstrPrinterNameW;
2522 BOOL ret;
2524 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName), phPrinter, pDefault);
2526 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2528 if(pDefault) {
2529 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2530 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2531 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2532 pDefaultW = &DefaultW;
2534 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2535 if(pDefault) {
2536 RtlFreeUnicodeString(&usBuffer);
2537 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2539 RtlFreeUnicodeString(&lpPrinterNameW);
2540 return ret;
2543 /******************************************************************
2544 * OpenPrinterW [WINSPOOL.@]
2546 * Open a Printer / Printserver or a Printer-Object
2548 * PARAMS
2549 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2550 * phPrinter [O] The resulting Handle is stored here
2551 * pDefault [I] PTR to Default Printer Settings or NULL
2553 * RETURNS
2554 * Success: TRUE
2555 * Failure: FALSE
2557 * NOTES
2558 * lpPrinterName is one of:
2559 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2560 *| Printer: "PrinterName"
2561 *| Printer-Object: "PrinterName,Job xxx"
2562 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2563 *| XcvPort: "Servername,XcvPort PortName"
2565 * BUGS
2566 *| Printer-Object not supported
2567 *| pDefaults is ignored
2570 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2572 HKEY key;
2574 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2576 if(!phPrinter) {
2577 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2578 SetLastError(ERROR_INVALID_PARAMETER);
2579 return FALSE;
2582 /* Get the unique handle of the printer or Printserver */
2583 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2585 if (*phPrinter && WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key ) == ERROR_SUCCESS)
2587 DWORD deleting = 0, size = sizeof( deleting ), type;
2588 DWORD status;
2589 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2590 WaitForSingleObject( init_mutex, INFINITE );
2591 status = get_dword_from_reg( key, StatusW );
2592 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2593 ReleaseMutex( init_mutex );
2594 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2595 update_driver( *phPrinter );
2596 RegCloseKey( key );
2599 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2600 return (*phPrinter != 0);
2603 /******************************************************************
2604 * AddMonitorA [WINSPOOL.@]
2606 * See AddMonitorW.
2609 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2611 LPWSTR nameW = NULL;
2612 INT len;
2613 BOOL res;
2614 LPMONITOR_INFO_2A mi2a;
2615 MONITOR_INFO_2W mi2w;
2617 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2618 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2619 debugstr_a(mi2a ? mi2a->pName : NULL),
2620 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2621 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2623 if (Level != 2) {
2624 SetLastError(ERROR_INVALID_LEVEL);
2625 return FALSE;
2628 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2629 if (mi2a == NULL) {
2630 return FALSE;
2633 if (pName) {
2634 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2635 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2636 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2639 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2640 if (mi2a->pName) {
2641 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2642 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2643 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2645 if (mi2a->pEnvironment) {
2646 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2647 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2648 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2650 if (mi2a->pDLLName) {
2651 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2652 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2653 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2656 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2658 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2659 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2660 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2662 HeapFree(GetProcessHeap(), 0, nameW);
2663 return (res);
2666 /******************************************************************************
2667 * AddMonitorW [WINSPOOL.@]
2669 * Install a Printmonitor
2671 * PARAMS
2672 * pName [I] Servername or NULL (local Computer)
2673 * Level [I] Structure-Level (Must be 2)
2674 * pMonitors [I] PTR to MONITOR_INFO_2
2676 * RETURNS
2677 * Success: TRUE
2678 * Failure: FALSE
2680 * NOTES
2681 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2684 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2686 LPMONITOR_INFO_2W mi2w;
2688 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2689 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2690 debugstr_w(mi2w ? mi2w->pName : NULL),
2691 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2692 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2694 if ((backend == NULL) && !load_backend()) return FALSE;
2696 if (Level != 2) {
2697 SetLastError(ERROR_INVALID_LEVEL);
2698 return FALSE;
2701 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2702 if (mi2w == NULL) {
2703 return FALSE;
2706 return backend->fpAddMonitor(pName, Level, pMonitors);
2709 /******************************************************************
2710 * DeletePrinterDriverA [WINSPOOL.@]
2713 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2715 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2718 /******************************************************************
2719 * DeletePrinterDriverW [WINSPOOL.@]
2722 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2724 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2727 /******************************************************************
2728 * DeleteMonitorA [WINSPOOL.@]
2730 * See DeleteMonitorW.
2733 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2735 LPWSTR nameW = NULL;
2736 LPWSTR EnvironmentW = NULL;
2737 LPWSTR MonitorNameW = NULL;
2738 BOOL res;
2739 INT len;
2741 if (pName) {
2742 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2743 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2744 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2747 if (pEnvironment) {
2748 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2749 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2750 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2752 if (pMonitorName) {
2753 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2754 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2755 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2758 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2760 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2761 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2762 HeapFree(GetProcessHeap(), 0, nameW);
2763 return (res);
2766 /******************************************************************
2767 * DeleteMonitorW [WINSPOOL.@]
2769 * Delete a specific Printmonitor from a Printing-Environment
2771 * PARAMS
2772 * pName [I] Servername or NULL (local Computer)
2773 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2774 * pMonitorName [I] Name of the Monitor, that should be deleted
2776 * RETURNS
2777 * Success: TRUE
2778 * Failure: FALSE
2780 * NOTES
2781 * pEnvironment is ignored in Windows for the local Computer.
2784 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2787 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2788 debugstr_w(pMonitorName));
2790 if ((backend == NULL) && !load_backend()) return FALSE;
2792 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2796 /******************************************************************
2797 * DeletePortA [WINSPOOL.@]
2799 * See DeletePortW.
2802 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2804 LPWSTR nameW = NULL;
2805 LPWSTR portW = NULL;
2806 INT len;
2807 DWORD res;
2809 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2811 /* convert servername to unicode */
2812 if (pName) {
2813 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2814 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2815 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2818 /* convert portname to unicode */
2819 if (pPortName) {
2820 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2821 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2822 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2825 res = DeletePortW(nameW, hWnd, portW);
2826 HeapFree(GetProcessHeap(), 0, nameW);
2827 HeapFree(GetProcessHeap(), 0, portW);
2828 return res;
2831 /******************************************************************
2832 * DeletePortW [WINSPOOL.@]
2834 * Delete a specific Port
2836 * PARAMS
2837 * pName [I] Servername or NULL (local Computer)
2838 * hWnd [I] Handle to parent Window for the Dialog-Box
2839 * pPortName [I] Name of the Port, that should be deleted
2841 * RETURNS
2842 * Success: TRUE
2843 * Failure: FALSE
2846 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2848 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2850 if ((backend == NULL) && !load_backend()) return FALSE;
2852 if (!pPortName) {
2853 SetLastError(RPC_X_NULL_REF_POINTER);
2854 return FALSE;
2857 return backend->fpDeletePort(pName, hWnd, pPortName);
2860 /******************************************************************************
2861 * WritePrinter [WINSPOOL.@]
2863 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2865 opened_printer_t *printer;
2866 BOOL ret = FALSE;
2868 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2870 EnterCriticalSection(&printer_handles_cs);
2871 printer = get_opened_printer(hPrinter);
2872 if(!printer)
2874 SetLastError(ERROR_INVALID_HANDLE);
2875 goto end;
2878 if(!printer->doc)
2880 SetLastError(ERROR_SPL_NO_STARTDOC);
2881 goto end;
2884 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2885 end:
2886 LeaveCriticalSection(&printer_handles_cs);
2887 return ret;
2890 /*****************************************************************************
2891 * AddFormA [WINSPOOL.@]
2893 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2895 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2896 return TRUE;
2899 /*****************************************************************************
2900 * AddFormW [WINSPOOL.@]
2902 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2904 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2905 return TRUE;
2908 /*****************************************************************************
2909 * AddJobA [WINSPOOL.@]
2911 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2913 BOOL ret;
2914 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2915 DWORD needed;
2917 if(Level != 1) {
2918 SetLastError(ERROR_INVALID_LEVEL);
2919 return FALSE;
2922 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2924 if(ret) {
2925 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2926 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2927 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2928 if(*pcbNeeded > cbBuf) {
2929 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2930 ret = FALSE;
2931 } else {
2932 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2933 addjobA->JobId = addjobW->JobId;
2934 addjobA->Path = (char *)(addjobA + 1);
2935 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2938 return ret;
2941 /*****************************************************************************
2942 * AddJobW [WINSPOOL.@]
2944 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2946 opened_printer_t *printer;
2947 job_t *job;
2948 BOOL ret = FALSE;
2949 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2950 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2951 WCHAR path[MAX_PATH], filename[MAX_PATH];
2952 DWORD len;
2953 ADDJOB_INFO_1W *addjob;
2955 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2957 EnterCriticalSection(&printer_handles_cs);
2959 printer = get_opened_printer(hPrinter);
2961 if(!printer) {
2962 SetLastError(ERROR_INVALID_HANDLE);
2963 goto end;
2966 if(Level != 1) {
2967 SetLastError(ERROR_INVALID_LEVEL);
2968 goto end;
2971 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2972 if(!job)
2973 goto end;
2975 job->job_id = InterlockedIncrement(&next_job_id);
2977 len = GetSystemDirectoryW(path, ARRAY_SIZE(path));
2978 if(path[len - 1] != '\\')
2979 path[len++] = '\\';
2980 memcpy(path + len, spool_path, sizeof(spool_path));
2981 sprintfW(filename, fmtW, path, job->job_id);
2983 len = strlenW(filename);
2984 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2985 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2986 job->portname = NULL;
2987 job->document_title = strdupW(default_doc_title);
2988 job->printer_name = strdupW(printer->name);
2989 job->devmode = dup_devmode( printer->devmode );
2990 list_add_tail(&printer->queue->jobs, &job->entry);
2992 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2993 if(*pcbNeeded <= cbBuf) {
2994 addjob = (ADDJOB_INFO_1W*)pData;
2995 addjob->JobId = job->job_id;
2996 addjob->Path = (WCHAR *)(addjob + 1);
2997 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2998 ret = TRUE;
2999 } else
3000 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3002 end:
3003 LeaveCriticalSection(&printer_handles_cs);
3004 return ret;
3007 /*****************************************************************************
3008 * GetPrintProcessorDirectoryA [WINSPOOL.@]
3010 * Return the PATH for the Print-Processors
3012 * See GetPrintProcessorDirectoryW.
3016 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
3017 DWORD level, LPBYTE Info,
3018 DWORD cbBuf, LPDWORD pcbNeeded)
3020 LPWSTR serverW = NULL;
3021 LPWSTR envW = NULL;
3022 BOOL ret;
3023 INT len;
3025 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
3026 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
3029 if (server) {
3030 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
3031 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3032 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
3035 if (env) {
3036 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
3037 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3038 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
3041 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
3042 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
3044 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
3045 cbBuf, pcbNeeded);
3047 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
3048 cbBuf, NULL, NULL) > 0;
3051 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3052 HeapFree(GetProcessHeap(), 0, envW);
3053 HeapFree(GetProcessHeap(), 0, serverW);
3054 return ret;
3057 /*****************************************************************************
3058 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3060 * Return the PATH for the Print-Processors
3062 * PARAMS
3063 * server [I] Servername (NT only) or NULL (local Computer)
3064 * env [I] Printing-Environment (see below) or NULL (Default)
3065 * level [I] Structure-Level (must be 1)
3066 * Info [O] PTR to Buffer that receives the Result
3067 * cbBuf [I] Size of Buffer at "Info"
3068 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3069 * required for the Buffer at "Info"
3071 * RETURNS
3072 * Success: TRUE and in pcbNeeded the Bytes used in Info
3073 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3074 * if cbBuf is too small
3076 * Native Values returned in Info on Success:
3077 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3078 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3079 *| win9x(Windows 4.0): "%winsysdir%"
3081 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3083 * BUGS
3084 * Only NULL or "" is supported for server
3087 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3088 DWORD level, LPBYTE Info,
3089 DWORD cbBuf, LPDWORD pcbNeeded)
3092 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3093 Info, cbBuf, pcbNeeded);
3095 if ((backend == NULL) && !load_backend()) return FALSE;
3097 if (level != 1) {
3098 /* (Level != 1) is ignored in win9x */
3099 SetLastError(ERROR_INVALID_LEVEL);
3100 return FALSE;
3103 if (pcbNeeded == NULL) {
3104 /* (pcbNeeded == NULL) is ignored in win9x */
3105 SetLastError(RPC_X_NULL_REF_POINTER);
3106 return FALSE;
3109 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3112 /*****************************************************************************
3113 * WINSPOOL_OpenDriverReg [internal]
3115 * opens the registry for the printer drivers depending on the given input
3116 * variable pEnvironment
3118 * RETURNS:
3119 * the opened hkey on success
3120 * NULL on error
3122 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3124 HKEY retval = NULL;
3125 LPWSTR buffer;
3126 const printenv_t * env;
3128 TRACE("(%s)\n", debugstr_w(pEnvironment));
3130 env = validate_envW(pEnvironment);
3131 if (!env) return NULL;
3133 buffer = HeapAlloc( GetProcessHeap(), 0,
3134 (strlenW(DriversW) + strlenW(env->envname) +
3135 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3136 if(buffer) {
3137 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3138 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3139 HeapFree(GetProcessHeap(), 0, buffer);
3141 return retval;
3144 /*****************************************************************************
3145 * set_devices_and_printerports [internal]
3147 * set the [Devices] and [PrinterPorts] entries for a printer.
3150 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3152 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3153 WCHAR *devline;
3154 HKEY hkey;
3156 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3158 /* FIXME: the driver must change to "winspool" */
3159 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3160 if (devline) {
3161 lstrcpyW(devline, driver_nt);
3162 lstrcatW(devline, commaW);
3163 lstrcatW(devline, pi->pPortName);
3165 TRACE("using %s\n", debugstr_w(devline));
3166 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3167 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3168 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3169 RegCloseKey(hkey);
3172 lstrcatW(devline, timeout_15_45);
3173 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3174 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3175 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3176 RegCloseKey(hkey);
3178 HeapFree(GetProcessHeap(), 0, devline);
3182 /*****************************************************************************
3183 * AddPrinterW [WINSPOOL.@]
3185 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3187 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3188 LPDEVMODEW dm;
3189 HANDLE retval;
3190 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3191 LONG size;
3193 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3195 if(pName && *pName) {
3196 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3197 SetLastError(ERROR_INVALID_PARAMETER);
3198 return 0;
3200 if(Level != 2) {
3201 ERR("Level = %d, unsupported!\n", Level);
3202 SetLastError(ERROR_INVALID_LEVEL);
3203 return 0;
3205 if(!pPrinter) {
3206 SetLastError(ERROR_INVALID_PARAMETER);
3207 return 0;
3209 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3210 ERROR_SUCCESS) {
3211 ERR("Can't create Printers key\n");
3212 return 0;
3214 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3215 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3216 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3217 RegCloseKey(hkeyPrinter);
3218 RegCloseKey(hkeyPrinters);
3219 return 0;
3221 RegCloseKey(hkeyPrinter);
3223 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3224 if(!hkeyDrivers) {
3225 ERR("Can't create Drivers key\n");
3226 RegCloseKey(hkeyPrinters);
3227 return 0;
3229 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3230 ERROR_SUCCESS) {
3231 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3232 RegCloseKey(hkeyPrinters);
3233 RegCloseKey(hkeyDrivers);
3234 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3235 return 0;
3237 RegCloseKey(hkeyDriver);
3238 RegCloseKey(hkeyDrivers);
3240 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3241 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3242 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3243 RegCloseKey(hkeyPrinters);
3244 return 0;
3247 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3248 ERROR_SUCCESS) {
3249 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3250 SetLastError(ERROR_INVALID_PRINTER_NAME);
3251 RegCloseKey(hkeyPrinters);
3252 return 0;
3255 set_devices_and_printerports(pi);
3257 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3258 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3259 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3260 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3261 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3262 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3263 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3264 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3265 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3266 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3267 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3268 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3269 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3270 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3271 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3272 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3273 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3274 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3276 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3278 if (size < 0)
3280 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3281 size = sizeof(DEVMODEW);
3283 if(pi->pDevMode)
3284 dm = pi->pDevMode;
3285 else
3287 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3288 dm->dmSize = size;
3289 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3291 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3292 HeapFree( GetProcessHeap(), 0, dm );
3293 dm = NULL;
3295 else
3297 /* set devmode to printer name */
3298 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3302 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3303 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3305 RegCloseKey(hkeyPrinter);
3306 RegCloseKey(hkeyPrinters);
3307 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3308 ERR("OpenPrinter failing\n");
3309 return 0;
3311 return retval;
3314 /*****************************************************************************
3315 * AddPrinterA [WINSPOOL.@]
3317 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3319 UNICODE_STRING pNameW;
3320 PWSTR pwstrNameW;
3321 PRINTER_INFO_2W *piW;
3322 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3323 HANDLE ret;
3325 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3326 if(Level != 2) {
3327 ERR("Level = %d, unsupported!\n", Level);
3328 SetLastError(ERROR_INVALID_LEVEL);
3329 return 0;
3331 pwstrNameW = asciitounicode(&pNameW,pName);
3332 piW = printer_info_AtoW( piA, Level );
3334 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3336 free_printer_info( piW, Level );
3337 RtlFreeUnicodeString(&pNameW);
3338 return ret;
3342 /*****************************************************************************
3343 * ClosePrinter [WINSPOOL.@]
3345 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3347 UINT_PTR i = (UINT_PTR)hPrinter;
3348 opened_printer_t *printer = NULL;
3350 TRACE("(%p)\n", hPrinter);
3352 EnterCriticalSection(&printer_handles_cs);
3354 if ((i > 0) && (i <= nb_printer_handles))
3355 printer = printer_handles[i - 1];
3358 if(printer)
3360 struct list *cursor, *cursor2;
3362 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3364 if(printer->doc)
3365 EndDocPrinter(hPrinter);
3367 if(InterlockedDecrement(&printer->queue->ref) == 0)
3369 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3371 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3372 ScheduleJob(hPrinter, job->job_id);
3374 HeapFree(GetProcessHeap(), 0, printer->queue);
3377 if (printer->backend_printer) {
3378 backend->fpClosePrinter(printer->backend_printer);
3381 free_printer_entry( printer );
3382 printer_handles[i - 1] = NULL;
3383 LeaveCriticalSection(&printer_handles_cs);
3384 return TRUE;
3387 LeaveCriticalSection(&printer_handles_cs);
3388 SetLastError(ERROR_INVALID_HANDLE);
3389 return FALSE;
3392 /*****************************************************************************
3393 * DeleteFormA [WINSPOOL.@]
3395 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3397 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3398 return TRUE;
3401 /*****************************************************************************
3402 * DeleteFormW [WINSPOOL.@]
3404 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3406 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3407 return TRUE;
3410 /*****************************************************************************
3411 * DeletePrinter [WINSPOOL.@]
3413 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3415 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3416 HKEY hkeyPrinters, hkey;
3417 WCHAR def[MAX_PATH];
3418 DWORD size = ARRAY_SIZE(def);
3420 if(!lpNameW) {
3421 SetLastError(ERROR_INVALID_HANDLE);
3422 return FALSE;
3424 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3425 RegDeleteTreeW(hkeyPrinters, lpNameW);
3426 RegCloseKey(hkeyPrinters);
3429 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3430 RegDeleteValueW(hkey, lpNameW);
3431 RegCloseKey(hkey);
3434 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3435 RegDeleteValueW(hkey, lpNameW);
3436 RegCloseKey(hkey);
3439 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3441 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3443 RegDeleteValueW( hkey, deviceW );
3444 RegCloseKey( hkey );
3446 SetDefaultPrinterW( NULL );
3449 return TRUE;
3452 /*****************************************************************************
3453 * SetPrinterA [WINSPOOL.@]
3455 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3457 BYTE *dataW = data;
3458 BOOL ret;
3460 if (level != 0)
3462 dataW = printer_info_AtoW( data, level );
3463 if (!dataW) return FALSE;
3466 ret = SetPrinterW( printer, level, dataW, command );
3468 if (dataW != data) free_printer_info( dataW, level );
3470 return ret;
3473 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3475 set_reg_szW( key, NameW, pi->pPrinterName );
3476 set_reg_szW( key, Share_NameW, pi->pShareName );
3477 set_reg_szW( key, PortW, pi->pPortName );
3478 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3479 set_reg_szW( key, DescriptionW, pi->pComment );
3480 set_reg_szW( key, LocationW, pi->pLocation );
3482 if (pi->pDevMode)
3483 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3485 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3486 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3487 set_reg_szW( key, DatatypeW, pi->pDatatype );
3488 set_reg_szW( key, ParametersW, pi->pParameters );
3490 set_reg_DWORD( key, AttributesW, pi->Attributes );
3491 set_reg_DWORD( key, PriorityW, pi->Priority );
3492 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3493 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3494 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3497 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3499 if (!pi->pDevMode) return FALSE;
3501 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3502 return TRUE;
3505 /******************************************************************************
3506 * SetPrinterW [WINSPOOL.@]
3508 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3510 HKEY key;
3511 BOOL ret = FALSE;
3513 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3515 if (command != 0) FIXME( "Ignoring command %d\n", command );
3517 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3518 return FALSE;
3520 switch (level)
3522 case 2:
3524 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3525 set_printer_2( key, pi2 );
3526 ret = TRUE;
3527 break;
3530 case 8:
3531 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
3532 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3533 /* fall through */
3534 case 9:
3536 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3537 ret = set_printer_9( key, pi );
3538 break;
3541 default:
3542 FIXME( "Unimplemented level %d\n", level );
3543 SetLastError( ERROR_INVALID_LEVEL );
3546 RegCloseKey( key );
3547 return ret;
3550 /*****************************************************************************
3551 * SetJobA [WINSPOOL.@]
3553 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3554 LPBYTE pJob, DWORD Command)
3556 BOOL ret;
3557 LPBYTE JobW;
3558 UNICODE_STRING usBuffer;
3560 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3562 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3563 are all ignored by SetJob, so we don't bother copying them */
3564 switch(Level)
3566 case 0:
3567 JobW = NULL;
3568 break;
3569 case 1:
3571 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3572 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3574 JobW = (LPBYTE)info1W;
3575 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3576 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3577 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3578 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3579 info1W->Status = info1A->Status;
3580 info1W->Priority = info1A->Priority;
3581 info1W->Position = info1A->Position;
3582 info1W->PagesPrinted = info1A->PagesPrinted;
3583 break;
3585 case 2:
3587 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3588 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3590 JobW = (LPBYTE)info2W;
3591 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3592 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3593 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3594 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3595 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3596 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3597 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3598 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3599 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3600 info2W->Status = info2A->Status;
3601 info2W->Priority = info2A->Priority;
3602 info2W->Position = info2A->Position;
3603 info2W->StartTime = info2A->StartTime;
3604 info2W->UntilTime = info2A->UntilTime;
3605 info2W->PagesPrinted = info2A->PagesPrinted;
3606 break;
3608 case 3:
3609 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3610 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3611 break;
3612 default:
3613 SetLastError(ERROR_INVALID_LEVEL);
3614 return FALSE;
3617 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3619 switch(Level)
3621 case 1:
3623 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3624 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3625 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3626 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3627 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3628 break;
3630 case 2:
3632 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3633 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3634 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3635 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3636 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3637 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3638 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3639 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3640 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3641 break;
3644 HeapFree(GetProcessHeap(), 0, JobW);
3646 return ret;
3649 /*****************************************************************************
3650 * SetJobW [WINSPOOL.@]
3652 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3653 LPBYTE pJob, DWORD Command)
3655 BOOL ret = FALSE;
3656 job_t *job;
3658 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3659 FIXME("Ignoring everything other than document title\n");
3661 EnterCriticalSection(&printer_handles_cs);
3662 job = get_job(hPrinter, JobId);
3663 if(!job)
3664 goto end;
3666 switch(Level)
3668 case 0:
3669 break;
3670 case 1:
3672 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3673 HeapFree(GetProcessHeap(), 0, job->document_title);
3674 job->document_title = strdupW(info1->pDocument);
3675 break;
3677 case 2:
3679 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3680 HeapFree(GetProcessHeap(), 0, job->document_title);
3681 job->document_title = strdupW(info2->pDocument);
3682 HeapFree(GetProcessHeap(), 0, job->devmode);
3683 job->devmode = dup_devmode( info2->pDevMode );
3684 break;
3686 case 3:
3687 break;
3688 default:
3689 SetLastError(ERROR_INVALID_LEVEL);
3690 goto end;
3692 ret = TRUE;
3693 end:
3694 LeaveCriticalSection(&printer_handles_cs);
3695 return ret;
3698 /*****************************************************************************
3699 * EndDocPrinter [WINSPOOL.@]
3701 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3703 opened_printer_t *printer;
3704 BOOL ret = FALSE;
3705 TRACE("(%p)\n", hPrinter);
3707 EnterCriticalSection(&printer_handles_cs);
3709 printer = get_opened_printer(hPrinter);
3710 if(!printer)
3712 SetLastError(ERROR_INVALID_HANDLE);
3713 goto end;
3716 if(!printer->doc)
3718 SetLastError(ERROR_SPL_NO_STARTDOC);
3719 goto end;
3722 CloseHandle(printer->doc->hf);
3723 ScheduleJob(hPrinter, printer->doc->job_id);
3724 HeapFree(GetProcessHeap(), 0, printer->doc);
3725 printer->doc = NULL;
3726 ret = TRUE;
3727 end:
3728 LeaveCriticalSection(&printer_handles_cs);
3729 return ret;
3732 /*****************************************************************************
3733 * EndPagePrinter [WINSPOOL.@]
3735 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3737 FIXME("(%p): stub\n", hPrinter);
3738 return TRUE;
3741 /*****************************************************************************
3742 * StartDocPrinterA [WINSPOOL.@]
3744 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3746 UNICODE_STRING usBuffer;
3747 DOC_INFO_2W doc2W;
3748 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3749 DWORD ret;
3751 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3752 or one (DOC_INFO_3) extra DWORDs */
3754 switch(Level) {
3755 case 2:
3756 doc2W.JobId = doc2->JobId;
3757 /* fall through */
3758 case 3:
3759 doc2W.dwMode = doc2->dwMode;
3760 /* fall through */
3761 case 1:
3762 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3763 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3764 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3765 break;
3767 default:
3768 SetLastError(ERROR_INVALID_LEVEL);
3769 return FALSE;
3772 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3774 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3775 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3776 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3778 return ret;
3781 /*****************************************************************************
3782 * StartDocPrinterW [WINSPOOL.@]
3784 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3786 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3787 opened_printer_t *printer;
3788 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3789 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3790 JOB_INFO_1W job_info;
3791 DWORD needed, ret = 0;
3792 HANDLE hf;
3793 WCHAR *filename;
3794 job_t *job;
3796 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3797 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3798 debugstr_w(doc->pDatatype));
3800 if(Level < 1 || Level > 3)
3802 SetLastError(ERROR_INVALID_LEVEL);
3803 return 0;
3806 EnterCriticalSection(&printer_handles_cs);
3807 printer = get_opened_printer(hPrinter);
3808 if(!printer)
3810 SetLastError(ERROR_INVALID_HANDLE);
3811 goto end;
3814 if(printer->doc)
3816 SetLastError(ERROR_INVALID_PRINTER_STATE);
3817 goto end;
3820 /* Even if we're printing to a file we still add a print job, we'll
3821 just ignore the spool file name */
3823 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3825 ERR("AddJob failed gle %u\n", GetLastError());
3826 goto end;
3829 /* use pOutputFile only, when it is a real filename */
3830 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3831 filename = doc->pOutputFile;
3832 else
3833 filename = addjob->Path;
3835 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3836 if(hf == INVALID_HANDLE_VALUE)
3837 goto end;
3839 memset(&job_info, 0, sizeof(job_info));
3840 job_info.pDocument = doc->pDocName;
3841 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3843 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3844 printer->doc->hf = hf;
3845 ret = printer->doc->job_id = addjob->JobId;
3846 job = get_job(hPrinter, ret);
3847 job->portname = strdupW(doc->pOutputFile);
3849 end:
3850 LeaveCriticalSection(&printer_handles_cs);
3852 return ret;
3855 /*****************************************************************************
3856 * StartPagePrinter [WINSPOOL.@]
3858 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3860 FIXME("(%p): stub\n", hPrinter);
3861 return TRUE;
3864 /*****************************************************************************
3865 * GetFormA [WINSPOOL.@]
3867 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3868 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3870 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3871 Level,pForm,cbBuf,pcbNeeded);
3872 return FALSE;
3875 /*****************************************************************************
3876 * GetFormW [WINSPOOL.@]
3878 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3879 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3881 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3882 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3883 return FALSE;
3886 /*****************************************************************************
3887 * SetFormA [WINSPOOL.@]
3889 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3890 LPBYTE pForm)
3892 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3893 return FALSE;
3896 /*****************************************************************************
3897 * SetFormW [WINSPOOL.@]
3899 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3900 LPBYTE pForm)
3902 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3903 return FALSE;
3906 /*****************************************************************************
3907 * ReadPrinter [WINSPOOL.@]
3909 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3910 LPDWORD pNoBytesRead)
3912 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3913 return FALSE;
3916 /*****************************************************************************
3917 * ResetPrinterA [WINSPOOL.@]
3919 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3921 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3922 return FALSE;
3925 /*****************************************************************************
3926 * ResetPrinterW [WINSPOOL.@]
3928 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3930 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3931 return FALSE;
3934 /*****************************************************************************
3935 * get_filename_from_reg [internal]
3937 * Get ValueName from hkey storing result in out
3938 * when the Value in the registry has only a filename, use driverdir as prefix
3939 * outlen is space left in out
3940 * String is stored either as unicode or ascii
3944 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3945 LPBYTE out, DWORD outlen, LPDWORD needed)
3947 WCHAR filename[MAX_PATH];
3948 DWORD size;
3949 DWORD type;
3950 LONG ret;
3951 LPWSTR buffer = filename;
3952 LPWSTR ptr;
3954 *needed = 0;
3955 size = sizeof(filename);
3956 buffer[0] = '\0';
3957 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3958 if (ret == ERROR_MORE_DATA) {
3959 TRACE("need dynamic buffer: %u\n", size);
3960 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3961 if (!buffer) {
3962 /* No Memory is bad */
3963 return FALSE;
3965 buffer[0] = '\0';
3966 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3969 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3970 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3971 return FALSE;
3974 ptr = buffer;
3975 while (ptr) {
3976 /* do we have a full path ? */
3977 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3978 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3980 if (!ret) {
3981 /* we must build the full Path */
3982 *needed += dirlen;
3983 if ((out) && (outlen > dirlen)) {
3984 lstrcpyW((LPWSTR)out, driverdir);
3985 out += dirlen;
3986 outlen -= dirlen;
3988 else
3989 out = NULL;
3992 /* write the filename */
3993 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3994 if ((out) && (outlen >= size)) {
3995 lstrcpyW((LPWSTR)out, ptr);
3996 out += size;
3997 outlen -= size;
3999 else
4000 out = NULL;
4001 *needed += size;
4002 ptr += lstrlenW(ptr)+1;
4003 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
4006 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
4008 /* write the multisz-termination */
4009 if (type == REG_MULTI_SZ) {
4010 size = sizeof(WCHAR);
4012 *needed += size;
4013 if (out && (outlen >= size)) {
4014 memset (out, 0, size);
4017 return TRUE;
4020 /*****************************************************************************
4021 * WINSPOOL_GetStringFromReg
4023 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4024 * String is stored as unicode.
4026 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
4027 DWORD buflen, DWORD *needed)
4029 DWORD sz = buflen, type;
4030 LONG ret;
4032 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4033 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
4034 WARN("Got ret = %d\n", ret);
4035 *needed = 0;
4036 return FALSE;
4038 /* add space for terminating '\0' */
4039 sz += sizeof(WCHAR);
4040 *needed = sz;
4042 if (ptr)
4043 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
4045 return TRUE;
4048 /*****************************************************************************
4049 * WINSPOOL_GetDefaultDevMode
4051 * Get a default DevMode values for wineps.
4053 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr, DWORD buflen, DWORD *needed)
4055 static const WCHAR winepsW[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4057 if (buflen >= sizeof(DEVMODEW))
4059 DEVMODEW *dm = (DEVMODEW *)ptr;
4061 /* the driver will update registry with real values */
4062 memset(dm, 0, sizeof(*dm));
4063 dm->dmSize = sizeof(*dm);
4064 lstrcpyW(dm->dmDeviceName, winepsW);
4066 *needed = sizeof(DEVMODEW);
4069 /*****************************************************************************
4070 * WINSPOOL_GetDevModeFromReg
4072 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4073 * DevMode is stored either as unicode or ascii.
4075 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4076 LPBYTE ptr,
4077 DWORD buflen, DWORD *needed)
4079 DWORD sz = buflen, type;
4080 LONG ret;
4082 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4083 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4084 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4085 if (sz < sizeof(DEVMODEA))
4087 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4088 return FALSE;
4090 /* ensures that dmSize is not erratically bogus if registry is invalid */
4091 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4092 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4093 sz += (CCHDEVICENAME + CCHFORMNAME);
4094 if (ptr && (buflen >= sz)) {
4095 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4096 memcpy(ptr, dmW, sz);
4097 HeapFree(GetProcessHeap(),0,dmW);
4099 *needed = sz;
4100 return TRUE;
4103 /*********************************************************************
4104 * WINSPOOL_GetPrinter_1
4106 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4108 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4109 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4111 DWORD size, left = cbBuf;
4112 BOOL space = (cbBuf > 0);
4113 LPBYTE ptr = buf;
4115 *pcbNeeded = 0;
4117 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4118 if(space && size <= left) {
4119 pi1->pName = (LPWSTR)ptr;
4120 ptr += size;
4121 left -= size;
4122 } else
4123 space = FALSE;
4124 *pcbNeeded += size;
4127 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4128 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4129 if(space && size <= left) {
4130 pi1->pDescription = (LPWSTR)ptr;
4131 ptr += size;
4132 left -= size;
4133 } else
4134 space = FALSE;
4135 *pcbNeeded += size;
4138 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4139 if(space && size <= left) {
4140 pi1->pComment = (LPWSTR)ptr;
4141 ptr += size;
4142 left -= size;
4143 } else
4144 space = FALSE;
4145 *pcbNeeded += size;
4148 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4150 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4151 memset(pi1, 0, sizeof(*pi1));
4153 return space;
4155 /*********************************************************************
4156 * WINSPOOL_GetPrinter_2
4158 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4160 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4161 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4163 DWORD size, left = cbBuf;
4164 BOOL space = (cbBuf > 0);
4165 LPBYTE ptr = buf;
4167 *pcbNeeded = 0;
4169 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4170 if(space && size <= left) {
4171 pi2->pPrinterName = (LPWSTR)ptr;
4172 ptr += size;
4173 left -= size;
4174 } else
4175 space = FALSE;
4176 *pcbNeeded += size;
4178 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4179 if(space && size <= left) {
4180 pi2->pShareName = (LPWSTR)ptr;
4181 ptr += size;
4182 left -= size;
4183 } else
4184 space = FALSE;
4185 *pcbNeeded += size;
4187 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4188 if(space && size <= left) {
4189 pi2->pPortName = (LPWSTR)ptr;
4190 ptr += size;
4191 left -= size;
4192 } else
4193 space = FALSE;
4194 *pcbNeeded += size;
4196 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4197 if(space && size <= left) {
4198 pi2->pDriverName = (LPWSTR)ptr;
4199 ptr += size;
4200 left -= size;
4201 } else
4202 space = FALSE;
4203 *pcbNeeded += size;
4205 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4206 if(space && size <= left) {
4207 pi2->pComment = (LPWSTR)ptr;
4208 ptr += size;
4209 left -= size;
4210 } else
4211 space = FALSE;
4212 *pcbNeeded += size;
4214 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4215 if(space && size <= left) {
4216 pi2->pLocation = (LPWSTR)ptr;
4217 ptr += size;
4218 left -= size;
4219 } else
4220 space = FALSE;
4221 *pcbNeeded += size;
4223 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4224 if(space && size <= left) {
4225 pi2->pDevMode = (LPDEVMODEW)ptr;
4226 ptr += size;
4227 left -= size;
4228 } else
4229 space = FALSE;
4230 *pcbNeeded += size;
4232 else
4234 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4235 if(space && size <= left) {
4236 pi2->pDevMode = (LPDEVMODEW)ptr;
4237 ptr += size;
4238 left -= size;
4239 } else
4240 space = FALSE;
4241 *pcbNeeded += size;
4243 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4244 if(space && size <= left) {
4245 pi2->pSepFile = (LPWSTR)ptr;
4246 ptr += size;
4247 left -= size;
4248 } else
4249 space = FALSE;
4250 *pcbNeeded += size;
4252 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4253 if(space && size <= left) {
4254 pi2->pPrintProcessor = (LPWSTR)ptr;
4255 ptr += size;
4256 left -= size;
4257 } else
4258 space = FALSE;
4259 *pcbNeeded += size;
4261 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4262 if(space && size <= left) {
4263 pi2->pDatatype = (LPWSTR)ptr;
4264 ptr += size;
4265 left -= size;
4266 } else
4267 space = FALSE;
4268 *pcbNeeded += size;
4270 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4271 if(space && size <= left) {
4272 pi2->pParameters = (LPWSTR)ptr;
4273 ptr += size;
4274 left -= size;
4275 } else
4276 space = FALSE;
4277 *pcbNeeded += size;
4279 if(pi2) {
4280 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4281 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4282 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4283 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4284 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4287 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4288 memset(pi2, 0, sizeof(*pi2));
4290 return space;
4293 /*********************************************************************
4294 * WINSPOOL_GetPrinter_4
4296 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4298 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4299 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4301 DWORD size, left = cbBuf;
4302 BOOL space = (cbBuf > 0);
4303 LPBYTE ptr = buf;
4305 *pcbNeeded = 0;
4307 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4308 if(space && size <= left) {
4309 pi4->pPrinterName = (LPWSTR)ptr;
4310 ptr += size;
4311 left -= size;
4312 } else
4313 space = FALSE;
4314 *pcbNeeded += size;
4316 if(pi4) {
4317 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4320 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4321 memset(pi4, 0, sizeof(*pi4));
4323 return space;
4326 /*********************************************************************
4327 * WINSPOOL_GetPrinter_5
4329 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4331 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4332 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4334 DWORD size, left = cbBuf;
4335 BOOL space = (cbBuf > 0);
4336 LPBYTE ptr = buf;
4338 *pcbNeeded = 0;
4340 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4341 if(space && size <= left) {
4342 pi5->pPrinterName = (LPWSTR)ptr;
4343 ptr += size;
4344 left -= size;
4345 } else
4346 space = FALSE;
4347 *pcbNeeded += size;
4349 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4350 if(space && size <= left) {
4351 pi5->pPortName = (LPWSTR)ptr;
4352 ptr += size;
4353 left -= size;
4354 } else
4355 space = FALSE;
4356 *pcbNeeded += size;
4358 if(pi5) {
4359 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4360 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4361 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4364 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4365 memset(pi5, 0, sizeof(*pi5));
4367 return space;
4370 /*********************************************************************
4371 * WINSPOOL_GetPrinter_7
4373 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4375 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4376 DWORD cbBuf, LPDWORD pcbNeeded)
4378 DWORD size, left = cbBuf;
4379 BOOL space = (cbBuf > 0);
4380 LPBYTE ptr = buf;
4382 *pcbNeeded = 0;
4384 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4386 ptr = NULL;
4387 size = sizeof(pi7->pszObjectGUID);
4389 if (space && size <= left) {
4390 pi7->pszObjectGUID = (LPWSTR)ptr;
4391 ptr += size;
4392 left -= size;
4393 } else
4394 space = FALSE;
4395 *pcbNeeded += size;
4396 if (pi7) {
4397 /* We do not have a Directory Service */
4398 pi7->dwAction = DSPRINT_UNPUBLISH;
4401 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4402 memset(pi7, 0, sizeof(*pi7));
4404 return space;
4407 /*********************************************************************
4408 * WINSPOOL_GetPrinter_9
4410 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4412 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4413 DWORD cbBuf, LPDWORD pcbNeeded)
4415 DWORD size;
4416 BOOL space = (cbBuf > 0);
4418 *pcbNeeded = 0;
4420 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4421 if(space && size <= cbBuf) {
4422 pi9->pDevMode = (LPDEVMODEW)buf;
4423 } else
4424 space = FALSE;
4425 *pcbNeeded += size;
4427 else
4429 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4430 if(space && size <= cbBuf) {
4431 pi9->pDevMode = (LPDEVMODEW)buf;
4432 } else
4433 space = FALSE;
4434 *pcbNeeded += size;
4437 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4438 memset(pi9, 0, sizeof(*pi9));
4440 return space;
4443 /*****************************************************************************
4444 * GetPrinterW [WINSPOOL.@]
4446 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4447 DWORD cbBuf, LPDWORD pcbNeeded)
4449 DWORD size, needed = 0, err;
4450 LPBYTE ptr = NULL;
4451 HKEY hkeyPrinter;
4452 BOOL ret;
4454 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4456 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4457 if (err)
4459 SetLastError( err );
4460 return FALSE;
4463 switch(Level) {
4464 case 1:
4466 PRINTER_INFO_1W *pi1 = (PRINTER_INFO_1W *)pPrinter;
4468 size = sizeof(PRINTER_INFO_1W);
4469 if (size <= cbBuf) {
4470 ptr = pPrinter + size;
4471 cbBuf -= size;
4472 memset(pPrinter, 0, size);
4473 } else {
4474 pi1 = NULL;
4475 cbBuf = 0;
4477 ret = WINSPOOL_GetPrinter_1(hkeyPrinter, pi1, ptr, cbBuf, &needed);
4478 needed += size;
4479 break;
4482 case 2:
4484 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4486 size = sizeof(PRINTER_INFO_2W);
4487 if(size <= cbBuf) {
4488 ptr = pPrinter + size;
4489 cbBuf -= size;
4490 memset(pPrinter, 0, size);
4491 } else {
4492 pi2 = NULL;
4493 cbBuf = 0;
4495 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4496 needed += size;
4497 break;
4500 case 4:
4502 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4504 size = sizeof(PRINTER_INFO_4W);
4505 if(size <= cbBuf) {
4506 ptr = pPrinter + size;
4507 cbBuf -= size;
4508 memset(pPrinter, 0, size);
4509 } else {
4510 pi4 = NULL;
4511 cbBuf = 0;
4513 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4514 needed += size;
4515 break;
4519 case 5:
4521 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4523 size = sizeof(PRINTER_INFO_5W);
4524 if(size <= cbBuf) {
4525 ptr = pPrinter + size;
4526 cbBuf -= size;
4527 memset(pPrinter, 0, size);
4528 } else {
4529 pi5 = NULL;
4530 cbBuf = 0;
4533 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4534 needed += size;
4535 break;
4539 case 6:
4541 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4543 size = sizeof(PRINTER_INFO_6);
4544 if (size <= cbBuf) {
4545 /* FIXME: We do not update the status yet */
4546 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4547 ret = TRUE;
4548 } else {
4549 ret = FALSE;
4552 needed += size;
4553 break;
4556 case 7:
4558 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4560 size = sizeof(PRINTER_INFO_7W);
4561 if (size <= cbBuf) {
4562 ptr = pPrinter + size;
4563 cbBuf -= size;
4564 memset(pPrinter, 0, size);
4565 } else {
4566 pi7 = NULL;
4567 cbBuf = 0;
4570 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4571 needed += size;
4572 break;
4576 case 8:
4577 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4578 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4579 /* fall through */
4580 case 9:
4582 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4584 size = sizeof(PRINTER_INFO_9W);
4585 if(size <= cbBuf) {
4586 ptr = pPrinter + size;
4587 cbBuf -= size;
4588 memset(pPrinter, 0, size);
4589 } else {
4590 pi9 = NULL;
4591 cbBuf = 0;
4594 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4595 needed += size;
4596 break;
4600 default:
4601 FIXME("Unimplemented level %d\n", Level);
4602 SetLastError(ERROR_INVALID_LEVEL);
4603 RegCloseKey(hkeyPrinter);
4604 return FALSE;
4607 RegCloseKey(hkeyPrinter);
4609 TRACE("returning %d needed = %d\n", ret, needed);
4610 if(pcbNeeded) *pcbNeeded = needed;
4611 if(!ret)
4612 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4613 return ret;
4616 /*****************************************************************************
4617 * GetPrinterA [WINSPOOL.@]
4619 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4620 DWORD cbBuf, LPDWORD pcbNeeded)
4622 BOOL ret;
4623 LPBYTE buf = NULL;
4625 if (cbBuf)
4626 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4628 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4629 if (ret)
4630 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4631 HeapFree(GetProcessHeap(), 0, buf);
4633 return ret;
4636 /*****************************************************************************
4637 * WINSPOOL_EnumPrintersW
4639 * Implementation of EnumPrintersW
4641 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4642 DWORD dwLevel, LPBYTE lpbPrinters,
4643 DWORD cbBuf, LPDWORD lpdwNeeded,
4644 LPDWORD lpdwReturned)
4647 HKEY hkeyPrinters, hkeyPrinter;
4648 WCHAR PrinterName[255];
4649 DWORD needed = 0, number = 0;
4650 DWORD used, i, left;
4651 PBYTE pi, buf;
4653 if(lpbPrinters)
4654 memset(lpbPrinters, 0, cbBuf);
4655 if(lpdwReturned)
4656 *lpdwReturned = 0;
4657 if(lpdwNeeded)
4658 *lpdwNeeded = 0;
4660 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4661 if(dwType == PRINTER_ENUM_DEFAULT)
4662 return TRUE;
4664 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4665 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4666 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4667 if (!dwType) {
4668 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4669 return TRUE;
4674 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4675 FIXME("dwType = %08x\n", dwType);
4676 SetLastError(ERROR_INVALID_FLAGS);
4677 return FALSE;
4680 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4681 ERROR_SUCCESS) {
4682 ERR("Can't create Printers key\n");
4683 return FALSE;
4686 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4687 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4688 RegCloseKey(hkeyPrinters);
4689 ERR("Can't query Printers key\n");
4690 return FALSE;
4692 TRACE("Found %d printers\n", number);
4694 switch(dwLevel) {
4695 case 1:
4696 used = number * sizeof(PRINTER_INFO_1W);
4697 break;
4698 case 2:
4699 used = number * sizeof(PRINTER_INFO_2W);
4700 break;
4701 case 4:
4702 used = number * sizeof(PRINTER_INFO_4W);
4703 break;
4704 case 5:
4705 used = number * sizeof(PRINTER_INFO_5W);
4706 break;
4708 default:
4709 SetLastError(ERROR_INVALID_LEVEL);
4710 RegCloseKey(hkeyPrinters);
4711 return FALSE;
4713 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4715 for(i = 0; i < number; i++) {
4716 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, ARRAY_SIZE(PrinterName)) != ERROR_SUCCESS) {
4717 ERR("Can't enum key number %d\n", i);
4718 RegCloseKey(hkeyPrinters);
4719 return FALSE;
4721 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4722 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4723 ERROR_SUCCESS) {
4724 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4725 RegCloseKey(hkeyPrinters);
4726 return FALSE;
4729 if(cbBuf > used) {
4730 buf = lpbPrinters + used;
4731 left = cbBuf - used;
4732 } else {
4733 buf = NULL;
4734 left = 0;
4737 switch(dwLevel) {
4738 case 1:
4739 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4740 left, &needed);
4741 used += needed;
4742 if(pi) pi += sizeof(PRINTER_INFO_1W);
4743 break;
4744 case 2:
4745 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4746 left, &needed);
4747 used += needed;
4748 if(pi) pi += sizeof(PRINTER_INFO_2W);
4749 break;
4750 case 4:
4751 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4752 left, &needed);
4753 used += needed;
4754 if(pi) pi += sizeof(PRINTER_INFO_4W);
4755 break;
4756 case 5:
4757 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4758 left, &needed);
4759 used += needed;
4760 if(pi) pi += sizeof(PRINTER_INFO_5W);
4761 break;
4762 default:
4763 ERR("Shouldn't be here!\n");
4764 RegCloseKey(hkeyPrinter);
4765 RegCloseKey(hkeyPrinters);
4766 return FALSE;
4768 RegCloseKey(hkeyPrinter);
4770 RegCloseKey(hkeyPrinters);
4772 if(lpdwNeeded)
4773 *lpdwNeeded = used;
4775 if(used > cbBuf) {
4776 if(lpbPrinters)
4777 memset(lpbPrinters, 0, cbBuf);
4778 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4779 return FALSE;
4781 if(lpdwReturned)
4782 *lpdwReturned = number;
4783 SetLastError(ERROR_SUCCESS);
4784 return TRUE;
4788 /******************************************************************
4789 * EnumPrintersW [WINSPOOL.@]
4791 * Enumerates the available printers, print servers and print
4792 * providers, depending on the specified flags, name and level.
4794 * RETURNS:
4796 * If level is set to 1:
4797 * Returns an array of PRINTER_INFO_1 data structures in the
4798 * lpbPrinters buffer.
4800 * If level is set to 2:
4801 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4802 * Returns an array of PRINTER_INFO_2 data structures in the
4803 * lpbPrinters buffer. Note that according to MSDN also an
4804 * OpenPrinter should be performed on every remote printer.
4806 * If level is set to 4 (officially WinNT only):
4807 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4808 * Fast: Only the registry is queried to retrieve printer names,
4809 * no connection to the driver is made.
4810 * Returns an array of PRINTER_INFO_4 data structures in the
4811 * lpbPrinters buffer.
4813 * If level is set to 5 (officially WinNT4/Win9x only):
4814 * Fast: Only the registry is queried to retrieve printer names,
4815 * no connection to the driver is made.
4816 * Returns an array of PRINTER_INFO_5 data structures in the
4817 * lpbPrinters buffer.
4819 * If level set to 3 or 6+:
4820 * returns zero (failure!)
4822 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4823 * for information.
4825 * BUGS:
4826 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4827 * - Only levels 2, 4 and 5 are implemented at the moment.
4828 * - 16-bit printer drivers are not enumerated.
4829 * - Returned amount of bytes used/needed does not match the real Windoze
4830 * implementation (as in this implementation, all strings are part
4831 * of the buffer, whereas Win32 keeps them somewhere else)
4832 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4834 * NOTE:
4835 * - In a regular Wine installation, no registry settings for printers
4836 * exist, which makes this function return an empty list.
4838 BOOL WINAPI EnumPrintersW(
4839 DWORD dwType, /* [in] Types of print objects to enumerate */
4840 LPWSTR lpszName, /* [in] name of objects to enumerate */
4841 DWORD dwLevel, /* [in] type of printer info structure */
4842 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4843 DWORD cbBuf, /* [in] max size of buffer in bytes */
4844 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4845 LPDWORD lpdwReturned /* [out] number of entries returned */
4848 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4849 lpdwNeeded, lpdwReturned);
4852 /******************************************************************
4853 * EnumPrintersA [WINSPOOL.@]
4855 * See EnumPrintersW
4858 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4859 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4861 BOOL ret;
4862 UNICODE_STRING pNameU;
4863 LPWSTR pNameW;
4864 LPBYTE pPrintersW;
4866 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4867 pPrinters, cbBuf, pcbNeeded, pcReturned);
4869 pNameW = asciitounicode(&pNameU, pName);
4871 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4872 MS Office need this */
4873 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4875 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4877 RtlFreeUnicodeString(&pNameU);
4878 if (ret) {
4879 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4881 HeapFree(GetProcessHeap(), 0, pPrintersW);
4882 return ret;
4885 /*****************************************************************************
4886 * WINSPOOL_GetDriverInfoFromReg [internal]
4888 * Enters the information from the registry into the DRIVER_INFO struct
4890 * RETURNS
4891 * zero if the printer driver does not exist in the registry
4892 * (only if Level > 1) otherwise nonzero
4894 static BOOL WINSPOOL_GetDriverInfoFromReg(
4895 HKEY hkeyDrivers,
4896 LPWSTR DriverName,
4897 const printenv_t * env,
4898 DWORD Level,
4899 LPBYTE ptr, /* DRIVER_INFO */
4900 LPBYTE pDriverStrings, /* strings buffer */
4901 DWORD cbBuf, /* size of string buffer */
4902 LPDWORD pcbNeeded) /* space needed for str. */
4904 DWORD size, tmp;
4905 HKEY hkeyDriver;
4906 WCHAR driverdir[MAX_PATH];
4907 DWORD dirlen;
4908 LPBYTE strPtr = pDriverStrings;
4909 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4911 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4912 debugstr_w(DriverName), env,
4913 Level, di, pDriverStrings, cbBuf);
4915 if (di) ZeroMemory(di, di_sizeof[Level]);
4917 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4918 if (*pcbNeeded <= cbBuf)
4919 strcpyW((LPWSTR)strPtr, DriverName);
4921 /* pName for level 1 has a different offset! */
4922 if (Level == 1) {
4923 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4924 return TRUE;
4927 /* .cVersion and .pName for level > 1 */
4928 if (di) {
4929 di->cVersion = env->driverversion;
4930 di->pName = (LPWSTR) strPtr;
4931 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4934 /* Reserve Space for the largest subdir and a Backslash*/
4935 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4936 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4937 /* Should never Fail */
4938 return FALSE;
4940 lstrcatW(driverdir, env->versionsubdir);
4941 lstrcatW(driverdir, backslashW);
4943 /* dirlen must not include the terminating zero */
4944 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4946 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4947 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4948 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4949 return FALSE;
4952 /* pEnvironment */
4953 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4955 *pcbNeeded += size;
4956 if (*pcbNeeded <= cbBuf) {
4957 lstrcpyW((LPWSTR)strPtr, env->envname);
4958 if (di) di->pEnvironment = (LPWSTR)strPtr;
4959 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4962 /* .pDriverPath is the Graphics rendering engine.
4963 The full Path is required to avoid a crash in some apps */
4964 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4965 *pcbNeeded += size;
4966 if (*pcbNeeded <= cbBuf)
4967 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4969 if (di) di->pDriverPath = (LPWSTR)strPtr;
4970 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4973 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4974 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4975 *pcbNeeded += size;
4976 if (*pcbNeeded <= cbBuf)
4977 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4979 if (di) di->pDataFile = (LPWSTR)strPtr;
4980 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4983 /* .pConfigFile is the Driver user Interface */
4984 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4985 *pcbNeeded += size;
4986 if (*pcbNeeded <= cbBuf)
4987 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4989 if (di) di->pConfigFile = (LPWSTR)strPtr;
4990 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4993 if (Level == 2 ) {
4994 RegCloseKey(hkeyDriver);
4995 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4996 return TRUE;
4999 if (Level == 5 ) {
5000 RegCloseKey(hkeyDriver);
5001 FIXME("level 5: incomplete\n");
5002 return TRUE;
5005 /* .pHelpFile */
5006 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
5007 *pcbNeeded += size;
5008 if (*pcbNeeded <= cbBuf)
5009 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
5011 if (di) di->pHelpFile = (LPWSTR)strPtr;
5012 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5015 /* .pDependentFiles */
5016 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
5017 *pcbNeeded += size;
5018 if (*pcbNeeded <= cbBuf)
5019 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
5021 if (di) di->pDependentFiles = (LPWSTR)strPtr;
5022 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5024 else if (GetVersion() & 0x80000000) {
5025 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
5026 size = 2 * sizeof(WCHAR);
5027 *pcbNeeded += size;
5028 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
5030 if (di) di->pDependentFiles = (LPWSTR)strPtr;
5031 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5034 /* .pMonitorName is the optional Language Monitor */
5035 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
5036 *pcbNeeded += size;
5037 if (*pcbNeeded <= cbBuf)
5038 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
5040 if (di) di->pMonitorName = (LPWSTR)strPtr;
5041 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5044 /* .pDefaultDataType */
5045 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
5046 *pcbNeeded += size;
5047 if(*pcbNeeded <= cbBuf)
5048 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
5050 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
5051 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5054 if (Level == 3 ) {
5055 RegCloseKey(hkeyDriver);
5056 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5057 return TRUE;
5060 /* .pszzPreviousNames */
5061 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
5062 *pcbNeeded += size;
5063 if(*pcbNeeded <= cbBuf)
5064 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
5066 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
5067 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5070 if (Level == 4 ) {
5071 RegCloseKey(hkeyDriver);
5072 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5073 return TRUE;
5076 /* support is missing, but not important enough for a FIXME */
5077 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5079 /* .pszMfgName */
5080 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5081 *pcbNeeded += size;
5082 if(*pcbNeeded <= cbBuf)
5083 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5085 if (di) di->pszMfgName = (LPWSTR)strPtr;
5086 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5089 /* .pszOEMUrl */
5090 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5091 *pcbNeeded += size;
5092 if(*pcbNeeded <= cbBuf)
5093 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5095 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5096 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5099 /* .pszHardwareID */
5100 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5101 *pcbNeeded += size;
5102 if(*pcbNeeded <= cbBuf)
5103 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5105 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5106 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5109 /* .pszProvider */
5110 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5111 *pcbNeeded += size;
5112 if(*pcbNeeded <= cbBuf)
5113 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5115 if (di) di->pszProvider = (LPWSTR)strPtr;
5116 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5119 if (Level == 6 ) {
5120 RegCloseKey(hkeyDriver);
5121 return TRUE;
5124 /* support is missing, but not important enough for a FIXME */
5125 TRACE("level 8: incomplete\n");
5127 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5128 RegCloseKey(hkeyDriver);
5129 return TRUE;
5132 /*****************************************************************************
5133 * GetPrinterDriverW [WINSPOOL.@]
5135 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5136 DWORD Level, LPBYTE pDriverInfo,
5137 DWORD cbBuf, LPDWORD pcbNeeded)
5139 LPCWSTR name;
5140 WCHAR DriverName[100];
5141 DWORD ret, type, size, needed = 0;
5142 LPBYTE ptr = NULL;
5143 HKEY hkeyPrinter, hkeyDrivers;
5144 const printenv_t * env;
5146 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5147 Level,pDriverInfo,cbBuf, pcbNeeded);
5149 if (cbBuf > 0)
5150 ZeroMemory(pDriverInfo, cbBuf);
5152 if (!(name = get_opened_printer_name(hPrinter))) {
5153 SetLastError(ERROR_INVALID_HANDLE);
5154 return FALSE;
5157 if (Level < 1 || Level == 7 || Level > 8) {
5158 SetLastError(ERROR_INVALID_LEVEL);
5159 return FALSE;
5162 env = validate_envW(pEnvironment);
5163 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5165 ret = open_printer_reg_key( name, &hkeyPrinter );
5166 if (ret)
5168 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5169 SetLastError( ret );
5170 return FALSE;
5173 size = sizeof(DriverName);
5174 DriverName[0] = 0;
5175 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5176 (LPBYTE)DriverName, &size);
5177 RegCloseKey(hkeyPrinter);
5178 if(ret != ERROR_SUCCESS) {
5179 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5180 return FALSE;
5183 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5184 if(!hkeyDrivers) {
5185 ERR("Can't create Drivers key\n");
5186 return FALSE;
5189 size = di_sizeof[Level];
5190 if ((size <= cbBuf) && pDriverInfo)
5191 ptr = pDriverInfo + size;
5193 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5194 env, Level, pDriverInfo, ptr,
5195 (cbBuf < size) ? 0 : cbBuf - size,
5196 &needed)) {
5197 RegCloseKey(hkeyDrivers);
5198 return FALSE;
5201 RegCloseKey(hkeyDrivers);
5203 if(pcbNeeded) *pcbNeeded = size + needed;
5204 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5205 if(cbBuf >= size + needed) return TRUE;
5206 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5207 return FALSE;
5210 /*****************************************************************************
5211 * GetPrinterDriverA [WINSPOOL.@]
5213 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5214 DWORD Level, LPBYTE pDriverInfo,
5215 DWORD cbBuf, LPDWORD pcbNeeded)
5217 BOOL ret;
5218 UNICODE_STRING pEnvW;
5219 PWSTR pwstrEnvW;
5220 LPBYTE buf = NULL;
5222 if (cbBuf)
5224 ZeroMemory(pDriverInfo, cbBuf);
5225 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5228 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5229 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5230 cbBuf, pcbNeeded);
5231 if (ret)
5232 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5234 HeapFree(GetProcessHeap(), 0, buf);
5236 RtlFreeUnicodeString(&pEnvW);
5237 return ret;
5240 /*****************************************************************************
5241 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5243 * Return the PATH for the Printer-Drivers (UNICODE)
5245 * PARAMS
5246 * pName [I] Servername (NT only) or NULL (local Computer)
5247 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5248 * Level [I] Structure-Level (must be 1)
5249 * pDriverDirectory [O] PTR to Buffer that receives the Result
5250 * cbBuf [I] Size of Buffer at pDriverDirectory
5251 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5252 * required for pDriverDirectory
5254 * RETURNS
5255 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5256 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5257 * if cbBuf is too small
5259 * Native Values returned in pDriverDirectory on Success:
5260 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5261 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5262 *| win9x(Windows 4.0): "%winsysdir%"
5264 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5266 * FIXME
5267 *- Only NULL or "" is supported for pName
5270 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5271 DWORD Level, LPBYTE pDriverDirectory,
5272 DWORD cbBuf, LPDWORD pcbNeeded)
5274 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5275 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5277 if ((backend == NULL) && !load_backend()) return FALSE;
5279 if (Level != 1) {
5280 /* (Level != 1) is ignored in win9x */
5281 SetLastError(ERROR_INVALID_LEVEL);
5282 return FALSE;
5284 if (pcbNeeded == NULL) {
5285 /* (pcbNeeded == NULL) is ignored in win9x */
5286 SetLastError(RPC_X_NULL_REF_POINTER);
5287 return FALSE;
5290 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5291 pDriverDirectory, cbBuf, pcbNeeded);
5296 /*****************************************************************************
5297 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5299 * Return the PATH for the Printer-Drivers (ANSI)
5301 * See GetPrinterDriverDirectoryW.
5303 * NOTES
5304 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5307 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5308 DWORD Level, LPBYTE pDriverDirectory,
5309 DWORD cbBuf, LPDWORD pcbNeeded)
5311 UNICODE_STRING nameW, environmentW;
5312 BOOL ret;
5313 DWORD pcbNeededW;
5314 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5315 WCHAR *driverDirectoryW = NULL;
5317 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5318 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5320 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5322 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5323 else nameW.Buffer = NULL;
5324 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5325 else environmentW.Buffer = NULL;
5327 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5328 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5329 if (ret) {
5330 DWORD needed;
5331 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5332 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5333 if(pcbNeeded)
5334 *pcbNeeded = needed;
5335 ret = needed <= cbBuf;
5336 } else
5337 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5339 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5341 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5342 RtlFreeUnicodeString(&environmentW);
5343 RtlFreeUnicodeString(&nameW);
5345 return ret;
5348 /*****************************************************************************
5349 * AddPrinterDriverA [WINSPOOL.@]
5351 * See AddPrinterDriverW.
5354 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5356 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5357 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5360 /******************************************************************************
5361 * AddPrinterDriverW (WINSPOOL.@)
5363 * Install a Printer Driver
5365 * PARAMS
5366 * pName [I] Servername or NULL (local Computer)
5367 * level [I] Level for the supplied DRIVER_INFO_*W struct
5368 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5370 * RESULTS
5371 * Success: TRUE
5372 * Failure: FALSE
5375 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5377 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5378 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5381 /*****************************************************************************
5382 * AddPrintProcessorA [WINSPOOL.@]
5384 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5385 LPSTR pPrintProcessorName)
5387 UNICODE_STRING NameW, EnvW, PathW, ProcessorW;
5388 BOOL ret;
5390 TRACE("(%s,%s,%s,%s)\n", debugstr_a(pName), debugstr_a(pEnvironment),
5391 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5393 asciitounicode(&NameW, pName);
5394 asciitounicode(&EnvW, pEnvironment);
5395 asciitounicode(&PathW, pPathName);
5396 asciitounicode(&ProcessorW, pPrintProcessorName);
5398 ret = AddPrintProcessorW(NameW.Buffer, EnvW.Buffer, PathW.Buffer, ProcessorW.Buffer);
5400 RtlFreeUnicodeString(&ProcessorW);
5401 RtlFreeUnicodeString(&PathW);
5402 RtlFreeUnicodeString(&EnvW);
5403 RtlFreeUnicodeString(&NameW);
5405 return ret;
5408 /*****************************************************************************
5409 * AddPrintProcessorW [WINSPOOL.@]
5411 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5412 LPWSTR pPrintProcessorName)
5414 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5415 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5416 return TRUE;
5419 /*****************************************************************************
5420 * AddPrintProvidorA [WINSPOOL.@]
5422 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5424 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5425 return FALSE;
5428 /*****************************************************************************
5429 * AddPrintProvidorW [WINSPOOL.@]
5431 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5433 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5434 return FALSE;
5437 /*****************************************************************************
5438 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5440 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5441 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5443 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5444 pDevModeOutput, pDevModeInput);
5445 return 0;
5448 /*****************************************************************************
5449 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5451 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5452 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5454 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5455 pDevModeOutput, pDevModeInput);
5456 return 0;
5459 /*****************************************************************************
5460 * PrinterProperties [WINSPOOL.@]
5462 * Displays a dialog to set the properties of the printer.
5464 * RETURNS
5465 * nonzero on success or zero on failure
5467 * BUGS
5468 * implemented as stub only
5470 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5471 HANDLE hPrinter /* [in] handle to printer object */
5473 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5474 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5475 return FALSE;
5478 /*****************************************************************************
5479 * EnumJobsA [WINSPOOL.@]
5482 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5483 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5484 LPDWORD pcReturned)
5486 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5487 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5489 if(pcbNeeded) *pcbNeeded = 0;
5490 if(pcReturned) *pcReturned = 0;
5491 return FALSE;
5495 /*****************************************************************************
5496 * EnumJobsW [WINSPOOL.@]
5499 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5500 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5501 LPDWORD pcReturned)
5503 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5504 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5506 if(pcbNeeded) *pcbNeeded = 0;
5507 if(pcReturned) *pcReturned = 0;
5508 return FALSE;
5511 /*****************************************************************************
5512 * WINSPOOL_EnumPrinterDrivers [internal]
5514 * Delivers information about all printer drivers installed on the
5515 * localhost or a given server
5517 * RETURNS
5518 * nonzero on success or zero on failure. If the buffer for the returned
5519 * information is too small the function will return an error
5521 * BUGS
5522 * - only implemented for localhost, foreign hosts will return an error
5524 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5525 DWORD Level, LPBYTE pDriverInfo,
5526 DWORD driver_index,
5527 DWORD cbBuf, LPDWORD pcbNeeded,
5528 LPDWORD pcFound, DWORD data_offset)
5530 { HKEY hkeyDrivers;
5531 DWORD i, size = 0;
5532 const printenv_t * env;
5534 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5535 debugstr_w(pName), debugstr_w(pEnvironment),
5536 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5538 env = validate_envW(pEnvironment);
5539 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5541 *pcFound = 0;
5543 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5544 if(!hkeyDrivers) {
5545 ERR("Can't open Drivers key\n");
5546 return FALSE;
5549 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5550 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5551 RegCloseKey(hkeyDrivers);
5552 ERR("Can't query Drivers key\n");
5553 return FALSE;
5555 TRACE("Found %d Drivers\n", *pcFound);
5557 /* get size of single struct
5558 * unicode and ascii structure have the same size
5560 size = di_sizeof[Level];
5562 if (data_offset == 0)
5563 data_offset = size * (*pcFound);
5564 *pcbNeeded = data_offset;
5566 for( i = 0; i < *pcFound; i++) {
5567 WCHAR DriverNameW[255];
5568 PBYTE table_ptr = NULL;
5569 PBYTE data_ptr = NULL;
5570 DWORD needed = 0;
5572 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, ARRAY_SIZE(DriverNameW)) != ERROR_SUCCESS) {
5573 ERR("Can't enum key number %d\n", i);
5574 RegCloseKey(hkeyDrivers);
5575 return FALSE;
5578 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5579 table_ptr = pDriverInfo + (driver_index + i) * size;
5580 if (pDriverInfo && *pcbNeeded <= cbBuf)
5581 data_ptr = pDriverInfo + *pcbNeeded;
5583 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5584 env, Level, table_ptr, data_ptr,
5585 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5586 &needed)) {
5587 RegCloseKey(hkeyDrivers);
5588 return FALSE;
5591 *pcbNeeded += needed;
5594 RegCloseKey(hkeyDrivers);
5596 if(cbBuf < *pcbNeeded){
5597 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5598 return FALSE;
5601 return TRUE;
5604 /*****************************************************************************
5605 * EnumPrinterDriversW [WINSPOOL.@]
5607 * see function EnumPrinterDrivers for RETURNS, BUGS
5609 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5610 LPBYTE pDriverInfo, DWORD cbBuf,
5611 LPDWORD pcbNeeded, LPDWORD pcReturned)
5613 static const WCHAR allW[] = {'a','l','l',0};
5614 BOOL ret;
5615 DWORD found;
5617 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5619 SetLastError(RPC_X_NULL_REF_POINTER);
5620 return FALSE;
5623 /* check for local drivers */
5624 if((pName) && (pName[0])) {
5625 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5626 SetLastError(ERROR_ACCESS_DENIED);
5627 return FALSE;
5630 /* check input parameter */
5631 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5632 SetLastError(ERROR_INVALID_LEVEL);
5633 return FALSE;
5636 if(pDriverInfo && cbBuf > 0)
5637 memset( pDriverInfo, 0, cbBuf);
5639 /* Exception: pull all printers */
5640 if (pEnvironment && !strcmpW(pEnvironment, allW))
5642 DWORD i, needed, bufsize = cbBuf;
5643 DWORD total_found = 0;
5644 DWORD data_offset;
5646 /* Precompute the overall total; we need this to know
5647 where pointers end and data begins (i.e. data_offset) */
5648 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
5650 needed = found = 0;
5651 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5652 NULL, 0, 0, &needed, &found, 0);
5653 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5654 total_found += found;
5657 data_offset = di_sizeof[Level] * total_found;
5659 *pcReturned = 0;
5660 *pcbNeeded = 0;
5661 total_found = 0;
5662 for (i = 0; i < ARRAY_SIZE(all_printenv); i++)
5664 needed = found = 0;
5665 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5666 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5667 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5668 else if (ret)
5669 *pcReturned += found;
5670 *pcbNeeded = needed;
5671 data_offset = needed;
5672 total_found += found;
5674 return ret;
5677 /* Normal behavior */
5678 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5679 0, cbBuf, pcbNeeded, &found, 0);
5680 if (ret)
5681 *pcReturned = found;
5683 return ret;
5686 /*****************************************************************************
5687 * EnumPrinterDriversA [WINSPOOL.@]
5689 * see function EnumPrinterDrivers for RETURNS, BUGS
5691 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5692 LPBYTE pDriverInfo, DWORD cbBuf,
5693 LPDWORD pcbNeeded, LPDWORD pcReturned)
5695 BOOL ret;
5696 UNICODE_STRING pNameW, pEnvironmentW;
5697 PWSTR pwstrNameW, pwstrEnvironmentW;
5698 LPBYTE buf = NULL;
5700 if (cbBuf)
5701 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5703 pwstrNameW = asciitounicode(&pNameW, pName);
5704 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5706 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5707 buf, cbBuf, pcbNeeded, pcReturned);
5708 if (ret)
5709 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5711 HeapFree(GetProcessHeap(), 0, buf);
5713 RtlFreeUnicodeString(&pNameW);
5714 RtlFreeUnicodeString(&pEnvironmentW);
5716 return ret;
5719 /******************************************************************************
5720 * EnumPortsA (WINSPOOL.@)
5722 * See EnumPortsW.
5725 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5726 LPDWORD pcbNeeded, LPDWORD pcReturned)
5728 BOOL res;
5729 LPBYTE bufferW = NULL;
5730 LPWSTR nameW = NULL;
5731 DWORD needed = 0;
5732 DWORD numentries = 0;
5733 INT len;
5735 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5736 cbBuf, pcbNeeded, pcReturned);
5738 /* convert servername to unicode */
5739 if (pName) {
5740 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5741 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5742 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5744 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5745 needed = cbBuf * sizeof(WCHAR);
5746 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5747 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5749 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5750 if (pcbNeeded) needed = *pcbNeeded;
5751 /* HeapReAlloc return NULL, when bufferW was NULL */
5752 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5753 HeapAlloc(GetProcessHeap(), 0, needed);
5755 /* Try again with the large Buffer */
5756 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5758 needed = pcbNeeded ? *pcbNeeded : 0;
5759 numentries = pcReturned ? *pcReturned : 0;
5762 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5763 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5765 if (res) {
5766 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5767 DWORD entrysize = 0;
5768 DWORD index;
5769 LPSTR ptr;
5770 LPPORT_INFO_2W pi2w;
5771 LPPORT_INFO_2A pi2a;
5773 needed = 0;
5774 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5776 /* First pass: calculate the size for all Entries */
5777 pi2w = (LPPORT_INFO_2W) bufferW;
5778 pi2a = (LPPORT_INFO_2A) pPorts;
5779 index = 0;
5780 while (index < numentries) {
5781 index++;
5782 needed += entrysize; /* PORT_INFO_?A */
5783 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5785 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5786 NULL, 0, NULL, NULL);
5787 if (Level > 1) {
5788 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5789 NULL, 0, NULL, NULL);
5790 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5791 NULL, 0, NULL, NULL);
5793 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5794 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5795 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5798 /* check for errors and quit on failure */
5799 if (cbBuf < needed) {
5800 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5801 res = FALSE;
5802 goto cleanup;
5804 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5805 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5806 cbBuf -= len ; /* free Bytes in the user-Buffer */
5807 pi2w = (LPPORT_INFO_2W) bufferW;
5808 pi2a = (LPPORT_INFO_2A) pPorts;
5809 index = 0;
5810 /* Second Pass: Fill the User Buffer (if we have one) */
5811 while ((index < numentries) && pPorts) {
5812 index++;
5813 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5814 pi2a->pPortName = ptr;
5815 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5816 ptr, cbBuf , NULL, NULL);
5817 ptr += len;
5818 cbBuf -= len;
5819 if (Level > 1) {
5820 pi2a->pMonitorName = ptr;
5821 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5822 ptr, cbBuf, NULL, NULL);
5823 ptr += len;
5824 cbBuf -= len;
5826 pi2a->pDescription = ptr;
5827 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5828 ptr, cbBuf, NULL, NULL);
5829 ptr += len;
5830 cbBuf -= len;
5832 pi2a->fPortType = pi2w->fPortType;
5833 pi2a->Reserved = 0; /* documented: "must be zero" */
5836 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5837 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5838 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5842 cleanup:
5843 if (pcbNeeded) *pcbNeeded = needed;
5844 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5846 HeapFree(GetProcessHeap(), 0, nameW);
5847 HeapFree(GetProcessHeap(), 0, bufferW);
5849 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5850 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5852 return (res);
5856 /******************************************************************************
5857 * EnumPortsW (WINSPOOL.@)
5859 * Enumerate available Ports
5861 * PARAMS
5862 * pName [I] Servername or NULL (local Computer)
5863 * Level [I] Structure-Level (1 or 2)
5864 * pPorts [O] PTR to Buffer that receives the Result
5865 * cbBuf [I] Size of Buffer at pPorts
5866 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5867 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5869 * RETURNS
5870 * Success: TRUE
5871 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5874 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5877 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5878 cbBuf, pcbNeeded, pcReturned);
5880 if ((backend == NULL) && !load_backend()) return FALSE;
5882 /* Level is not checked in win9x */
5883 if (!Level || (Level > 2)) {
5884 WARN("level (%d) is ignored in win9x\n", Level);
5885 SetLastError(ERROR_INVALID_LEVEL);
5886 return FALSE;
5888 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5889 SetLastError(RPC_X_NULL_REF_POINTER);
5890 return FALSE;
5893 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5896 /******************************************************************************
5897 * GetDefaultPrinterW (WINSPOOL.@)
5899 * FIXME
5900 * This function must read the value from data 'device' of key
5901 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5903 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5905 BOOL retval = TRUE;
5906 DWORD insize, len;
5907 WCHAR *buffer, *ptr;
5909 if (!namesize)
5911 SetLastError(ERROR_INVALID_PARAMETER);
5912 return FALSE;
5915 /* make the buffer big enough for the stuff from the profile/registry,
5916 * the content must fit into the local buffer to compute the correct
5917 * size even if the extern buffer is too small or not given.
5918 * (20 for ,driver,port) */
5919 insize = *namesize;
5920 len = max(100, (insize + 20));
5921 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5923 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5925 SetLastError (ERROR_FILE_NOT_FOUND);
5926 retval = FALSE;
5927 goto end;
5929 TRACE("%s\n", debugstr_w(buffer));
5931 if ((ptr = strchrW(buffer, ',')) == NULL)
5933 SetLastError(ERROR_INVALID_NAME);
5934 retval = FALSE;
5935 goto end;
5938 *ptr = 0;
5939 *namesize = strlenW(buffer) + 1;
5940 if(!name || (*namesize > insize))
5942 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5943 retval = FALSE;
5944 goto end;
5946 strcpyW(name, buffer);
5948 end:
5949 HeapFree( GetProcessHeap(), 0, buffer);
5950 return retval;
5954 /******************************************************************************
5955 * GetDefaultPrinterA (WINSPOOL.@)
5957 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5959 BOOL retval = TRUE;
5960 DWORD insize = 0;
5961 WCHAR *bufferW = NULL;
5963 if (!namesize)
5965 SetLastError(ERROR_INVALID_PARAMETER);
5966 return FALSE;
5969 if(name && *namesize) {
5970 insize = *namesize;
5971 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5974 if(!GetDefaultPrinterW( bufferW, namesize)) {
5975 retval = FALSE;
5976 goto end;
5979 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5980 NULL, NULL);
5981 if (!*namesize)
5983 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5984 retval = FALSE;
5986 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5988 end:
5989 HeapFree( GetProcessHeap(), 0, bufferW);
5990 return retval;
5994 /******************************************************************************
5995 * SetDefaultPrinterW (WINSPOOL.204)
5997 * Set the Name of the Default Printer
5999 * PARAMS
6000 * pszPrinter [I] Name of the Printer or NULL
6002 * RETURNS
6003 * Success: True
6004 * Failure: FALSE
6006 * NOTES
6007 * When the Parameter is NULL or points to an Empty String and
6008 * a Default Printer was already present, then this Function changes nothing.
6009 * Without a Default Printer and NULL (or an Empty String) as Parameter,
6010 * the First enumerated local Printer is used.
6013 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
6015 WCHAR default_printer[MAX_PATH];
6016 LPWSTR buffer = NULL;
6017 HKEY hreg;
6018 DWORD size;
6019 DWORD namelen;
6020 LONG lres;
6022 TRACE("(%s)\n", debugstr_w(pszPrinter));
6023 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
6025 default_printer[0] = '\0';
6026 size = ARRAY_SIZE(default_printer);
6028 /* if we have a default Printer, do nothing. */
6029 if (GetDefaultPrinterW(default_printer, &size))
6030 return TRUE;
6032 pszPrinter = NULL;
6033 /* we have no default Printer: search local Printers and use the first */
6034 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
6036 default_printer[0] = '\0';
6037 size = ARRAY_SIZE(default_printer);
6038 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
6040 pszPrinter = default_printer;
6041 TRACE("using %s\n", debugstr_w(pszPrinter));
6043 RegCloseKey(hreg);
6046 if (pszPrinter == NULL) {
6047 TRACE("no local printer found\n");
6048 SetLastError(ERROR_FILE_NOT_FOUND);
6049 return FALSE;
6053 /* "pszPrinter" is never empty or NULL here. */
6054 namelen = lstrlenW(pszPrinter);
6055 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
6056 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
6057 if (!buffer ||
6058 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
6059 HeapFree(GetProcessHeap(), 0, buffer);
6060 SetLastError(ERROR_FILE_NOT_FOUND);
6061 return FALSE;
6064 /* read the devices entry for the printer (driver,port) to build the string for the
6065 default device entry (printer,driver,port) */
6066 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
6067 buffer[namelen] = ',';
6068 namelen++; /* move index to the start of the driver */
6070 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
6071 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
6072 if (!lres) {
6073 HKEY hdev;
6075 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev))
6077 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (BYTE *)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6078 RegCloseKey(hdev);
6081 else
6083 if (lres != ERROR_FILE_NOT_FOUND)
6084 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6086 SetLastError(ERROR_INVALID_PRINTER_NAME);
6089 RegCloseKey(hreg);
6090 HeapFree(GetProcessHeap(), 0, buffer);
6091 return (lres == ERROR_SUCCESS);
6094 /******************************************************************************
6095 * SetDefaultPrinterA (WINSPOOL.202)
6097 * See SetDefaultPrinterW.
6100 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6102 LPWSTR bufferW = NULL;
6103 BOOL res;
6105 TRACE("(%s)\n", debugstr_a(pszPrinter));
6106 if(pszPrinter) {
6107 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6108 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6109 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6111 res = SetDefaultPrinterW(bufferW);
6112 HeapFree(GetProcessHeap(), 0, bufferW);
6113 return res;
6116 /******************************************************************************
6117 * SetPrinterDataExA (WINSPOOL.@)
6119 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6120 LPCSTR pValueName, DWORD Type,
6121 LPBYTE pData, DWORD cbData)
6123 HKEY hkeyPrinter, hkeySubkey;
6124 DWORD ret;
6126 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6127 debugstr_a(pValueName), Type, pData, cbData);
6129 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6130 != ERROR_SUCCESS)
6131 return ret;
6133 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6134 != ERROR_SUCCESS) {
6135 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6136 RegCloseKey(hkeyPrinter);
6137 return ret;
6139 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6140 RegCloseKey(hkeySubkey);
6141 RegCloseKey(hkeyPrinter);
6142 return ret;
6145 /******************************************************************************
6146 * SetPrinterDataExW (WINSPOOL.@)
6148 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6149 LPCWSTR pValueName, DWORD Type,
6150 LPBYTE pData, DWORD cbData)
6152 HKEY hkeyPrinter, hkeySubkey;
6153 DWORD ret;
6155 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6156 debugstr_w(pValueName), Type, pData, cbData);
6158 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6159 != ERROR_SUCCESS)
6160 return ret;
6162 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6163 != ERROR_SUCCESS) {
6164 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6165 RegCloseKey(hkeyPrinter);
6166 return ret;
6168 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6169 RegCloseKey(hkeySubkey);
6170 RegCloseKey(hkeyPrinter);
6171 return ret;
6174 /******************************************************************************
6175 * SetPrinterDataA (WINSPOOL.@)
6177 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6178 LPBYTE pData, DWORD cbData)
6180 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6181 pData, cbData);
6184 /******************************************************************************
6185 * SetPrinterDataW (WINSPOOL.@)
6187 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6188 LPBYTE pData, DWORD cbData)
6190 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6191 pData, cbData);
6194 /******************************************************************************
6195 * GetPrinterDataExA (WINSPOOL.@)
6197 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6198 LPCSTR pValueName, LPDWORD pType,
6199 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6201 opened_printer_t *printer;
6202 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6203 DWORD ret;
6205 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6206 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6208 printer = get_opened_printer(hPrinter);
6209 if(!printer) return ERROR_INVALID_HANDLE;
6211 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6212 if (ret) return ret;
6214 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6216 if (printer->name) {
6218 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6219 if (ret) {
6220 RegCloseKey(hkeyPrinters);
6221 return ret;
6223 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6224 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6225 RegCloseKey(hkeyPrinter);
6226 RegCloseKey(hkeyPrinters);
6227 return ret;
6230 *pcbNeeded = nSize;
6231 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6232 0, pType, pData, pcbNeeded);
6234 if (!ret && !pData) ret = ERROR_MORE_DATA;
6236 RegCloseKey(hkeySubkey);
6237 RegCloseKey(hkeyPrinter);
6238 RegCloseKey(hkeyPrinters);
6240 TRACE("--> %d\n", ret);
6241 return ret;
6244 /******************************************************************************
6245 * GetPrinterDataExW (WINSPOOL.@)
6247 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6248 LPCWSTR pValueName, LPDWORD pType,
6249 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6251 opened_printer_t *printer;
6252 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6253 DWORD ret;
6255 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6256 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6258 printer = get_opened_printer(hPrinter);
6259 if(!printer) return ERROR_INVALID_HANDLE;
6261 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6262 if (ret) return ret;
6264 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6266 if (printer->name) {
6268 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6269 if (ret) {
6270 RegCloseKey(hkeyPrinters);
6271 return ret;
6273 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6274 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6275 RegCloseKey(hkeyPrinter);
6276 RegCloseKey(hkeyPrinters);
6277 return ret;
6280 *pcbNeeded = nSize;
6281 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6282 0, pType, pData, pcbNeeded);
6284 if (!ret && !pData) ret = ERROR_MORE_DATA;
6286 RegCloseKey(hkeySubkey);
6287 RegCloseKey(hkeyPrinter);
6288 RegCloseKey(hkeyPrinters);
6290 TRACE("--> %d\n", ret);
6291 return ret;
6294 /******************************************************************************
6295 * GetPrinterDataA (WINSPOOL.@)
6297 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6298 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6300 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6301 pData, nSize, pcbNeeded);
6304 /******************************************************************************
6305 * GetPrinterDataW (WINSPOOL.@)
6307 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6308 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6310 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6311 pData, nSize, pcbNeeded);
6314 /*******************************************************************************
6315 * EnumPrinterDataExW [WINSPOOL.@]
6317 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6318 LPBYTE pEnumValues, DWORD cbEnumValues,
6319 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6321 HKEY hkPrinter, hkSubKey;
6322 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6323 cbValueNameLen, cbMaxValueLen, cbValueLen,
6324 cbBufSize, dwType;
6325 LPWSTR lpValueName;
6326 HANDLE hHeap;
6327 PBYTE lpValue;
6328 PPRINTER_ENUM_VALUESW ppev;
6330 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6332 if (pKeyName == NULL || *pKeyName == 0)
6333 return ERROR_INVALID_PARAMETER;
6335 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6336 if (ret != ERROR_SUCCESS)
6338 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6339 hPrinter, ret);
6340 return ret;
6343 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6344 if (ret != ERROR_SUCCESS)
6346 r = RegCloseKey (hkPrinter);
6347 if (r != ERROR_SUCCESS)
6348 WARN ("RegCloseKey returned %i\n", r);
6349 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6350 debugstr_w (pKeyName), ret);
6351 return ret;
6354 ret = RegCloseKey (hkPrinter);
6355 if (ret != ERROR_SUCCESS)
6357 ERR ("RegCloseKey returned %i\n", ret);
6358 r = RegCloseKey (hkSubKey);
6359 if (r != ERROR_SUCCESS)
6360 WARN ("RegCloseKey returned %i\n", r);
6361 return ret;
6364 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6365 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6366 if (ret != ERROR_SUCCESS)
6368 r = RegCloseKey (hkSubKey);
6369 if (r != ERROR_SUCCESS)
6370 WARN ("RegCloseKey returned %i\n", r);
6371 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6372 return ret;
6375 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6376 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6378 if (cValues == 0) /* empty key */
6380 r = RegCloseKey (hkSubKey);
6381 if (r != ERROR_SUCCESS)
6382 WARN ("RegCloseKey returned %i\n", r);
6383 *pcbEnumValues = *pnEnumValues = 0;
6384 return ERROR_SUCCESS;
6387 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6389 hHeap = GetProcessHeap ();
6390 if (hHeap == NULL)
6392 ERR ("GetProcessHeap failed\n");
6393 r = RegCloseKey (hkSubKey);
6394 if (r != ERROR_SUCCESS)
6395 WARN ("RegCloseKey returned %i\n", r);
6396 return ERROR_OUTOFMEMORY;
6399 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6400 if (lpValueName == NULL)
6402 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6403 r = RegCloseKey (hkSubKey);
6404 if (r != ERROR_SUCCESS)
6405 WARN ("RegCloseKey returned %i\n", r);
6406 return ERROR_OUTOFMEMORY;
6409 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6410 if (lpValue == NULL)
6412 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6413 if (HeapFree (hHeap, 0, lpValueName) == 0)
6414 WARN ("HeapFree failed with code %i\n", GetLastError ());
6415 r = RegCloseKey (hkSubKey);
6416 if (r != ERROR_SUCCESS)
6417 WARN ("RegCloseKey returned %i\n", r);
6418 return ERROR_OUTOFMEMORY;
6421 TRACE ("pass 1: calculating buffer required for all names and values\n");
6423 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6425 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6427 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6429 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6430 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6431 NULL, NULL, lpValue, &cbValueLen);
6432 if (ret != ERROR_SUCCESS)
6434 if (HeapFree (hHeap, 0, lpValue) == 0)
6435 WARN ("HeapFree failed with code %i\n", GetLastError ());
6436 if (HeapFree (hHeap, 0, lpValueName) == 0)
6437 WARN ("HeapFree failed with code %i\n", GetLastError ());
6438 r = RegCloseKey (hkSubKey);
6439 if (r != ERROR_SUCCESS)
6440 WARN ("RegCloseKey returned %i\n", r);
6441 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6442 return ret;
6445 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6446 debugstr_w (lpValueName), dwIndex,
6447 cbValueNameLen + 1, cbValueLen);
6449 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6450 cbBufSize += cbValueLen;
6453 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6455 *pcbEnumValues = cbBufSize;
6456 *pnEnumValues = cValues;
6458 if (cbEnumValues < cbBufSize) /* buffer too small */
6460 if (HeapFree (hHeap, 0, lpValue) == 0)
6461 WARN ("HeapFree failed with code %i\n", GetLastError ());
6462 if (HeapFree (hHeap, 0, lpValueName) == 0)
6463 WARN ("HeapFree failed with code %i\n", GetLastError ());
6464 r = RegCloseKey (hkSubKey);
6465 if (r != ERROR_SUCCESS)
6466 WARN ("RegCloseKey returned %i\n", r);
6467 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6468 return ERROR_MORE_DATA;
6471 TRACE ("pass 2: copying all names and values to buffer\n");
6473 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6474 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6476 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6478 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6479 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6480 NULL, &dwType, lpValue, &cbValueLen);
6481 if (ret != ERROR_SUCCESS)
6483 if (HeapFree (hHeap, 0, lpValue) == 0)
6484 WARN ("HeapFree failed with code %i\n", GetLastError ());
6485 if (HeapFree (hHeap, 0, lpValueName) == 0)
6486 WARN ("HeapFree failed with code %i\n", GetLastError ());
6487 r = RegCloseKey (hkSubKey);
6488 if (r != ERROR_SUCCESS)
6489 WARN ("RegCloseKey returned %i\n", r);
6490 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6491 return ret;
6494 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6495 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6496 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6497 pEnumValues += cbValueNameLen;
6499 /* return # of *bytes* (including trailing \0), not # of chars */
6500 ppev[dwIndex].cbValueName = cbValueNameLen;
6502 ppev[dwIndex].dwType = dwType;
6504 memcpy (pEnumValues, lpValue, cbValueLen);
6505 ppev[dwIndex].pData = pEnumValues;
6506 pEnumValues += cbValueLen;
6508 ppev[dwIndex].cbData = cbValueLen;
6510 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6511 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6514 if (HeapFree (hHeap, 0, lpValue) == 0)
6516 ret = GetLastError ();
6517 ERR ("HeapFree failed with code %i\n", ret);
6518 if (HeapFree (hHeap, 0, lpValueName) == 0)
6519 WARN ("HeapFree failed with code %i\n", GetLastError ());
6520 r = RegCloseKey (hkSubKey);
6521 if (r != ERROR_SUCCESS)
6522 WARN ("RegCloseKey returned %i\n", r);
6523 return ret;
6526 if (HeapFree (hHeap, 0, lpValueName) == 0)
6528 ret = GetLastError ();
6529 ERR ("HeapFree failed with code %i\n", ret);
6530 r = RegCloseKey (hkSubKey);
6531 if (r != ERROR_SUCCESS)
6532 WARN ("RegCloseKey returned %i\n", r);
6533 return ret;
6536 ret = RegCloseKey (hkSubKey);
6537 if (ret != ERROR_SUCCESS)
6539 ERR ("RegCloseKey returned %i\n", ret);
6540 return ret;
6543 return ERROR_SUCCESS;
6546 /*******************************************************************************
6547 * EnumPrinterDataExA [WINSPOOL.@]
6549 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6550 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6551 * what Windows 2000 SP1 does.
6554 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6555 LPBYTE pEnumValues, DWORD cbEnumValues,
6556 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6558 INT len;
6559 LPWSTR pKeyNameW;
6560 DWORD ret, dwIndex, dwBufSize;
6561 HANDLE hHeap;
6562 LPSTR pBuffer;
6564 TRACE ("%p %s\n", hPrinter, pKeyName);
6566 if (pKeyName == NULL || *pKeyName == 0)
6567 return ERROR_INVALID_PARAMETER;
6569 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6570 if (len == 0)
6572 ret = GetLastError ();
6573 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6574 return ret;
6577 hHeap = GetProcessHeap ();
6578 if (hHeap == NULL)
6580 ERR ("GetProcessHeap failed\n");
6581 return ERROR_OUTOFMEMORY;
6584 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6585 if (pKeyNameW == NULL)
6587 ERR ("Failed to allocate %i bytes from process heap\n",
6588 (LONG)(len * sizeof (WCHAR)));
6589 return ERROR_OUTOFMEMORY;
6592 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6594 ret = GetLastError ();
6595 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6596 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6597 WARN ("HeapFree failed with code %i\n", GetLastError ());
6598 return ret;
6601 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6602 pcbEnumValues, pnEnumValues);
6603 if (ret != ERROR_SUCCESS)
6605 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6606 WARN ("HeapFree failed with code %i\n", GetLastError ());
6607 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6608 return ret;
6611 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6613 ret = GetLastError ();
6614 ERR ("HeapFree failed with code %i\n", ret);
6615 return ret;
6618 if (*pnEnumValues == 0) /* empty key */
6619 return ERROR_SUCCESS;
6621 dwBufSize = 0;
6622 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6624 PPRINTER_ENUM_VALUESW ppev =
6625 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6627 if (dwBufSize < ppev->cbValueName)
6628 dwBufSize = ppev->cbValueName;
6630 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6631 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6632 dwBufSize = ppev->cbData;
6635 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6637 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6638 if (pBuffer == NULL)
6640 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6641 return ERROR_OUTOFMEMORY;
6644 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6646 PPRINTER_ENUM_VALUESW ppev =
6647 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6649 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6650 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6651 NULL);
6652 if (len == 0)
6654 ret = GetLastError ();
6655 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6656 if (HeapFree (hHeap, 0, pBuffer) == 0)
6657 WARN ("HeapFree failed with code %i\n", GetLastError ());
6658 return ret;
6661 memcpy (ppev->pValueName, pBuffer, len);
6663 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6665 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6666 ppev->dwType != REG_MULTI_SZ)
6667 continue;
6669 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6670 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6671 if (len == 0)
6673 ret = GetLastError ();
6674 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6675 if (HeapFree (hHeap, 0, pBuffer) == 0)
6676 WARN ("HeapFree failed with code %i\n", GetLastError ());
6677 return ret;
6680 memcpy (ppev->pData, pBuffer, len);
6682 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6683 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6686 if (HeapFree (hHeap, 0, pBuffer) == 0)
6688 ret = GetLastError ();
6689 ERR ("HeapFree failed with code %i\n", ret);
6690 return ret;
6693 return ERROR_SUCCESS;
6696 /******************************************************************************
6697 * AbortPrinter (WINSPOOL.@)
6699 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6701 FIXME("(%p), stub!\n", hPrinter);
6702 return TRUE;
6705 /******************************************************************************
6706 * AddPortA (WINSPOOL.@)
6708 * See AddPortW.
6711 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6713 LPWSTR nameW = NULL;
6714 LPWSTR monitorW = NULL;
6715 DWORD len;
6716 BOOL res;
6718 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6720 if (pName) {
6721 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6722 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6723 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6726 if (pMonitorName) {
6727 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6728 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6729 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6731 res = AddPortW(nameW, hWnd, monitorW);
6732 HeapFree(GetProcessHeap(), 0, nameW);
6733 HeapFree(GetProcessHeap(), 0, monitorW);
6734 return res;
6737 /******************************************************************************
6738 * AddPortW (WINSPOOL.@)
6740 * Add a Port for a specific Monitor
6742 * PARAMS
6743 * pName [I] Servername or NULL (local Computer)
6744 * hWnd [I] Handle to parent Window for the Dialog-Box
6745 * pMonitorName [I] Name of the Monitor that manage the Port
6747 * RETURNS
6748 * Success: TRUE
6749 * Failure: FALSE
6752 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6754 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6756 if ((backend == NULL) && !load_backend()) return FALSE;
6758 if (!pMonitorName) {
6759 SetLastError(RPC_X_NULL_REF_POINTER);
6760 return FALSE;
6763 return backend->fpAddPort(pName, hWnd, pMonitorName);
6766 /******************************************************************************
6767 * AddPortExA (WINSPOOL.@)
6769 * See AddPortExW.
6772 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6774 PORT_INFO_2W pi2W;
6775 PORT_INFO_2A * pi2A;
6776 LPWSTR nameW = NULL;
6777 LPWSTR monitorW = NULL;
6778 DWORD len;
6779 BOOL res;
6781 pi2A = (PORT_INFO_2A *) pBuffer;
6783 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6784 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6786 if ((level < 1) || (level > 2)) {
6787 SetLastError(ERROR_INVALID_LEVEL);
6788 return FALSE;
6791 if (!pi2A) {
6792 SetLastError(ERROR_INVALID_PARAMETER);
6793 return FALSE;
6796 if (pName) {
6797 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6798 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6799 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6802 if (pMonitorName) {
6803 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6804 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6805 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6808 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6810 if (pi2A->pPortName) {
6811 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6812 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6813 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6816 if (level > 1) {
6817 if (pi2A->pMonitorName) {
6818 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6819 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6820 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6823 if (pi2A->pDescription) {
6824 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6825 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6826 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6828 pi2W.fPortType = pi2A->fPortType;
6829 pi2W.Reserved = pi2A->Reserved;
6832 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6834 HeapFree(GetProcessHeap(), 0, nameW);
6835 HeapFree(GetProcessHeap(), 0, monitorW);
6836 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6837 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6838 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6839 return res;
6843 /******************************************************************************
6844 * AddPortExW (WINSPOOL.@)
6846 * Add a Port for a specific Monitor, without presenting a user interface
6848 * PARAMS
6849 * pName [I] Servername or NULL (local Computer)
6850 * level [I] Structure-Level (1 or 2) for pBuffer
6851 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6852 * pMonitorName [I] Name of the Monitor that manage the Port
6854 * RETURNS
6855 * Success: TRUE
6856 * Failure: FALSE
6859 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6861 PORT_INFO_2W * pi2;
6863 pi2 = (PORT_INFO_2W *) pBuffer;
6865 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6866 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6867 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6868 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6870 if ((backend == NULL) && !load_backend()) return FALSE;
6872 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6873 SetLastError(ERROR_INVALID_PARAMETER);
6874 return FALSE;
6877 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6880 /******************************************************************************
6881 * AddPrinterConnectionA (WINSPOOL.@)
6883 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6885 FIXME("%s\n", debugstr_a(pName));
6886 return FALSE;
6889 /******************************************************************************
6890 * AddPrinterConnectionW (WINSPOOL.@)
6892 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6894 FIXME("%s\n", debugstr_w(pName));
6895 return FALSE;
6898 /******************************************************************************
6899 * AddPrinterDriverExW (WINSPOOL.@)
6901 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6903 * PARAMS
6904 * pName [I] Servername or NULL (local Computer)
6905 * level [I] Level for the supplied DRIVER_INFO_*W struct
6906 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6907 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6909 * RESULTS
6910 * Success: TRUE
6911 * Failure: FALSE
6914 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6916 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6918 if ((backend == NULL) && !load_backend()) return FALSE;
6920 if (level < 2 || level == 5 || level == 7 || level > 8) {
6921 SetLastError(ERROR_INVALID_LEVEL);
6922 return FALSE;
6925 if (!pDriverInfo) {
6926 SetLastError(ERROR_INVALID_PARAMETER);
6927 return FALSE;
6930 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6933 /******************************************************************************
6934 * AddPrinterDriverExA (WINSPOOL.@)
6936 * See AddPrinterDriverExW.
6939 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6941 DRIVER_INFO_8A *diA;
6942 DRIVER_INFO_8W diW;
6943 LPWSTR nameW = NULL;
6944 DWORD lenA;
6945 DWORD len;
6946 BOOL res = FALSE;
6948 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6950 diA = (DRIVER_INFO_8A *) pDriverInfo;
6951 ZeroMemory(&diW, sizeof(diW));
6953 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6954 SetLastError(ERROR_INVALID_LEVEL);
6955 return FALSE;
6958 if (diA == NULL) {
6959 SetLastError(ERROR_INVALID_PARAMETER);
6960 return FALSE;
6963 /* convert servername to unicode */
6964 if (pName) {
6965 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6966 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6967 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6970 /* common fields */
6971 diW.cVersion = diA->cVersion;
6973 if (diA->pName) {
6974 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6975 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6976 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6979 if (diA->pEnvironment) {
6980 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6981 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6982 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6985 if (diA->pDriverPath) {
6986 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6987 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6988 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6991 if (diA->pDataFile) {
6992 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6993 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6994 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6997 if (diA->pConfigFile) {
6998 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6999 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7000 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
7003 if ((Level > 2) && diA->pHelpFile) {
7004 len = MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, NULL, 0);
7005 diW.pHelpFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7006 MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, diW.pHelpFile, len);
7009 if ((Level > 2) && diA->pDependentFiles) {
7010 lenA = multi_sz_lenA(diA->pDependentFiles);
7011 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
7012 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7013 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
7016 if ((Level > 2) && diA->pMonitorName) {
7017 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
7018 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7019 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
7022 if ((Level > 2) && diA->pDefaultDataType) {
7023 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
7024 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7025 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
7028 if ((Level > 3) && diA->pszzPreviousNames) {
7029 lenA = multi_sz_lenA(diA->pszzPreviousNames);
7030 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
7031 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7032 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
7035 if (Level > 5) {
7036 diW.ftDriverDate = diA->ftDriverDate;
7037 diW.dwlDriverVersion = diA->dwlDriverVersion;
7040 if ((Level > 5) && diA->pszMfgName) {
7041 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
7042 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7043 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
7046 if ((Level > 5) && diA->pszOEMUrl) {
7047 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
7048 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7049 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
7052 if ((Level > 5) && diA->pszHardwareID) {
7053 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
7054 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7055 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
7058 if ((Level > 5) && diA->pszProvider) {
7059 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
7060 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7061 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
7064 if ((Level > 7) && diA->pszPrintProcessor) {
7065 len = MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, NULL, 0);
7066 diW.pszPrintProcessor = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7067 MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, diW.pszPrintProcessor, len);
7070 if ((Level > 7) && diA->pszVendorSetup) {
7071 len = MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, NULL, 0);
7072 diW.pszVendorSetup = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7073 MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, diW.pszVendorSetup, len);
7076 if ((Level > 7) && diA->pszzColorProfiles) {
7077 lenA = multi_sz_lenA(diA->pszzColorProfiles);
7078 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, NULL, 0);
7079 diW.pszzColorProfiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7080 MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, diW.pszzColorProfiles, len);
7083 if ((Level > 7) && diA->pszInfPath) {
7084 len = MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, NULL, 0);
7085 diW.pszInfPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7086 MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, diW.pszInfPath, len);
7089 if ((Level > 7) && diA->pszzCoreDriverDependencies) {
7090 lenA = multi_sz_lenA(diA->pszzCoreDriverDependencies);
7091 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, NULL, 0);
7092 diW.pszzCoreDriverDependencies = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7093 MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, diW.pszzCoreDriverDependencies, len);
7096 if (Level > 7) {
7097 diW.dwPrinterDriverAttributes = diA->dwPrinterDriverAttributes;
7098 diW.ftMinInboxDriverVerDate = diA->ftMinInboxDriverVerDate;
7099 diW.dwlMinInboxDriverVerVersion = diA->dwlMinInboxDriverVerVersion;
7102 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
7103 TRACE("got %u with %u\n", res, GetLastError());
7104 HeapFree(GetProcessHeap(), 0, nameW);
7105 HeapFree(GetProcessHeap(), 0, diW.pName);
7106 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
7107 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
7108 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
7109 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
7110 HeapFree(GetProcessHeap(), 0, diW.pHelpFile);
7111 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
7112 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
7113 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
7114 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
7115 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
7116 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
7117 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
7118 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
7119 HeapFree(GetProcessHeap(), 0, diW.pszPrintProcessor);
7120 HeapFree(GetProcessHeap(), 0, diW.pszVendorSetup);
7121 HeapFree(GetProcessHeap(), 0, diW.pszzColorProfiles);
7122 HeapFree(GetProcessHeap(), 0, diW.pszInfPath);
7123 HeapFree(GetProcessHeap(), 0, diW.pszzCoreDriverDependencies);
7125 TRACE("=> %u with %u\n", res, GetLastError());
7126 return res;
7129 /******************************************************************************
7130 * ConfigurePortA (WINSPOOL.@)
7132 * See ConfigurePortW.
7135 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7137 LPWSTR nameW = NULL;
7138 LPWSTR portW = NULL;
7139 INT len;
7140 DWORD res;
7142 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7144 /* convert servername to unicode */
7145 if (pName) {
7146 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7147 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7148 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7151 /* convert portname to unicode */
7152 if (pPortName) {
7153 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7154 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7155 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7158 res = ConfigurePortW(nameW, hWnd, portW);
7159 HeapFree(GetProcessHeap(), 0, nameW);
7160 HeapFree(GetProcessHeap(), 0, portW);
7161 return res;
7164 /******************************************************************************
7165 * ConfigurePortW (WINSPOOL.@)
7167 * Display the Configuration-Dialog for a specific Port
7169 * PARAMS
7170 * pName [I] Servername or NULL (local Computer)
7171 * hWnd [I] Handle to parent Window for the Dialog-Box
7172 * pPortName [I] Name of the Port, that should be configured
7174 * RETURNS
7175 * Success: TRUE
7176 * Failure: FALSE
7179 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7182 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7184 if ((backend == NULL) && !load_backend()) return FALSE;
7186 if (!pPortName) {
7187 SetLastError(RPC_X_NULL_REF_POINTER);
7188 return FALSE;
7191 return backend->fpConfigurePort(pName, hWnd, pPortName);
7194 /******************************************************************************
7195 * ConnectToPrinterDlg (WINSPOOL.@)
7197 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7199 FIXME("%p %x\n", hWnd, Flags);
7200 return NULL;
7203 /******************************************************************************
7204 * DeletePrinterConnectionA (WINSPOOL.@)
7206 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7208 FIXME("%s\n", debugstr_a(pName));
7209 return TRUE;
7212 /******************************************************************************
7213 * DeletePrinterConnectionW (WINSPOOL.@)
7215 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7217 FIXME("%s\n", debugstr_w(pName));
7218 return TRUE;
7221 /******************************************************************************
7222 * DeletePrinterDriverExW (WINSPOOL.@)
7224 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7225 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7227 HKEY hkey_drivers;
7228 BOOL ret = FALSE;
7230 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7231 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7233 if(pName && pName[0])
7235 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7236 SetLastError(ERROR_INVALID_PARAMETER);
7237 return FALSE;
7240 if(dwDeleteFlag)
7242 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7243 SetLastError(ERROR_INVALID_PARAMETER);
7244 return FALSE;
7247 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7249 if(!hkey_drivers)
7251 ERR("Can't open drivers key\n");
7252 return FALSE;
7255 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7256 ret = TRUE;
7258 RegCloseKey(hkey_drivers);
7260 return ret;
7263 /******************************************************************************
7264 * DeletePrinterDriverExA (WINSPOOL.@)
7266 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7267 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7269 UNICODE_STRING NameW, EnvW, DriverW;
7270 BOOL ret;
7272 asciitounicode(&NameW, pName);
7273 asciitounicode(&EnvW, pEnvironment);
7274 asciitounicode(&DriverW, pDriverName);
7276 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7278 RtlFreeUnicodeString(&DriverW);
7279 RtlFreeUnicodeString(&EnvW);
7280 RtlFreeUnicodeString(&NameW);
7282 return ret;
7285 /******************************************************************************
7286 * DeletePrinterDataExW (WINSPOOL.@)
7288 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7289 LPCWSTR pValueName)
7291 FIXME("%p %s %s\n", hPrinter,
7292 debugstr_w(pKeyName), debugstr_w(pValueName));
7293 return ERROR_INVALID_PARAMETER;
7296 /******************************************************************************
7297 * DeletePrinterDataExA (WINSPOOL.@)
7299 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7300 LPCSTR pValueName)
7302 FIXME("%p %s %s\n", hPrinter,
7303 debugstr_a(pKeyName), debugstr_a(pValueName));
7304 return ERROR_INVALID_PARAMETER;
7307 /******************************************************************************
7308 * DeletePrintProcessorA (WINSPOOL.@)
7310 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7312 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7313 debugstr_a(pPrintProcessorName));
7314 return TRUE;
7317 /******************************************************************************
7318 * DeletePrintProcessorW (WINSPOOL.@)
7320 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7322 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7323 debugstr_w(pPrintProcessorName));
7324 return TRUE;
7327 /******************************************************************************
7328 * DeletePrintProvidorA (WINSPOOL.@)
7330 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7332 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7333 debugstr_a(pPrintProviderName));
7334 return TRUE;
7337 /******************************************************************************
7338 * DeletePrintProvidorW (WINSPOOL.@)
7340 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7342 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7343 debugstr_w(pPrintProviderName));
7344 return TRUE;
7347 /******************************************************************************
7348 * EnumFormsA (WINSPOOL.@)
7350 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7351 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7353 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7354 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7355 return FALSE;
7358 /******************************************************************************
7359 * EnumFormsW (WINSPOOL.@)
7361 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7362 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7364 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7365 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7366 return FALSE;
7369 /*****************************************************************************
7370 * EnumMonitorsA [WINSPOOL.@]
7372 * See EnumMonitorsW.
7375 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7376 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7378 BOOL res;
7379 LPBYTE bufferW = NULL;
7380 LPWSTR nameW = NULL;
7381 DWORD needed = 0;
7382 DWORD numentries = 0;
7383 INT len;
7385 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7386 cbBuf, pcbNeeded, pcReturned);
7388 /* convert servername to unicode */
7389 if (pName) {
7390 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7391 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7392 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7394 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7395 needed = cbBuf * sizeof(WCHAR);
7396 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7397 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7399 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7400 if (pcbNeeded) needed = *pcbNeeded;
7401 /* HeapReAlloc return NULL, when bufferW was NULL */
7402 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7403 HeapAlloc(GetProcessHeap(), 0, needed);
7405 /* Try again with the large Buffer */
7406 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7408 numentries = pcReturned ? *pcReturned : 0;
7409 needed = 0;
7411 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7412 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7414 if (res) {
7415 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7416 DWORD entrysize = 0;
7417 DWORD index;
7418 LPSTR ptr;
7419 LPMONITOR_INFO_2W mi2w;
7420 LPMONITOR_INFO_2A mi2a;
7422 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7423 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7425 /* First pass: calculate the size for all Entries */
7426 mi2w = (LPMONITOR_INFO_2W) bufferW;
7427 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7428 index = 0;
7429 while (index < numentries) {
7430 index++;
7431 needed += entrysize; /* MONITOR_INFO_?A */
7432 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7434 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7435 NULL, 0, NULL, NULL);
7436 if (Level > 1) {
7437 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7438 NULL, 0, NULL, NULL);
7439 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7440 NULL, 0, NULL, NULL);
7442 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7443 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7444 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7447 /* check for errors and quit on failure */
7448 if (cbBuf < needed) {
7449 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7450 res = FALSE;
7451 goto emA_cleanup;
7453 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7454 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7455 cbBuf -= len ; /* free Bytes in the user-Buffer */
7456 mi2w = (LPMONITOR_INFO_2W) bufferW;
7457 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7458 index = 0;
7459 /* Second Pass: Fill the User Buffer (if we have one) */
7460 while ((index < numentries) && pMonitors) {
7461 index++;
7462 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7463 mi2a->pName = ptr;
7464 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7465 ptr, cbBuf , NULL, NULL);
7466 ptr += len;
7467 cbBuf -= len;
7468 if (Level > 1) {
7469 mi2a->pEnvironment = ptr;
7470 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7471 ptr, cbBuf, NULL, NULL);
7472 ptr += len;
7473 cbBuf -= len;
7475 mi2a->pDLLName = ptr;
7476 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7477 ptr, cbBuf, NULL, NULL);
7478 ptr += len;
7479 cbBuf -= len;
7481 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7482 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7483 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7486 emA_cleanup:
7487 if (pcbNeeded) *pcbNeeded = needed;
7488 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7490 HeapFree(GetProcessHeap(), 0, nameW);
7491 HeapFree(GetProcessHeap(), 0, bufferW);
7493 TRACE("returning %d with %d (%d byte for %d entries)\n",
7494 (res), GetLastError(), needed, numentries);
7496 return (res);
7500 /*****************************************************************************
7501 * EnumMonitorsW [WINSPOOL.@]
7503 * Enumerate available Port-Monitors
7505 * PARAMS
7506 * pName [I] Servername or NULL (local Computer)
7507 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7508 * pMonitors [O] PTR to Buffer that receives the Result
7509 * cbBuf [I] Size of Buffer at pMonitors
7510 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7511 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7513 * RETURNS
7514 * Success: TRUE
7515 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7518 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7519 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7522 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7523 cbBuf, pcbNeeded, pcReturned);
7525 if ((backend == NULL) && !load_backend()) return FALSE;
7527 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7528 SetLastError(RPC_X_NULL_REF_POINTER);
7529 return FALSE;
7532 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7535 /******************************************************************************
7536 * SpoolerInit (WINSPOOL.@)
7538 * Initialize the Spooler
7540 * RETURNS
7541 * Success: TRUE
7542 * Failure: FALSE
7544 * NOTES
7545 * The function fails on windows, when the spooler service is not running
7548 BOOL WINAPI SpoolerInit(void)
7551 if ((backend == NULL) && !load_backend()) return FALSE;
7552 return TRUE;
7555 /******************************************************************************
7556 * XcvDataW (WINSPOOL.@)
7558 * Execute commands in the Printmonitor DLL
7560 * PARAMS
7561 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7562 * pszDataName [i] Name of the command to execute
7563 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7564 * cbInputData [i] Size in Bytes of Buffer at pInputData
7565 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7566 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7567 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7568 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7570 * RETURNS
7571 * Success: TRUE
7572 * Failure: FALSE
7574 * NOTES
7575 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7576 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7578 * Minimal List of commands, that a Printmonitor DLL should support:
7580 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7581 *| "AddPort" : Add a Port
7582 *| "DeletePort": Delete a Port
7584 * Many Printmonitors support additional commands. Examples for localspl.dll:
7585 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7586 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7589 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7590 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7591 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7593 opened_printer_t *printer;
7595 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7596 pInputData, cbInputData, pOutputData,
7597 cbOutputData, pcbOutputNeeded, pdwStatus);
7599 if ((backend == NULL) && !load_backend()) return FALSE;
7601 printer = get_opened_printer(hXcv);
7602 if (!printer || (!printer->backend_printer)) {
7603 SetLastError(ERROR_INVALID_HANDLE);
7604 return FALSE;
7607 if (!pcbOutputNeeded) {
7608 SetLastError(ERROR_INVALID_PARAMETER);
7609 return FALSE;
7612 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7613 SetLastError(RPC_X_NULL_REF_POINTER);
7614 return FALSE;
7617 *pcbOutputNeeded = 0;
7619 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7620 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7624 /*****************************************************************************
7625 * EnumPrinterDataA [WINSPOOL.@]
7628 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7629 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7630 DWORD cbData, LPDWORD pcbData )
7632 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7633 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7634 return ERROR_NO_MORE_ITEMS;
7637 /*****************************************************************************
7638 * EnumPrinterDataW [WINSPOOL.@]
7641 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7642 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7643 DWORD cbData, LPDWORD pcbData )
7645 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7646 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7647 return ERROR_NO_MORE_ITEMS;
7650 /*****************************************************************************
7651 * EnumPrinterKeyA [WINSPOOL.@]
7654 DWORD WINAPI EnumPrinterKeyA(HANDLE printer, const CHAR *key, CHAR *subkey, DWORD size, DWORD *needed)
7656 FIXME("%p %s %p %x %p\n", printer, debugstr_a(key), subkey, size, needed);
7657 return ERROR_CALL_NOT_IMPLEMENTED;
7660 /*****************************************************************************
7661 * EnumPrinterKeyW [WINSPOOL.@]
7664 DWORD WINAPI EnumPrinterKeyW(HANDLE printer, const WCHAR *key, WCHAR *subkey, DWORD size, DWORD *needed)
7666 FIXME("%p %s %p %x %p\n", printer, debugstr_w(key), subkey, size, needed);
7667 return ERROR_CALL_NOT_IMPLEMENTED;
7670 /*****************************************************************************
7671 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7674 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7675 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7676 LPDWORD pcbNeeded, LPDWORD pcReturned)
7678 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7679 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7680 pcbNeeded, pcReturned);
7681 return FALSE;
7684 /*****************************************************************************
7685 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7688 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7689 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7690 LPDWORD pcbNeeded, LPDWORD pcReturned)
7692 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7693 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7694 pcbNeeded, pcReturned);
7695 return FALSE;
7698 /*****************************************************************************
7699 * EnumPrintProcessorsA [WINSPOOL.@]
7701 * See EnumPrintProcessorsW.
7704 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7705 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7707 BOOL res;
7708 LPBYTE bufferW = NULL;
7709 LPWSTR nameW = NULL;
7710 LPWSTR envW = NULL;
7711 DWORD needed = 0;
7712 DWORD numentries = 0;
7713 INT len;
7715 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7716 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7718 /* convert names to unicode */
7719 if (pName) {
7720 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7721 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7722 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7724 if (pEnvironment) {
7725 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7726 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7727 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7730 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7731 needed = cbBuf * sizeof(WCHAR);
7732 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7733 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7735 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7736 if (pcbNeeded) needed = *pcbNeeded;
7737 /* HeapReAlloc return NULL, when bufferW was NULL */
7738 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7739 HeapAlloc(GetProcessHeap(), 0, needed);
7741 /* Try again with the large Buffer */
7742 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7744 numentries = pcReturned ? *pcReturned : 0;
7745 needed = 0;
7747 if (res) {
7748 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7749 DWORD index;
7750 LPSTR ptr;
7751 PPRINTPROCESSOR_INFO_1W ppiw;
7752 PPRINTPROCESSOR_INFO_1A ppia;
7754 /* First pass: calculate the size for all Entries */
7755 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7756 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7757 index = 0;
7758 while (index < numentries) {
7759 index++;
7760 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7761 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7763 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7764 NULL, 0, NULL, NULL);
7766 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7767 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7770 /* check for errors and quit on failure */
7771 if (cbBuf < needed) {
7772 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7773 res = FALSE;
7774 goto epp_cleanup;
7777 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7778 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7779 cbBuf -= len ; /* free Bytes in the user-Buffer */
7780 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7781 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7782 index = 0;
7783 /* Second Pass: Fill the User Buffer (if we have one) */
7784 while ((index < numentries) && pPPInfo) {
7785 index++;
7786 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7787 ppia->pName = ptr;
7788 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7789 ptr, cbBuf , NULL, NULL);
7790 ptr += len;
7791 cbBuf -= len;
7793 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7794 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7798 epp_cleanup:
7799 if (pcbNeeded) *pcbNeeded = needed;
7800 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7802 HeapFree(GetProcessHeap(), 0, nameW);
7803 HeapFree(GetProcessHeap(), 0, envW);
7804 HeapFree(GetProcessHeap(), 0, bufferW);
7806 TRACE("returning %d with %d (%d byte for %d entries)\n",
7807 (res), GetLastError(), needed, numentries);
7809 return (res);
7812 /*****************************************************************************
7813 * EnumPrintProcessorsW [WINSPOOL.@]
7815 * Enumerate available Print Processors
7817 * PARAMS
7818 * pName [I] Servername or NULL (local Computer)
7819 * pEnvironment [I] Printing-Environment or NULL (Default)
7820 * Level [I] Structure-Level (Only 1 is allowed)
7821 * pPPInfo [O] PTR to Buffer that receives the Result
7822 * cbBuf [I] Size of Buffer at pPPInfo
7823 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7824 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7826 * RETURNS
7827 * Success: TRUE
7828 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7831 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7832 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7835 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7836 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7838 if ((backend == NULL) && !load_backend()) return FALSE;
7840 if (!pcbNeeded || !pcReturned) {
7841 SetLastError(RPC_X_NULL_REF_POINTER);
7842 return FALSE;
7845 if (!pPPInfo && (cbBuf > 0)) {
7846 SetLastError(ERROR_INVALID_USER_BUFFER);
7847 return FALSE;
7850 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7851 cbBuf, pcbNeeded, pcReturned);
7854 /*****************************************************************************
7855 * ExtDeviceMode [WINSPOOL.@]
7858 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7859 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7860 DWORD fMode)
7862 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7863 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7864 debugstr_a(pProfile), fMode);
7865 return -1;
7868 /*****************************************************************************
7869 * FindClosePrinterChangeNotification [WINSPOOL.@]
7872 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7874 FIXME("Stub: %p\n", hChange);
7875 return TRUE;
7878 /*****************************************************************************
7879 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7882 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7883 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7885 FIXME("Stub: %p %x %x %p\n",
7886 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7887 return INVALID_HANDLE_VALUE;
7890 /*****************************************************************************
7891 * FindNextPrinterChangeNotification [WINSPOOL.@]
7894 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7895 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7897 FIXME("Stub: %p %p %p %p\n",
7898 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7899 return FALSE;
7902 /*****************************************************************************
7903 * FreePrinterNotifyInfo [WINSPOOL.@]
7906 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7908 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7909 return TRUE;
7912 /*****************************************************************************
7913 * string_to_buf
7915 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7916 * ansi depending on the unicode parameter.
7918 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7920 if(!str)
7922 *size = 0;
7923 return TRUE;
7926 if(unicode)
7928 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7929 if(*size <= cb)
7931 memcpy(ptr, str, *size);
7932 return TRUE;
7934 return FALSE;
7936 else
7938 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7939 if(*size <= cb)
7941 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7942 return TRUE;
7944 return FALSE;
7948 /*****************************************************************************
7949 * get_job_info_1
7951 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7952 LPDWORD pcbNeeded, BOOL unicode)
7954 DWORD size, left = cbBuf;
7955 BOOL space = (cbBuf > 0);
7956 LPBYTE ptr = buf;
7958 *pcbNeeded = 0;
7960 if(space)
7962 ji1->JobId = job->job_id;
7965 string_to_buf(job->document_title, ptr, left, &size, unicode);
7966 if(space && size <= left)
7968 ji1->pDocument = (LPWSTR)ptr;
7969 ptr += size;
7970 left -= size;
7972 else
7973 space = FALSE;
7974 *pcbNeeded += size;
7976 if (job->printer_name)
7978 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7979 if(space && size <= left)
7981 ji1->pPrinterName = (LPWSTR)ptr;
7982 ptr += size;
7983 left -= size;
7985 else
7986 space = FALSE;
7987 *pcbNeeded += size;
7990 return space;
7993 /*****************************************************************************
7994 * get_job_info_2
7996 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7997 LPDWORD pcbNeeded, BOOL unicode)
7999 DWORD size, left = cbBuf;
8000 DWORD shift;
8001 BOOL space = (cbBuf > 0);
8002 LPBYTE ptr = buf;
8003 LPDEVMODEA dmA = NULL;
8004 LPDEVMODEW devmode;
8006 *pcbNeeded = 0;
8008 if(space)
8010 ji2->JobId = job->job_id;
8013 string_to_buf(job->document_title, ptr, left, &size, unicode);
8014 if(space && size <= left)
8016 ji2->pDocument = (LPWSTR)ptr;
8017 ptr += size;
8018 left -= size;
8020 else
8021 space = FALSE;
8022 *pcbNeeded += size;
8024 if (job->printer_name)
8026 string_to_buf(job->printer_name, ptr, left, &size, unicode);
8027 if(space && size <= left)
8029 ji2->pPrinterName = (LPWSTR)ptr;
8030 ptr += size;
8031 left -= size;
8033 else
8034 space = FALSE;
8035 *pcbNeeded += size;
8038 if (job->devmode)
8040 if (!unicode)
8042 dmA = DEVMODEdupWtoA(job->devmode);
8043 devmode = (LPDEVMODEW) dmA;
8044 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
8046 else
8048 devmode = job->devmode;
8049 size = devmode->dmSize + devmode->dmDriverExtra;
8052 if (!devmode)
8053 FIXME("Can't convert DEVMODE W to A\n");
8054 else
8056 /* align DEVMODE to a DWORD boundary */
8057 shift = (4 - (*pcbNeeded & 3)) & 3;
8058 size += shift;
8060 if (size <= left)
8062 ptr += shift;
8063 memcpy(ptr, devmode, size-shift);
8064 ji2->pDevMode = (LPDEVMODEW)ptr;
8065 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
8066 ptr += size-shift;
8067 left -= size;
8069 else
8070 space = FALSE;
8071 *pcbNeeded +=size;
8075 return space;
8078 /*****************************************************************************
8079 * get_job_info
8081 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8082 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
8084 BOOL ret = FALSE;
8085 DWORD needed = 0, size;
8086 job_t *job;
8087 LPBYTE ptr = pJob;
8089 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
8091 EnterCriticalSection(&printer_handles_cs);
8092 job = get_job(hPrinter, JobId);
8093 if(!job)
8094 goto end;
8096 switch(Level)
8098 case 1:
8099 size = sizeof(JOB_INFO_1W);
8100 if(cbBuf >= size)
8102 cbBuf -= size;
8103 ptr += size;
8104 memset(pJob, 0, size);
8106 else
8107 cbBuf = 0;
8108 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
8109 needed += size;
8110 break;
8112 case 2:
8113 size = sizeof(JOB_INFO_2W);
8114 if(cbBuf >= size)
8116 cbBuf -= size;
8117 ptr += size;
8118 memset(pJob, 0, size);
8120 else
8121 cbBuf = 0;
8122 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
8123 needed += size;
8124 break;
8126 case 3:
8127 size = sizeof(JOB_INFO_3);
8128 if(cbBuf >= size)
8130 cbBuf -= size;
8131 memset(pJob, 0, size);
8132 ret = TRUE;
8134 else
8135 cbBuf = 0;
8136 needed = size;
8137 break;
8139 default:
8140 SetLastError(ERROR_INVALID_LEVEL);
8141 goto end;
8143 if(pcbNeeded)
8144 *pcbNeeded = needed;
8145 end:
8146 LeaveCriticalSection(&printer_handles_cs);
8147 return ret;
8150 /*****************************************************************************
8151 * GetJobA [WINSPOOL.@]
8154 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8155 DWORD cbBuf, LPDWORD pcbNeeded)
8157 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8160 /*****************************************************************************
8161 * GetJobW [WINSPOOL.@]
8164 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8165 DWORD cbBuf, LPDWORD pcbNeeded)
8167 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8170 /*****************************************************************************
8171 * schedule_pipe
8173 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8175 #ifdef HAVE_FORK
8176 char *unixname, *cmdA;
8177 DWORD len;
8178 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8179 BOOL ret = FALSE;
8180 char buf[1024];
8181 pid_t pid, wret;
8182 int status;
8184 if(!(unixname = wine_get_unix_file_name(filename)))
8185 return FALSE;
8187 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8188 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8189 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8191 TRACE("printing with: %s\n", cmdA);
8193 if((file_fd = open(unixname, O_RDONLY)) == -1)
8194 goto end;
8196 if (pipe(fds))
8198 ERR("pipe() failed!\n");
8199 goto end;
8202 if ((pid = fork()) == 0)
8204 close(0);
8205 dup2(fds[0], 0);
8206 close(fds[1]);
8208 /* reset signals that we previously set to SIG_IGN */
8209 signal(SIGPIPE, SIG_DFL);
8211 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8212 _exit(1);
8214 else if (pid == -1)
8216 ERR("fork() failed!\n");
8217 goto end;
8220 close(fds[0]);
8221 fds[0] = -1;
8222 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8223 write(fds[1], buf, no_read);
8225 close(fds[1]);
8226 fds[1] = -1;
8228 /* reap child */
8229 do {
8230 wret = waitpid(pid, &status, 0);
8231 } while (wret < 0 && errno == EINTR);
8232 if (wret < 0)
8234 ERR("waitpid() failed!\n");
8235 goto end;
8237 if (!WIFEXITED(status) || WEXITSTATUS(status))
8239 ERR("child process failed! %d\n", status);
8240 goto end;
8243 ret = TRUE;
8245 end:
8246 if(file_fd != -1) close(file_fd);
8247 if(fds[0] != -1) close(fds[0]);
8248 if(fds[1] != -1) close(fds[1]);
8250 HeapFree(GetProcessHeap(), 0, cmdA);
8251 HeapFree(GetProcessHeap(), 0, unixname);
8252 return ret;
8253 #else
8254 return FALSE;
8255 #endif
8258 /*****************************************************************************
8259 * schedule_lpr
8261 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8263 static const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8264 WCHAR *cmd;
8265 BOOL r;
8267 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8268 sprintfW(cmd, fmtW, printer_name);
8270 r = schedule_pipe(cmd, filename);
8272 HeapFree(GetProcessHeap(), 0, cmd);
8273 return r;
8276 #ifdef SONAME_LIBCUPS
8277 /*****************************************************************************
8278 * get_cups_jobs_ticket_options
8280 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8281 * The CUPS scheduler only looks for these in Print-File requests, and since
8282 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8283 * parsed.
8285 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8287 FILE *fp = fopen( file, "r" );
8288 char buf[257]; /* DSC max of 256 + '\0' */
8289 const char *ps_adobe = "%!PS-Adobe-";
8290 const char *cups_job = "%cupsJobTicket:";
8292 if (!fp) return num_options;
8293 if (!fgets( buf, sizeof(buf), fp )) goto end;
8294 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8295 while (fgets( buf, sizeof(buf), fp ))
8297 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8298 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8301 end:
8302 fclose( fp );
8303 return num_options;
8306 static int get_cups_default_options( const char *printer, int num_options, cups_option_t **options )
8308 cups_dest_t *dest;
8309 int i;
8311 if (!pcupsGetNamedDest) return num_options;
8313 dest = pcupsGetNamedDest( NULL, printer, NULL );
8314 if (!dest) return num_options;
8316 for (i = 0; i < dest->num_options; i++)
8318 if (!pcupsGetOption( dest->options[i].name, num_options, *options ))
8319 num_options = pcupsAddOption( dest->options[i].name, dest->options[i].value,
8320 num_options, options );
8323 pcupsFreeDests( 1, dest );
8324 return num_options;
8326 #endif
8328 /*****************************************************************************
8329 * schedule_cups
8331 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8333 #ifdef SONAME_LIBCUPS
8334 if(pcupsPrintFile)
8336 char *unixname, *queue, *unix_doc_title;
8337 DWORD len;
8338 BOOL ret;
8339 int num_options = 0, i;
8340 cups_option_t *options = NULL;
8342 if(!(unixname = wine_get_unix_file_name(filename)))
8343 return FALSE;
8345 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8346 queue = HeapAlloc(GetProcessHeap(), 0, len);
8347 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8349 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8350 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8351 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8353 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8354 num_options = get_cups_default_options( queue, num_options, &options );
8356 TRACE( "printing via cups with options:\n" );
8357 for (i = 0; i < num_options; i++)
8358 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8360 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8361 if (ret == 0 && pcupsLastErrorString)
8362 WARN("cupsPrintFile failed with error %s\n", debugstr_a(pcupsLastErrorString()));
8364 pcupsFreeOptions( num_options, options );
8366 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8367 HeapFree(GetProcessHeap(), 0, queue);
8368 HeapFree(GetProcessHeap(), 0, unixname);
8369 return ret;
8371 else
8372 #endif
8374 return schedule_lpr(printer_name, filename);
8378 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8380 LPWSTR filename;
8382 switch(msg)
8384 case WM_INITDIALOG:
8385 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8386 return TRUE;
8388 case WM_COMMAND:
8389 if(HIWORD(wparam) == BN_CLICKED)
8391 if(LOWORD(wparam) == IDOK)
8393 HANDLE hf;
8394 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8395 LPWSTR *output;
8397 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8398 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8400 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8402 WCHAR caption[200], message[200];
8403 int mb_ret;
8405 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, ARRAY_SIZE(caption));
8406 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, ARRAY_SIZE(message));
8407 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8408 if(mb_ret == IDCANCEL)
8410 HeapFree(GetProcessHeap(), 0, filename);
8411 return TRUE;
8414 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8415 if(hf == INVALID_HANDLE_VALUE)
8417 WCHAR caption[200], message[200];
8419 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, ARRAY_SIZE(caption));
8420 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, ARRAY_SIZE(message));
8421 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8422 HeapFree(GetProcessHeap(), 0, filename);
8423 return TRUE;
8425 CloseHandle(hf);
8426 DeleteFileW(filename);
8427 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8428 *output = filename;
8429 EndDialog(hwnd, IDOK);
8430 return TRUE;
8432 if(LOWORD(wparam) == IDCANCEL)
8434 EndDialog(hwnd, IDCANCEL);
8435 return TRUE;
8438 return FALSE;
8440 return FALSE;
8443 /*****************************************************************************
8444 * get_filename
8446 static BOOL get_filename(LPWSTR *filename)
8448 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8449 file_dlg_proc, (LPARAM)filename) == IDOK;
8452 /*****************************************************************************
8453 * schedule_file
8455 static BOOL schedule_file(LPCWSTR filename)
8457 LPWSTR output = NULL;
8459 if(get_filename(&output))
8461 BOOL r;
8462 TRACE("copy to %s\n", debugstr_w(output));
8463 r = CopyFileW(filename, output, FALSE);
8464 HeapFree(GetProcessHeap(), 0, output);
8465 return r;
8467 return FALSE;
8470 /*****************************************************************************
8471 * schedule_unixfile
8473 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8475 int in_fd, out_fd, no_read;
8476 char buf[1024];
8477 BOOL ret = FALSE;
8478 char *unixname, *outputA;
8479 DWORD len;
8481 if(!(unixname = wine_get_unix_file_name(filename)))
8482 return FALSE;
8484 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8485 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8486 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8488 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8489 in_fd = open(unixname, O_RDONLY);
8490 if(out_fd == -1 || in_fd == -1)
8491 goto end;
8493 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8494 write(out_fd, buf, no_read);
8496 ret = TRUE;
8497 end:
8498 if(in_fd != -1) close(in_fd);
8499 if(out_fd != -1) close(out_fd);
8500 HeapFree(GetProcessHeap(), 0, outputA);
8501 HeapFree(GetProcessHeap(), 0, unixname);
8502 return ret;
8505 /*****************************************************************************
8506 * ScheduleJob [WINSPOOL.@]
8509 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8511 opened_printer_t *printer;
8512 BOOL ret = FALSE;
8513 struct list *cursor, *cursor2;
8515 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8516 EnterCriticalSection(&printer_handles_cs);
8517 printer = get_opened_printer(hPrinter);
8518 if(!printer)
8519 goto end;
8521 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8523 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8524 HANDLE hf;
8526 if(job->job_id != dwJobID) continue;
8528 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8529 if(hf != INVALID_HANDLE_VALUE)
8531 PRINTER_INFO_5W *pi5 = NULL;
8532 LPWSTR portname = job->portname;
8533 DWORD needed;
8534 HKEY hkey;
8535 WCHAR output[1024];
8536 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8537 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8539 if (!portname)
8541 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8542 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8543 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8544 portname = pi5->pPortName;
8546 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8547 debugstr_w(portname));
8549 output[0] = 0;
8551 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8552 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8554 DWORD type, count = sizeof(output);
8555 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8556 RegCloseKey(hkey);
8558 if(output[0] == '|')
8560 ret = schedule_pipe(output + 1, job->filename);
8562 else if(output[0])
8564 ret = schedule_unixfile(output, job->filename);
8566 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8568 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8570 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8572 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8574 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8576 ret = schedule_file(job->filename);
8578 else if(isalpha(portname[0]) && portname[1] == ':')
8580 TRACE("copying to %s\n", debugstr_w(portname));
8581 ret = CopyFileW(job->filename, portname, FALSE);
8583 else
8585 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8587 HeapFree(GetProcessHeap(), 0, pi5);
8588 CloseHandle(hf);
8589 DeleteFileW(job->filename);
8591 list_remove(cursor);
8592 HeapFree(GetProcessHeap(), 0, job->document_title);
8593 HeapFree(GetProcessHeap(), 0, job->printer_name);
8594 HeapFree(GetProcessHeap(), 0, job->portname);
8595 HeapFree(GetProcessHeap(), 0, job->filename);
8596 HeapFree(GetProcessHeap(), 0, job->devmode);
8597 HeapFree(GetProcessHeap(), 0, job);
8598 break;
8600 end:
8601 LeaveCriticalSection(&printer_handles_cs);
8602 return ret;
8605 /*****************************************************************************
8606 * StartDocDlgA [WINSPOOL.@]
8608 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8610 UNICODE_STRING usBuffer;
8611 DOCINFOW docW = { 0 };
8612 LPWSTR retW;
8613 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8614 LPSTR ret = NULL;
8616 docW.cbSize = sizeof(docW);
8617 if (doc->lpszDocName)
8619 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8620 if (!(docW.lpszDocName = docnameW)) goto failed;
8622 if (doc->lpszOutput)
8624 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8625 if (!(docW.lpszOutput = outputW)) goto failed;
8627 if (doc->lpszDatatype)
8629 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8630 if (!(docW.lpszDatatype = datatypeW)) goto failed;
8632 docW.fwType = doc->fwType;
8634 retW = StartDocDlgW(hPrinter, &docW);
8636 if(retW)
8638 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8639 ret = HeapAlloc(GetProcessHeap(), 0, len);
8640 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8641 HeapFree(GetProcessHeap(), 0, retW);
8644 failed:
8645 HeapFree(GetProcessHeap(), 0, datatypeW);
8646 HeapFree(GetProcessHeap(), 0, outputW);
8647 HeapFree(GetProcessHeap(), 0, docnameW);
8649 return ret;
8652 /*****************************************************************************
8653 * StartDocDlgW [WINSPOOL.@]
8655 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8656 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8657 * port is "FILE:". Also returns the full path if passed a relative path.
8659 * The caller should free the returned string from the process heap.
8661 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8663 LPWSTR ret = NULL;
8664 DWORD len, attr;
8666 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8668 PRINTER_INFO_5W *pi5;
8669 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8670 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8671 return NULL;
8672 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8673 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8674 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8676 HeapFree(GetProcessHeap(), 0, pi5);
8677 return NULL;
8679 HeapFree(GetProcessHeap(), 0, pi5);
8682 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8684 LPWSTR name;
8686 if (get_filename(&name))
8688 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8690 HeapFree(GetProcessHeap(), 0, name);
8691 return NULL;
8693 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8694 GetFullPathNameW(name, len, ret, NULL);
8695 HeapFree(GetProcessHeap(), 0, name);
8697 return ret;
8700 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8701 return NULL;
8703 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8704 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8706 attr = GetFileAttributesW(ret);
8707 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8709 HeapFree(GetProcessHeap(), 0, ret);
8710 ret = NULL;
8712 return ret;
8715 /*****************************************************************************
8716 * UploadPrinterDriverPackageA [WINSPOOL.@]
8718 HRESULT WINAPI UploadPrinterDriverPackageA( LPCSTR server, LPCSTR path, LPCSTR env,
8719 DWORD flags, HWND hwnd, LPSTR dst, PULONG dstlen )
8721 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server), debugstr_a(path), debugstr_a(env),
8722 flags, hwnd, dst, dstlen);
8723 return E_NOTIMPL;
8726 /*****************************************************************************
8727 * UploadPrinterDriverPackageW [WINSPOOL.@]
8729 HRESULT WINAPI UploadPrinterDriverPackageW( LPCWSTR server, LPCWSTR path, LPCWSTR env,
8730 DWORD flags, HWND hwnd, LPWSTR dst, PULONG dstlen )
8732 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server), debugstr_w(path), debugstr_w(env),
8733 flags, hwnd, dst, dstlen);
8734 return E_NOTIMPL;
8737 /*****************************************************************************
8738 * PerfOpen [WINSPOOL.@]
8740 DWORD WINAPI PerfOpen(LPWSTR context)
8742 FIXME("%s: stub\n", debugstr_w(context));
8743 return ERROR_SUCCESS;
8746 /*****************************************************************************
8747 * PerfClose [WINSPOOL.@]
8749 DWORD WINAPI PerfClose(void)
8751 FIXME("stub\n");
8752 return ERROR_SUCCESS;
8755 /*****************************************************************************
8756 * PerfCollect [WINSPOOL.@]
8758 DWORD WINAPI PerfCollect(LPWSTR query, LPVOID *data, LPDWORD size, LPDWORD obj_count)
8760 FIXME("%s, %p, %p, %p: stub\n", debugstr_w(query), data, size, obj_count);
8761 *size = 0;
8762 *obj_count = 0;
8763 return ERROR_SUCCESS;