mstask: Implement ITask::DeleteTrigger().
[wine.git] / dlls / winspool.drv / info.c
blob9c24256b512be63ab3b4c3b835cdf262b74dcbde
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include "wine/port.h"
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <stddef.h>
36 #include <errno.h>
37 #ifdef HAVE_SYS_WAIT_H
38 #include <sys/wait.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif
43 #include <signal.h>
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
46 #endif
47 #ifdef HAVE_CUPS_PPD_H
48 # include <cups/ppd.h>
49 #endif
51 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
52 #define GetCurrentProcess GetCurrentProcess_Mac
53 #define GetCurrentThread GetCurrentThread_Mac
54 #define LoadResource LoadResource_Mac
55 #define AnimatePalette AnimatePalette_Mac
56 #define EqualRgn EqualRgn_Mac
57 #define FillRgn FillRgn_Mac
58 #define FrameRgn FrameRgn_Mac
59 #define GetPixel GetPixel_Mac
60 #define InvertRgn InvertRgn_Mac
61 #define LineTo LineTo_Mac
62 #define OffsetRgn OffsetRgn_Mac
63 #define PaintRgn PaintRgn_Mac
64 #define Polygon Polygon_Mac
65 #define ResizePalette ResizePalette_Mac
66 #define SetRectRgn SetRectRgn_Mac
67 #define EqualRect EqualRect_Mac
68 #define FillRect FillRect_Mac
69 #define FrameRect FrameRect_Mac
70 #define GetCursor GetCursor_Mac
71 #define InvertRect InvertRect_Mac
72 #define OffsetRect OffsetRect_Mac
73 #define PtInRect PtInRect_Mac
74 #define SetCursor SetCursor_Mac
75 #define SetRect SetRect_Mac
76 #define ShowCursor ShowCursor_Mac
77 #define UnionRect UnionRect_Mac
78 #include <ApplicationServices/ApplicationServices.h>
79 #undef GetCurrentProcess
80 #undef GetCurrentThread
81 #undef LoadResource
82 #undef AnimatePalette
83 #undef EqualRgn
84 #undef FillRgn
85 #undef FrameRgn
86 #undef GetPixel
87 #undef InvertRgn
88 #undef LineTo
89 #undef OffsetRgn
90 #undef PaintRgn
91 #undef Polygon
92 #undef ResizePalette
93 #undef SetRectRgn
94 #undef EqualRect
95 #undef FillRect
96 #undef FrameRect
97 #undef GetCursor
98 #undef InvertRect
99 #undef OffsetRect
100 #undef PtInRect
101 #undef SetCursor
102 #undef SetRect
103 #undef ShowCursor
104 #undef UnionRect
105 #undef DPRINTF
106 #endif
108 #include "wine/library.h"
109 #include "windef.h"
110 #include "winbase.h"
111 #include "winuser.h"
112 #include "winerror.h"
113 #include "winreg.h"
114 #include "wingdi.h"
115 #include "winspool.h"
116 #include "winternl.h"
117 #include "wine/windef16.h"
118 #include "wine/unicode.h"
119 #include "wine/debug.h"
120 #include "wine/list.h"
121 #include "winnls.h"
123 #include "ddk/winsplp.h"
124 #include "wspool.h"
126 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
128 /* ############################### */
130 static CRITICAL_SECTION printer_handles_cs;
131 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
133 0, 0, &printer_handles_cs,
134 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
135 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
137 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
139 /* ############################### */
141 typedef struct {
142 DWORD job_id;
143 HANDLE hf;
144 } started_doc_t;
146 typedef struct {
147 struct list jobs;
148 LONG ref;
149 } jobqueue_t;
151 typedef struct {
152 LPWSTR name;
153 LPWSTR printername;
154 HANDLE backend_printer;
155 jobqueue_t *queue;
156 started_doc_t *doc;
157 DEVMODEW *devmode;
158 } opened_printer_t;
160 typedef struct {
161 struct list entry;
162 DWORD job_id;
163 WCHAR *filename;
164 WCHAR *portname;
165 WCHAR *document_title;
166 WCHAR *printer_name;
167 LPDEVMODEW devmode;
168 } job_t;
171 typedef struct {
172 LPCWSTR envname;
173 LPCWSTR subdir;
174 DWORD driverversion;
175 LPCWSTR versionregpath;
176 LPCWSTR versionsubdir;
177 } printenv_t;
179 /* ############################### */
181 static opened_printer_t **printer_handles;
182 static UINT nb_printer_handles;
183 static LONG next_job_id = 1;
185 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
186 WORD fwCapability, LPSTR lpszOutput,
187 LPDEVMODEA lpdm );
188 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
189 LPSTR lpszDevice, LPSTR lpszPort,
190 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
191 DWORD fwMode );
193 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
194 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
195 'c','o','n','t','r','o','l','\\',
196 'P','r','i','n','t','\\',
197 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
198 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
200 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
201 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
202 'C','o','n','t','r','o','l','\\',
203 'P','r','i','n','t','\\',
204 'P','r','i','n','t','e','r','s',0};
206 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
207 'M','i','c','r','o','s','o','f','t','\\',
208 'W','i','n','d','o','w','s',' ','N','T','\\',
209 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
210 'W','i','n','d','o','w','s',0};
212 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
213 'M','i','c','r','o','s','o','f','t','\\',
214 'W','i','n','d','o','w','s',' ','N','T','\\',
215 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
216 'D','e','v','i','c','e','s',0};
218 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
219 'M','i','c','r','o','s','o','f','t','\\',
220 'W','i','n','d','o','w','s',' ','N','T','\\',
221 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
222 'P','r','i','n','t','e','r','P','o','r','t','s',0};
224 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
225 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
226 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
227 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
228 static const WCHAR subdir_x64W[] = {'x','6','4',0};
229 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
230 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
231 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
232 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
233 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
235 static const WCHAR AttributesW[] = {'A','t','t','r','i','b','u','t','e','s',0};
236 static const WCHAR backslashW[] = {'\\',0};
237 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
238 'i','o','n',' ','F','i','l','e',0};
239 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
240 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
241 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
242 static const WCHAR Default_PriorityW[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
243 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
244 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
245 static const WCHAR dnsTimeoutW[] = {'d','n','s','T','i','m','e','o','u','t',0};
246 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
247 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
248 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
249 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
250 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
251 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
252 static const WCHAR NameW[] = {'N','a','m','e',0};
253 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
254 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
255 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
256 static const WCHAR PortW[] = {'P','o','r','t',0};
257 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
258 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
259 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
260 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
261 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
262 static const WCHAR PriorityW[] = {'P','r','i','o','r','i','t','y',0};
263 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
264 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
265 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
266 static const WCHAR StartTimeW[] = {'S','t','a','r','t','T','i','m','e',0};
267 static const WCHAR StatusW[] = {'S','t','a','t','u','s',0};
268 static const WCHAR txTimeoutW[] = {'t','x','T','i','m','e','o','u','t',0};
269 static const WCHAR UntilTimeW[] = {'U','n','t','i','l','T','i','m','e',0};
270 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
271 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
272 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
273 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
274 static WCHAR rawW[] = {'R','A','W',0};
275 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
276 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
277 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
278 static const WCHAR commaW[] = {',',0};
279 static WCHAR emptyStringW[] = {0};
281 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
283 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
284 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
285 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
287 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
288 'D','o','c','u','m','e','n','t',0};
290 static const WCHAR PPD_Overrides[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
291 static const WCHAR DefaultPageSize[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
293 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
294 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
295 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
296 0, sizeof(DRIVER_INFO_8W)};
299 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
300 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
301 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
302 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
303 sizeof(PRINTER_INFO_9W)};
305 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
306 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
307 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
309 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
311 /******************************************************************
312 * validate the user-supplied printing-environment [internal]
314 * PARAMS
315 * env [I] PTR to Environment-String or NULL
317 * RETURNS
318 * Failure: NULL
319 * Success: PTR to printenv_t
321 * NOTES
322 * An empty string is handled the same way as NULL.
323 * SetLastError(ERROR_INVALID_ENVIRONMENT) is called on Failure
327 static const printenv_t * validate_envW(LPCWSTR env)
329 const printenv_t *result = NULL;
330 unsigned int i;
332 TRACE("testing %s\n", debugstr_w(env));
333 if (env && env[0])
335 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
337 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
339 result = all_printenv[i];
340 break;
344 if (result == NULL) {
345 FIXME("unsupported Environment: %s\n", debugstr_w(env));
346 SetLastError(ERROR_INVALID_ENVIRONMENT);
348 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
350 else
352 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
354 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
356 return result;
360 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
361 if passed a NULL string. This returns NULLs to the result.
363 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
365 if ( (src) )
367 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
368 return usBufferPtr->Buffer;
370 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
371 return NULL;
374 static LPWSTR strdupW(LPCWSTR p)
376 LPWSTR ret;
377 DWORD len;
379 if(!p) return NULL;
380 len = (strlenW(p) + 1) * sizeof(WCHAR);
381 ret = HeapAlloc(GetProcessHeap(), 0, len);
382 memcpy(ret, p, len);
383 return ret;
386 static LPSTR strdupWtoA( LPCWSTR str )
388 LPSTR ret;
389 INT len;
391 if (!str) return NULL;
392 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
393 ret = HeapAlloc( GetProcessHeap(), 0, len );
394 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
395 return ret;
398 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
400 DEVMODEW *ret;
402 if (!dm) return NULL;
403 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
404 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
405 return ret;
408 /***********************************************************
409 * DEVMODEdupWtoA
410 * Creates an ansi copy of supplied devmode
412 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
414 LPDEVMODEA dmA;
415 DWORD size;
417 if (!dmW) return NULL;
418 size = dmW->dmSize - CCHDEVICENAME -
419 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
421 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
422 if (!dmA) return NULL;
424 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
425 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
427 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
429 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
430 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
432 else
434 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
435 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
436 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
437 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
439 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
442 dmA->dmSize = size;
443 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
444 return dmA;
448 /******************************************************************
449 * verify, that the filename is a local file
452 static inline BOOL is_local_file(LPWSTR name)
454 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
457 /* ################################ */
459 static int multi_sz_lenA(const char *str)
461 const char *ptr = str;
462 if(!str) return 0;
465 ptr += lstrlenA(ptr) + 1;
466 } while(*ptr);
468 return ptr - str + 1;
471 /*****************************************************************************
472 * get_dword_from_reg
474 * Return DWORD associated with name from hkey.
476 static DWORD get_dword_from_reg( HKEY hkey, const WCHAR *name )
478 DWORD sz = sizeof(DWORD), type, value = 0;
479 LONG ret;
481 ret = RegQueryValueExW( hkey, name, 0, &type, (LPBYTE)&value, &sz );
483 if (ret != ERROR_SUCCESS)
485 WARN( "Got ret = %d on name %s\n", ret, debugstr_w(name) );
486 return 0;
488 if (type != REG_DWORD)
490 ERR( "Got type %d\n", type );
491 return 0;
493 return value;
496 static inline DWORD set_reg_DWORD( HKEY hkey, const WCHAR *keyname, const DWORD value )
498 return RegSetValueExW( hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value) );
501 /******************************************************************
502 * get_opened_printer
503 * Get the pointer to the opened printer referred by the handle
505 static opened_printer_t *get_opened_printer(HANDLE hprn)
507 UINT_PTR idx = (UINT_PTR)hprn;
508 opened_printer_t *ret = NULL;
510 EnterCriticalSection(&printer_handles_cs);
512 if ((idx > 0) && (idx <= nb_printer_handles)) {
513 ret = printer_handles[idx - 1];
515 LeaveCriticalSection(&printer_handles_cs);
516 return ret;
519 /******************************************************************
520 * get_opened_printer_name
521 * Get the pointer to the opened printer name referred by the handle
523 static LPCWSTR get_opened_printer_name(HANDLE hprn)
525 opened_printer_t *printer = get_opened_printer(hprn);
526 if(!printer) return NULL;
527 return printer->name;
530 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
532 HKEY printers;
533 DWORD err;
535 *key = NULL;
536 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
537 if (err) return err;
539 err = RegOpenKeyW( printers, name, key );
540 if (err) err = ERROR_INVALID_PRINTER_NAME;
541 RegCloseKey( printers );
542 return err;
545 /******************************************************************
546 * WINSPOOL_GetOpenedPrinterRegKey
549 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
551 LPCWSTR name = get_opened_printer_name(hPrinter);
553 if(!name) return ERROR_INVALID_HANDLE;
554 return open_printer_reg_key( name, phkey );
557 static void
558 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
559 char qbuf[200];
561 /* If forcing, or no profile string entry for device yet, set the entry
563 * The always change entry if not WINEPS yet is discussable.
565 if (force ||
566 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
567 !strcmp(qbuf,"*") ||
568 !strstr(qbuf,"WINEPS.DRV")
570 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
571 HKEY hkey;
573 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
574 WriteProfileStringA("windows","device",buf);
575 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
576 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
577 RegCloseKey(hkey);
579 HeapFree(GetProcessHeap(),0,buf);
583 static BOOL add_printer_driver(const WCHAR *name, WCHAR *ppd)
585 DRIVER_INFO_3W di3;
586 unsigned int i;
587 BOOL res;
589 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
590 di3.cVersion = 3;
591 di3.pName = (WCHAR*)name;
592 di3.pDriverPath = driver_nt;
593 di3.pDataFile = ppd;
594 di3.pConfigFile = driver_nt;
595 di3.pDefaultDataType = rawW;
597 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
599 di3.pEnvironment = (WCHAR *) all_printenv[i]->envname;
600 if (all_printenv[i]->envname == envname_win40W)
602 /* We use wineps16.drv as driver for 16 bit */
603 di3.pDriverPath = driver_9x;
604 di3.pConfigFile = driver_9x;
606 res = AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY );
607 TRACE("got %d and %d for %s (%s)\n", res, GetLastError(), debugstr_w(name), debugstr_w(di3.pEnvironment));
609 if (!res && (GetLastError() != ERROR_PRINTER_DRIVER_ALREADY_INSTALLED))
611 ERR("failed with %u for %s (%s) %s\n", GetLastError(), debugstr_w(name),
612 debugstr_w(di3.pEnvironment), debugstr_w(di3.pDriverPath));
613 return FALSE;
617 return TRUE;
620 static inline char *expand_env_string( char *str, DWORD type )
622 if (type == REG_EXPAND_SZ)
624 char *tmp;
625 DWORD needed = ExpandEnvironmentStringsA( str, NULL, 0 );
626 tmp = HeapAlloc( GetProcessHeap(), 0, needed );
627 if (tmp)
629 ExpandEnvironmentStringsA( str, tmp, needed );
630 HeapFree( GetProcessHeap(), 0, str );
631 return tmp;
634 return str;
637 static char *get_fallback_ppd_name( const char *printer_name )
639 static const WCHAR ppds_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
640 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
641 HKEY hkey;
642 DWORD needed, type;
643 char *ret = NULL;
645 if (RegOpenKeyW( HKEY_CURRENT_USER, ppds_key, &hkey ) == ERROR_SUCCESS )
647 const char *value_name = NULL;
649 if (RegQueryValueExA( hkey, printer_name, 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
650 value_name = printer_name;
651 else if (RegQueryValueExA( hkey, "generic", 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
652 value_name = "generic";
654 if (value_name)
656 ret = HeapAlloc( GetProcessHeap(), 0, needed );
657 if (!ret) return NULL;
658 RegQueryValueExA( hkey, value_name, 0, &type, (BYTE *)ret, &needed );
660 RegCloseKey( hkey );
661 if (ret) return expand_env_string( ret, type );
663 return NULL;
666 static BOOL copy_file( const char *src, const char *dst )
668 int fds[2] = {-1, -1}, num;
669 char buf[1024];
670 BOOL ret = FALSE;
672 fds[0] = open( src, O_RDONLY );
673 fds[1] = open( dst, O_CREAT | O_TRUNC | O_WRONLY, 0666 );
674 if (fds[0] == -1 || fds[1] == -1) goto fail;
676 while ((num = read( fds[0], buf, sizeof(buf) )) != 0)
678 if (num == -1) goto fail;
679 if (write( fds[1], buf, num ) != num) goto fail;
681 ret = TRUE;
683 fail:
684 if (fds[1] != -1) close( fds[1] );
685 if (fds[0] != -1) close( fds[0] );
686 return ret;
689 static BOOL get_internal_fallback_ppd( const WCHAR *ppd )
691 static const WCHAR typeW[] = {'P','P','D','F','I','L','E',0};
693 char *ptr, *end;
694 DWORD size, written;
695 HANDLE file;
696 BOOL ret;
697 HRSRC res = FindResourceW( WINSPOOL_hInstance, MAKEINTRESOURCEW(1), typeW );
699 if (!res || !(ptr = LoadResource( WINSPOOL_hInstance, res ))) return FALSE;
700 size = SizeofResource( WINSPOOL_hInstance, res );
701 end = memchr( ptr, 0, size ); /* resource file may contain additional nulls */
702 if (end) size = end - ptr;
703 file = CreateFileW( ppd, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0 );
704 if (file == INVALID_HANDLE_VALUE) return FALSE;
705 ret = WriteFile( file, ptr, size, &written, NULL ) && written == size;
706 CloseHandle( file );
707 if (ret) TRACE( "using internal fallback for %s\n", debugstr_w( ppd ));
708 else DeleteFileW( ppd );
709 return ret;
712 static BOOL get_fallback_ppd( const char *printer_name, const WCHAR *ppd )
714 char *dst, *src = get_fallback_ppd_name( printer_name );
715 BOOL ret = FALSE;
717 if (!src) return get_internal_fallback_ppd( ppd );
719 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name), debugstr_w(ppd), debugstr_a(src) );
721 if (!(dst = wine_get_unix_file_name( ppd ))) goto fail;
723 if (symlink( src, dst ) == -1)
724 if (errno != ENOSYS || !copy_file( src, dst ))
725 goto fail;
727 ret = TRUE;
728 fail:
729 HeapFree( GetProcessHeap(), 0, dst );
730 HeapFree( GetProcessHeap(), 0, src );
731 return ret;
734 static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
736 static const WCHAR dot_ppd[] = {'.','p','p','d',0};
737 int len = (strlenW( dir ) + strlenW( file_name )) * sizeof(WCHAR) + sizeof(dot_ppd);
738 WCHAR *ppd = HeapAlloc( GetProcessHeap(), 0, len );
740 if (!ppd) return NULL;
741 strcpyW( ppd, dir );
742 strcatW( ppd, file_name );
743 strcatW( ppd, dot_ppd );
745 return ppd;
748 static WCHAR *get_ppd_dir( void )
750 static const WCHAR wine_ppds[] = {'w','i','n','e','_','p','p','d','s','\\',0};
751 DWORD len;
752 WCHAR *dir, tmp_path[MAX_PATH];
753 BOOL res;
755 len = GetTempPathW( sizeof(tmp_path) / sizeof(tmp_path[0]), tmp_path );
756 if (!len) return NULL;
757 dir = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
758 if (!dir) return NULL;
760 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
761 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
762 res = CreateDirectoryW( dir, NULL );
763 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
765 HeapFree( GetProcessHeap(), 0, dir );
766 dir = NULL;
768 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
769 return dir;
772 static void unlink_ppd( const WCHAR *ppd )
774 char *unix_name = wine_get_unix_file_name( ppd );
775 unlink( unix_name );
776 HeapFree( GetProcessHeap(), 0, unix_name );
779 #ifdef SONAME_LIBCUPS
781 static void *cupshandle;
783 #define CUPS_FUNCS \
784 DO_FUNC(cupsAddOption); \
785 DO_FUNC(cupsFreeDests); \
786 DO_FUNC(cupsFreeOptions); \
787 DO_FUNC(cupsGetDests); \
788 DO_FUNC(cupsGetOption); \
789 DO_FUNC(cupsGetPPD); \
790 DO_FUNC(cupsParseOptions); \
791 DO_FUNC(cupsPrintFile)
792 #define CUPS_OPT_FUNCS \
793 DO_FUNC(cupsGetNamedDest); \
794 DO_FUNC(cupsGetPPD3); \
795 DO_FUNC(cupsLastErrorString)
797 #define DO_FUNC(f) static typeof(f) *p##f
798 CUPS_FUNCS;
799 #undef DO_FUNC
800 static cups_dest_t * (*pcupsGetNamedDest)(http_t *, const char *, const char *);
801 static http_status_t (*pcupsGetPPD3)(http_t *, const char *, time_t *, char *, size_t);
802 static const char * (*pcupsLastErrorString)(void);
804 static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name,
805 time_t *modtime, char *buffer,
806 size_t bufsize )
808 const char *ppd;
810 if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
812 if (!pcupsGetPPD) return HTTP_NOT_FOUND;
814 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
816 *modtime = 0;
817 ppd = pcupsGetPPD( name );
819 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
821 if (!ppd) return HTTP_NOT_FOUND;
823 if (rename( ppd, buffer ) == -1)
825 BOOL res = copy_file( ppd, buffer );
826 unlink( ppd );
827 if (!res) return HTTP_NOT_FOUND;
829 return HTTP_OK;
832 static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
834 time_t modtime = 0;
835 http_status_t http_status;
836 char *unix_name = wine_get_unix_file_name( ppd );
838 TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
840 if (!unix_name) return FALSE;
842 http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
843 unix_name, strlen( unix_name ) + 1 );
845 if (http_status != HTTP_OK) unlink( unix_name );
846 HeapFree( GetProcessHeap(), 0, unix_name );
848 if (http_status == HTTP_OK) return TRUE;
850 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
851 debugstr_a(printer_name), http_status );
852 return get_fallback_ppd( printer_name, ppd );
855 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
857 const char *value;
858 WCHAR *ret;
859 int len;
861 value = pcupsGetOption( name, num_options, options );
862 if (!value) return NULL;
864 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
865 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
866 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
868 return ret;
871 static cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
873 WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
874 cups_ptype_t ret = 0;
876 if (type && *type)
878 ret = (cups_ptype_t)strtoulW( type, &end, 10 );
879 if (*end) ret = 0;
881 HeapFree( GetProcessHeap(), 0, type );
882 return ret;
885 static void load_cups(void)
887 cupshandle = wine_dlopen( SONAME_LIBCUPS, RTLD_NOW, NULL, 0 );
888 if (!cupshandle) return;
890 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
892 #define DO_FUNC(x) \
893 p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); \
894 if (!p##x) \
896 ERR("failed to load symbol %s\n", #x); \
897 cupshandle = NULL; \
898 return; \
900 CUPS_FUNCS;
901 #undef DO_FUNC
902 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 )
903 CUPS_OPT_FUNCS;
904 #undef DO_FUNC
907 static BOOL CUPS_LoadPrinters(void)
909 int i, nrofdests;
910 BOOL hadprinter = FALSE, haddefault = FALSE;
911 cups_dest_t *dests;
912 PRINTER_INFO_2W pi2;
913 WCHAR *port, *ppd_dir = NULL, *ppd;
914 HKEY hkeyPrinter, hkeyPrinters;
915 WCHAR nameW[MAX_PATH];
916 HANDLE added_printer;
917 cups_ptype_t printer_type;
919 if (!cupshandle) return FALSE;
921 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
922 ERROR_SUCCESS) {
923 ERR("Can't create Printers key\n");
924 return FALSE;
927 nrofdests = pcupsGetDests(&dests);
928 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
929 for (i=0;i<nrofdests;i++) {
930 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
931 printer_type = get_cups_printer_type( dests + i );
933 TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
935 if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
937 TRACE( "skipping scanner-only device\n" );
938 continue;
941 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
942 lstrcpyW(port, CUPS_Port);
943 lstrcatW(port, nameW);
945 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
946 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
947 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
948 and continue */
949 TRACE("Printer already exists\n");
950 /* overwrite old LPR:* port */
951 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
952 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
953 /* flag that the PPD file should be checked for an update */
954 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
955 RegCloseKey(hkeyPrinter);
956 } else {
957 BOOL added_driver = FALSE;
959 if (!ppd_dir && !(ppd_dir = get_ppd_dir()))
961 HeapFree( GetProcessHeap(), 0, port );
962 break;
964 ppd = get_ppd_filename( ppd_dir, nameW );
965 if (get_cups_ppd( dests[i].name, ppd ))
967 added_driver = add_printer_driver( nameW, ppd );
968 unlink_ppd( ppd );
970 HeapFree( GetProcessHeap(), 0, ppd );
971 if (!added_driver)
973 HeapFree( GetProcessHeap(), 0, port );
974 continue;
977 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
978 pi2.pPrinterName = nameW;
979 pi2.pDatatype = rawW;
980 pi2.pPrintProcessor = WinPrintW;
981 pi2.pDriverName = nameW;
982 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
983 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
984 pi2.pPortName = port;
985 pi2.pParameters = emptyStringW;
986 pi2.pShareName = emptyStringW;
987 pi2.pSepFile = emptyStringW;
989 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
990 if (added_printer) ClosePrinter( added_printer );
991 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
992 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
994 HeapFree( GetProcessHeap(), 0, pi2.pComment );
995 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
997 HeapFree( GetProcessHeap(), 0, port );
999 hadprinter = TRUE;
1000 if (dests[i].is_default) {
1001 SetDefaultPrinterW(nameW);
1002 haddefault = TRUE;
1006 if (ppd_dir)
1008 RemoveDirectoryW( ppd_dir );
1009 HeapFree( GetProcessHeap(), 0, ppd_dir );
1012 if (hadprinter && !haddefault) {
1013 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
1014 SetDefaultPrinterW(nameW);
1016 pcupsFreeDests(nrofdests, dests);
1017 RegCloseKey(hkeyPrinters);
1018 return TRUE;
1021 #endif
1023 static char *get_queue_name( HANDLE printer, BOOL *cups )
1025 WCHAR *port, *name = NULL;
1026 DWORD err, needed, type;
1027 char *ret = NULL;
1028 HKEY key;
1030 *cups = FALSE;
1032 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
1033 if (err) return NULL;
1034 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
1035 if (err) goto end;
1036 port = HeapAlloc( GetProcessHeap(), 0, needed );
1037 if (!port) goto end;
1038 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
1040 if (!strncmpW( port, CUPS_Port, sizeof(CUPS_Port) / sizeof(WCHAR) -1 ))
1042 name = port + sizeof(CUPS_Port) / sizeof(WCHAR) - 1;
1043 *cups = TRUE;
1045 else if (!strncmpW( port, LPR_Port, sizeof(LPR_Port) / sizeof(WCHAR) -1 ))
1046 name = port + sizeof(LPR_Port) / sizeof(WCHAR) - 1;
1047 if (name)
1049 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
1050 ret = HeapAlloc( GetProcessHeap(), 0, needed );
1051 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
1053 HeapFree( GetProcessHeap(), 0, port );
1054 end:
1055 RegCloseKey( key );
1056 return ret;
1060 static void set_ppd_overrides( HANDLE printer )
1062 WCHAR *wstr = NULL;
1063 int size = 0;
1064 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1065 OSStatus status;
1066 PMPrintSession session = NULL;
1067 PMPageFormat format = NULL;
1068 PMPaper paper;
1069 CFStringRef paper_name;
1070 CFRange range;
1072 status = PMCreateSession( &session );
1073 if (status) goto end;
1075 status = PMCreatePageFormat( &format );
1076 if (status) goto end;
1078 status = PMSessionDefaultPageFormat( session, format );
1079 if (status) goto end;
1081 status = PMGetPageFormatPaper( format, &paper );
1082 if (status) goto end;
1084 status = PMPaperGetPPDPaperName( paper, &paper_name );
1085 if (status) goto end;
1087 range.location = 0;
1088 range.length = CFStringGetLength( paper_name );
1089 size = (range.length + 1) * sizeof(WCHAR);
1091 wstr = HeapAlloc( GetProcessHeap(), 0, size );
1092 CFStringGetCharacters( paper_name, range, (UniChar*)wstr );
1093 wstr[range.length] = 0;
1095 end:
1096 if (format) PMRelease( format );
1097 if (session) PMRelease( session );
1098 #endif
1100 SetPrinterDataExW( printer, PPD_Overrides, DefaultPageSize, REG_SZ, (BYTE*)wstr, size );
1101 HeapFree( GetProcessHeap(), 0, wstr );
1104 static BOOL update_driver( HANDLE printer )
1106 BOOL ret, is_cups;
1107 const WCHAR *name = get_opened_printer_name( printer );
1108 WCHAR *ppd_dir, *ppd;
1109 char *queue_name;
1111 if (!name) return FALSE;
1112 queue_name = get_queue_name( printer, &is_cups );
1113 if (!queue_name) return FALSE;
1115 if (!(ppd_dir = get_ppd_dir()))
1117 HeapFree( GetProcessHeap(), 0, queue_name );
1118 return FALSE;
1120 ppd = get_ppd_filename( ppd_dir, name );
1122 #ifdef SONAME_LIBCUPS
1123 if (is_cups)
1124 ret = get_cups_ppd( queue_name, ppd );
1125 else
1126 #endif
1127 ret = get_fallback_ppd( queue_name, ppd );
1129 if (ret)
1131 TRACE( "updating driver %s\n", debugstr_w( name ) );
1132 ret = add_printer_driver( name, ppd );
1133 unlink_ppd( ppd );
1135 HeapFree( GetProcessHeap(), 0, ppd_dir );
1136 HeapFree( GetProcessHeap(), 0, ppd );
1137 HeapFree( GetProcessHeap(), 0, queue_name );
1139 set_ppd_overrides( printer );
1141 /* call into the driver to update the devmode */
1142 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
1144 return ret;
1147 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
1149 PRINTER_INFO_2A pinfo2a;
1150 const char *r;
1151 size_t name_len;
1152 char *e,*s,*name,*prettyname,*devname;
1153 BOOL ret = FALSE, set_default = FALSE;
1154 char *port = NULL, *env_default;
1155 HKEY hkeyPrinter, hkeyPrinters = NULL;
1156 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
1157 HANDLE added_printer;
1159 while (isspace(*pent)) pent++;
1160 r = strchr(pent,':');
1161 if (r)
1162 name_len = r - pent;
1163 else
1164 name_len = strlen(pent);
1165 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1166 memcpy(name, pent, name_len);
1167 name[name_len] = '\0';
1168 if (r)
1169 pent = r;
1170 else
1171 pent = "";
1173 TRACE("name=%s entry=%s\n",name, pent);
1175 if(ispunct(*name)) { /* a tc entry, not a real printer */
1176 TRACE("skipping tc entry\n");
1177 goto end;
1180 if(strstr(pent,":server")) { /* server only version so skip */
1181 TRACE("skipping server entry\n");
1182 goto end;
1185 /* Determine whether this is a postscript printer. */
1187 ret = TRUE;
1188 env_default = getenv("PRINTER");
1189 prettyname = name;
1190 /* Get longest name, usually the one at the right for later display. */
1191 while((s=strchr(prettyname,'|'))) {
1192 *s = '\0';
1193 e = s;
1194 while(isspace(*--e)) *e = '\0';
1195 TRACE("\t%s\n", debugstr_a(prettyname));
1196 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1197 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1200 e = prettyname + strlen(prettyname);
1201 while(isspace(*--e)) *e = '\0';
1202 TRACE("\t%s\n", debugstr_a(prettyname));
1203 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1205 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1206 * if it is too long, we use it as comment below. */
1207 devname = prettyname;
1208 if (strlen(devname)>=CCHDEVICENAME-1)
1209 devname = name;
1210 if (strlen(devname)>=CCHDEVICENAME-1) {
1211 ret = FALSE;
1212 goto end;
1215 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1216 sprintf(port,"LPR:%s",name);
1218 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1219 ERROR_SUCCESS) {
1220 ERR("Can't create Printers key\n");
1221 ret = FALSE;
1222 goto end;
1225 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
1227 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1228 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1229 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1230 and continue */
1231 TRACE("Printer already exists\n");
1232 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1233 /* flag that the PPD file should be checked for an update */
1234 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1235 RegCloseKey(hkeyPrinter);
1236 } else {
1237 static CHAR data_type[] = "RAW",
1238 print_proc[] = "WinPrint",
1239 comment[] = "WINEPS Printer using LPR",
1240 params[] = "<parameters?>",
1241 share_name[] = "<share name?>",
1242 sep_file[] = "<sep file?>";
1243 BOOL added_driver = FALSE;
1245 if (!ppd_dir && !(ppd_dir = get_ppd_dir())) goto end;
1246 ppd = get_ppd_filename( ppd_dir, devnameW );
1247 if (get_fallback_ppd( devname, ppd ))
1249 added_driver = add_printer_driver( devnameW, ppd );
1250 unlink_ppd( ppd );
1252 HeapFree( GetProcessHeap(), 0, ppd );
1253 if (!added_driver) goto end;
1255 memset(&pinfo2a,0,sizeof(pinfo2a));
1256 pinfo2a.pPrinterName = devname;
1257 pinfo2a.pDatatype = data_type;
1258 pinfo2a.pPrintProcessor = print_proc;
1259 pinfo2a.pDriverName = devname;
1260 pinfo2a.pComment = comment;
1261 pinfo2a.pLocation = prettyname;
1262 pinfo2a.pPortName = port;
1263 pinfo2a.pParameters = params;
1264 pinfo2a.pShareName = share_name;
1265 pinfo2a.pSepFile = sep_file;
1267 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1268 if (added_printer) ClosePrinter( added_printer );
1269 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1270 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1273 if (isfirst || set_default)
1274 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1276 end:
1277 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1278 if (ppd_dir)
1280 RemoveDirectoryW( ppd_dir );
1281 HeapFree( GetProcessHeap(), 0, ppd_dir );
1283 HeapFree(GetProcessHeap(), 0, port);
1284 HeapFree(GetProcessHeap(), 0, name);
1285 return ret;
1288 static BOOL
1289 PRINTCAP_LoadPrinters(void) {
1290 BOOL hadprinter = FALSE;
1291 char buf[200];
1292 FILE *f;
1293 char *pent = NULL;
1294 BOOL had_bash = FALSE;
1296 f = fopen("/etc/printcap","r");
1297 if (!f)
1298 return FALSE;
1300 while(fgets(buf,sizeof(buf),f)) {
1301 char *start, *end;
1303 end=strchr(buf,'\n');
1304 if (end) *end='\0';
1306 start = buf;
1307 while(isspace(*start)) start++;
1308 if(*start == '#' || *start == '\0')
1309 continue;
1311 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1312 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1313 HeapFree(GetProcessHeap(),0,pent);
1314 pent = NULL;
1317 if (end && *--end == '\\') {
1318 *end = '\0';
1319 had_bash = TRUE;
1320 } else
1321 had_bash = FALSE;
1323 if (pent) {
1324 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1325 strcat(pent,start);
1326 } else {
1327 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1328 strcpy(pent,start);
1332 if(pent) {
1333 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1334 HeapFree(GetProcessHeap(),0,pent);
1336 fclose(f);
1337 return hadprinter;
1340 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1342 if (value)
1343 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1344 (lstrlenW(value) + 1) * sizeof(WCHAR));
1345 else
1346 return ERROR_FILE_NOT_FOUND;
1349 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1351 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1352 DWORD ret = ERROR_FILE_NOT_FOUND;
1354 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1355 and we support these drivers. NT writes DEVMODEW so somehow
1356 we'll need to distinguish between these when we support NT
1357 drivers */
1359 if (dmA)
1361 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1362 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1363 HeapFree( GetProcessHeap(), 0, dmA );
1366 return ret;
1369 /******************************************************************
1370 * get_servername_from_name (internal)
1372 * for an external server, a copy of the serverpart from the full name is returned
1375 static LPWSTR get_servername_from_name(LPCWSTR name)
1377 LPWSTR server;
1378 LPWSTR ptr;
1379 WCHAR buffer[MAX_PATH];
1380 DWORD len;
1382 if (name == NULL) return NULL;
1383 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1385 server = strdupW(&name[2]); /* skip over both backslash */
1386 if (server == NULL) return NULL;
1388 /* strip '\' and the printername */
1389 ptr = strchrW(server, '\\');
1390 if (ptr) ptr[0] = '\0';
1392 TRACE("found %s\n", debugstr_w(server));
1394 len = sizeof(buffer)/sizeof(buffer[0]);
1395 if (GetComputerNameW(buffer, &len)) {
1396 if (lstrcmpW(buffer, server) == 0) {
1397 /* The requested Servername is our computername */
1398 HeapFree(GetProcessHeap(), 0, server);
1399 return NULL;
1402 return server;
1405 /******************************************************************
1406 * get_basename_from_name (internal)
1408 * skip over the serverpart from the full name
1411 static LPCWSTR get_basename_from_name(LPCWSTR name)
1413 if (name == NULL) return NULL;
1414 if ((name[0] == '\\') && (name[1] == '\\')) {
1415 /* skip over the servername and search for the following '\' */
1416 name = strchrW(&name[2], '\\');
1417 if ((name) && (name[1])) {
1418 /* found a separator ('\') followed by a name:
1419 skip over the separator and return the rest */
1420 name++;
1422 else
1424 /* no basename present (we found only a servername) */
1425 return NULL;
1428 return name;
1431 static void free_printer_entry( opened_printer_t *printer )
1433 /* the queue is shared, so don't free that here */
1434 HeapFree( GetProcessHeap(), 0, printer->printername );
1435 HeapFree( GetProcessHeap(), 0, printer->name );
1436 HeapFree( GetProcessHeap(), 0, printer->devmode );
1437 HeapFree( GetProcessHeap(), 0, printer );
1440 /******************************************************************
1441 * get_opened_printer_entry
1442 * Get the first place empty in the opened printer table
1444 * ToDo:
1445 * - pDefault is ignored
1447 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1449 UINT_PTR handle = nb_printer_handles, i;
1450 jobqueue_t *queue = NULL;
1451 opened_printer_t *printer = NULL;
1452 LPWSTR servername;
1453 LPCWSTR printername;
1455 if ((backend == NULL) && !load_backend()) return NULL;
1457 servername = get_servername_from_name(name);
1458 if (servername) {
1459 FIXME("server %s not supported\n", debugstr_w(servername));
1460 HeapFree(GetProcessHeap(), 0, servername);
1461 SetLastError(ERROR_INVALID_PRINTER_NAME);
1462 return NULL;
1465 printername = get_basename_from_name(name);
1466 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1468 /* an empty printername is invalid */
1469 if (printername && (!printername[0])) {
1470 SetLastError(ERROR_INVALID_PARAMETER);
1471 return NULL;
1474 EnterCriticalSection(&printer_handles_cs);
1476 for (i = 0; i < nb_printer_handles; i++)
1478 if (!printer_handles[i])
1480 if(handle == nb_printer_handles)
1481 handle = i;
1483 else
1485 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1486 queue = printer_handles[i]->queue;
1490 if (handle >= nb_printer_handles)
1492 opened_printer_t **new_array;
1493 if (printer_handles)
1494 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1495 (nb_printer_handles + 16) * sizeof(*new_array) );
1496 else
1497 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1498 (nb_printer_handles + 16) * sizeof(*new_array) );
1500 if (!new_array)
1502 handle = 0;
1503 goto end;
1505 printer_handles = new_array;
1506 nb_printer_handles += 16;
1509 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1511 handle = 0;
1512 goto end;
1515 /* get a printer handle from the backend */
1516 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1517 handle = 0;
1518 goto end;
1521 /* clone the base name. This is NULL for the printserver */
1522 printer->printername = strdupW(printername);
1524 /* clone the full name */
1525 printer->name = strdupW(name);
1526 if (name && (!printer->name)) {
1527 handle = 0;
1528 goto end;
1531 if (pDefault && pDefault->pDevMode)
1532 printer->devmode = dup_devmode( pDefault->pDevMode );
1534 if(queue)
1535 printer->queue = queue;
1536 else
1538 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1539 if (!printer->queue) {
1540 handle = 0;
1541 goto end;
1543 list_init(&printer->queue->jobs);
1544 printer->queue->ref = 0;
1546 InterlockedIncrement(&printer->queue->ref);
1548 printer_handles[handle] = printer;
1549 handle++;
1550 end:
1551 LeaveCriticalSection(&printer_handles_cs);
1552 if (!handle && printer) {
1553 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1554 free_printer_entry( printer );
1557 return (HANDLE)handle;
1560 static void old_printer_check( BOOL delete_phase )
1562 PRINTER_INFO_5W* pi;
1563 DWORD needed, type, num, delete, i, size;
1564 const DWORD one = 1;
1565 HKEY key;
1566 HANDLE hprn;
1568 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1569 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1571 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1572 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1573 for (i = 0; i < num; i++)
1575 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1576 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1577 continue;
1579 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1581 if (!delete_phase)
1583 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1584 RegCloseKey( key );
1586 else
1588 delete = 0;
1589 size = sizeof( delete );
1590 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1591 RegCloseKey( key );
1592 if (delete)
1594 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1595 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1597 DeletePrinter( hprn );
1598 ClosePrinter( hprn );
1600 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1604 HeapFree(GetProcessHeap(), 0, pi);
1607 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1608 'M','U','T','E','X','_','_','\0'};
1609 static HANDLE init_mutex;
1611 void WINSPOOL_LoadSystemPrinters(void)
1613 HKEY hkey, hkeyPrinters;
1614 DWORD needed, num, i;
1615 WCHAR PrinterName[256];
1616 BOOL done = FALSE;
1618 #ifdef SONAME_LIBCUPS
1619 load_cups();
1620 #endif
1622 /* FIXME: The init code should be moved to spoolsv.exe */
1623 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1624 if (!init_mutex)
1626 ERR( "Failed to create mutex\n" );
1627 return;
1629 if (GetLastError() == ERROR_ALREADY_EXISTS)
1631 WaitForSingleObject( init_mutex, INFINITE );
1632 ReleaseMutex( init_mutex );
1633 TRACE( "Init already done\n" );
1634 return;
1637 /* This ensures that all printer entries have a valid Name value. If causes
1638 problems later if they don't. If one is found to be missed we create one
1639 and set it equal to the name of the key */
1640 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1641 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1642 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1643 for(i = 0; i < num; i++) {
1644 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1645 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1646 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1647 set_reg_szW(hkey, NameW, PrinterName);
1649 RegCloseKey(hkey);
1654 RegCloseKey(hkeyPrinters);
1657 old_printer_check( FALSE );
1659 #ifdef SONAME_LIBCUPS
1660 done = CUPS_LoadPrinters();
1661 #endif
1663 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1664 PRINTCAP_LoadPrinters();
1666 old_printer_check( TRUE );
1668 ReleaseMutex( init_mutex );
1669 return;
1672 /******************************************************************
1673 * get_job
1675 * Get the pointer to the specified job.
1676 * Should hold the printer_handles_cs before calling.
1678 static job_t *get_job(HANDLE hprn, DWORD JobId)
1680 opened_printer_t *printer = get_opened_printer(hprn);
1681 job_t *job;
1683 if(!printer) return NULL;
1684 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1686 if(job->job_id == JobId)
1687 return job;
1689 return NULL;
1692 /***********************************************************
1693 * DEVMODEcpyAtoW
1695 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1697 BOOL Formname;
1698 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1699 DWORD size;
1701 Formname = (dmA->dmSize > off_formname);
1702 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1703 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1704 dmW->dmDeviceName, CCHDEVICENAME);
1705 if(!Formname) {
1706 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1707 dmA->dmSize - CCHDEVICENAME);
1708 } else {
1709 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1710 off_formname - CCHDEVICENAME);
1711 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1712 dmW->dmFormName, CCHFORMNAME);
1713 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1714 (off_formname + CCHFORMNAME));
1716 dmW->dmSize = size;
1717 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1718 dmA->dmDriverExtra);
1719 return dmW;
1722 /******************************************************************
1723 * convert_printerinfo_W_to_A [internal]
1726 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1727 DWORD level, DWORD outlen, DWORD numentries)
1729 DWORD id = 0;
1730 LPSTR ptr;
1731 INT len;
1733 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1735 len = pi_sizeof[level] * numentries;
1736 ptr = (LPSTR) out + len;
1737 outlen -= len;
1739 /* copy the numbers of all PRINTER_INFO_* first */
1740 memcpy(out, pPrintersW, len);
1742 while (id < numentries) {
1743 switch (level) {
1744 case 1:
1746 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1747 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1749 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1750 if (piW->pDescription) {
1751 piA->pDescription = ptr;
1752 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1753 ptr, outlen, NULL, NULL);
1754 ptr += len;
1755 outlen -= len;
1757 if (piW->pName) {
1758 piA->pName = ptr;
1759 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1760 ptr, outlen, NULL, NULL);
1761 ptr += len;
1762 outlen -= len;
1764 if (piW->pComment) {
1765 piA->pComment = ptr;
1766 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1767 ptr, outlen, NULL, NULL);
1768 ptr += len;
1769 outlen -= len;
1771 break;
1774 case 2:
1776 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1777 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1778 LPDEVMODEA dmA;
1780 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1781 if (piW->pServerName) {
1782 piA->pServerName = ptr;
1783 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1784 ptr, outlen, NULL, NULL);
1785 ptr += len;
1786 outlen -= len;
1788 if (piW->pPrinterName) {
1789 piA->pPrinterName = ptr;
1790 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1791 ptr, outlen, NULL, NULL);
1792 ptr += len;
1793 outlen -= len;
1795 if (piW->pShareName) {
1796 piA->pShareName = ptr;
1797 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1798 ptr, outlen, NULL, NULL);
1799 ptr += len;
1800 outlen -= len;
1802 if (piW->pPortName) {
1803 piA->pPortName = ptr;
1804 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1805 ptr, outlen, NULL, NULL);
1806 ptr += len;
1807 outlen -= len;
1809 if (piW->pDriverName) {
1810 piA->pDriverName = ptr;
1811 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1812 ptr, outlen, NULL, NULL);
1813 ptr += len;
1814 outlen -= len;
1816 if (piW->pComment) {
1817 piA->pComment = ptr;
1818 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1819 ptr, outlen, NULL, NULL);
1820 ptr += len;
1821 outlen -= len;
1823 if (piW->pLocation) {
1824 piA->pLocation = ptr;
1825 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1826 ptr, outlen, NULL, NULL);
1827 ptr += len;
1828 outlen -= len;
1831 dmA = DEVMODEdupWtoA(piW->pDevMode);
1832 if (dmA) {
1833 /* align DEVMODEA to a DWORD boundary */
1834 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1835 ptr += len;
1836 outlen -= len;
1838 piA->pDevMode = (LPDEVMODEA) ptr;
1839 len = dmA->dmSize + dmA->dmDriverExtra;
1840 memcpy(ptr, dmA, len);
1841 HeapFree(GetProcessHeap(), 0, dmA);
1843 ptr += len;
1844 outlen -= len;
1847 if (piW->pSepFile) {
1848 piA->pSepFile = ptr;
1849 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1850 ptr, outlen, NULL, NULL);
1851 ptr += len;
1852 outlen -= len;
1854 if (piW->pPrintProcessor) {
1855 piA->pPrintProcessor = ptr;
1856 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1857 ptr, outlen, NULL, NULL);
1858 ptr += len;
1859 outlen -= len;
1861 if (piW->pDatatype) {
1862 piA->pDatatype = ptr;
1863 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1864 ptr, outlen, NULL, NULL);
1865 ptr += len;
1866 outlen -= len;
1868 if (piW->pParameters) {
1869 piA->pParameters = ptr;
1870 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1871 ptr, outlen, NULL, NULL);
1872 ptr += len;
1873 outlen -= len;
1875 if (piW->pSecurityDescriptor) {
1876 piA->pSecurityDescriptor = NULL;
1877 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1879 break;
1882 case 4:
1884 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1885 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1887 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1889 if (piW->pPrinterName) {
1890 piA->pPrinterName = ptr;
1891 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1892 ptr, outlen, NULL, NULL);
1893 ptr += len;
1894 outlen -= len;
1896 if (piW->pServerName) {
1897 piA->pServerName = ptr;
1898 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1899 ptr, outlen, NULL, NULL);
1900 ptr += len;
1901 outlen -= len;
1903 break;
1906 case 5:
1908 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1909 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1911 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1913 if (piW->pPrinterName) {
1914 piA->pPrinterName = ptr;
1915 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1916 ptr, outlen, NULL, NULL);
1917 ptr += len;
1918 outlen -= len;
1920 if (piW->pPortName) {
1921 piA->pPortName = ptr;
1922 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1923 ptr, outlen, NULL, NULL);
1924 ptr += len;
1925 outlen -= len;
1927 break;
1930 case 6: /* 6A and 6W are the same structure */
1931 break;
1933 case 7:
1935 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1936 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1938 TRACE("(%u) #%u\n", level, id);
1939 if (piW->pszObjectGUID) {
1940 piA->pszObjectGUID = ptr;
1941 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1942 ptr, outlen, NULL, NULL);
1943 ptr += len;
1944 outlen -= len;
1946 break;
1949 case 8:
1950 case 9:
1952 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1953 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1954 LPDEVMODEA dmA;
1956 TRACE("(%u) #%u\n", level, id);
1957 dmA = DEVMODEdupWtoA(piW->pDevMode);
1958 if (dmA) {
1959 /* align DEVMODEA to a DWORD boundary */
1960 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1961 ptr += len;
1962 outlen -= len;
1964 piA->pDevMode = (LPDEVMODEA) ptr;
1965 len = dmA->dmSize + dmA->dmDriverExtra;
1966 memcpy(ptr, dmA, len);
1967 HeapFree(GetProcessHeap(), 0, dmA);
1969 ptr += len;
1970 outlen -= len;
1973 break;
1976 default:
1977 FIXME("for level %u\n", level);
1979 pPrintersW += pi_sizeof[level];
1980 out += pi_sizeof[level];
1981 id++;
1985 /******************************************************************
1986 * convert_driverinfo_W_to_A [internal]
1989 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1990 DWORD level, DWORD outlen, DWORD numentries)
1992 DWORD id = 0;
1993 LPSTR ptr;
1994 INT len;
1996 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1998 len = di_sizeof[level] * numentries;
1999 ptr = (LPSTR) out + len;
2000 outlen -= len;
2002 /* copy the numbers of all PRINTER_INFO_* first */
2003 memcpy(out, pDriversW, len);
2005 #define COPY_STRING(fld) \
2006 { if (diW->fld){ \
2007 diA->fld = ptr; \
2008 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
2009 ptr += len; outlen -= len;\
2011 #define COPY_MULTIZ_STRING(fld) \
2012 { LPWSTR p = diW->fld; if (p){ \
2013 diA->fld = ptr; \
2014 do {\
2015 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2016 ptr += len; outlen -= len; p += len;\
2018 while(len > 1 && outlen > 0); \
2021 while (id < numentries)
2023 switch (level)
2025 case 1:
2027 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
2028 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
2030 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2032 COPY_STRING(pName);
2033 break;
2035 case 2:
2037 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
2038 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
2040 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2042 COPY_STRING(pName);
2043 COPY_STRING(pEnvironment);
2044 COPY_STRING(pDriverPath);
2045 COPY_STRING(pDataFile);
2046 COPY_STRING(pConfigFile);
2047 break;
2049 case 3:
2051 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
2052 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
2054 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2056 COPY_STRING(pName);
2057 COPY_STRING(pEnvironment);
2058 COPY_STRING(pDriverPath);
2059 COPY_STRING(pDataFile);
2060 COPY_STRING(pConfigFile);
2061 COPY_STRING(pHelpFile);
2062 COPY_MULTIZ_STRING(pDependentFiles);
2063 COPY_STRING(pMonitorName);
2064 COPY_STRING(pDefaultDataType);
2065 break;
2067 case 4:
2069 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
2070 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
2072 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2074 COPY_STRING(pName);
2075 COPY_STRING(pEnvironment);
2076 COPY_STRING(pDriverPath);
2077 COPY_STRING(pDataFile);
2078 COPY_STRING(pConfigFile);
2079 COPY_STRING(pHelpFile);
2080 COPY_MULTIZ_STRING(pDependentFiles);
2081 COPY_STRING(pMonitorName);
2082 COPY_STRING(pDefaultDataType);
2083 COPY_MULTIZ_STRING(pszzPreviousNames);
2084 break;
2086 case 5:
2088 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
2089 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
2091 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2093 COPY_STRING(pName);
2094 COPY_STRING(pEnvironment);
2095 COPY_STRING(pDriverPath);
2096 COPY_STRING(pDataFile);
2097 COPY_STRING(pConfigFile);
2098 break;
2100 case 6:
2102 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
2103 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
2105 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2107 COPY_STRING(pName);
2108 COPY_STRING(pEnvironment);
2109 COPY_STRING(pDriverPath);
2110 COPY_STRING(pDataFile);
2111 COPY_STRING(pConfigFile);
2112 COPY_STRING(pHelpFile);
2113 COPY_MULTIZ_STRING(pDependentFiles);
2114 COPY_STRING(pMonitorName);
2115 COPY_STRING(pDefaultDataType);
2116 COPY_MULTIZ_STRING(pszzPreviousNames);
2117 COPY_STRING(pszMfgName);
2118 COPY_STRING(pszOEMUrl);
2119 COPY_STRING(pszHardwareID);
2120 COPY_STRING(pszProvider);
2121 break;
2123 case 8:
2125 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
2126 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
2128 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
2130 COPY_STRING(pName);
2131 COPY_STRING(pEnvironment);
2132 COPY_STRING(pDriverPath);
2133 COPY_STRING(pDataFile);
2134 COPY_STRING(pConfigFile);
2135 COPY_STRING(pHelpFile);
2136 COPY_MULTIZ_STRING(pDependentFiles);
2137 COPY_STRING(pMonitorName);
2138 COPY_STRING(pDefaultDataType);
2139 COPY_MULTIZ_STRING(pszzPreviousNames);
2140 COPY_STRING(pszMfgName);
2141 COPY_STRING(pszOEMUrl);
2142 COPY_STRING(pszHardwareID);
2143 COPY_STRING(pszProvider);
2144 COPY_STRING(pszPrintProcessor);
2145 COPY_STRING(pszVendorSetup);
2146 COPY_MULTIZ_STRING(pszzColorProfiles);
2147 COPY_STRING(pszInfPath);
2148 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
2149 break;
2153 default:
2154 FIXME("for level %u\n", level);
2157 pDriversW += di_sizeof[level];
2158 out += di_sizeof[level];
2159 id++;
2162 #undef COPY_STRING
2163 #undef COPY_MULTIZ_STRING
2167 /***********************************************************
2168 * printer_info_AtoW
2170 static void *printer_info_AtoW( const void *data, DWORD level )
2172 void *ret;
2173 UNICODE_STRING usBuffer;
2175 if (!data) return NULL;
2177 if (level < 1 || level > 9) return NULL;
2179 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2180 if (!ret) return NULL;
2182 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2184 switch (level)
2186 case 2:
2188 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2189 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2191 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2192 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2193 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2194 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2195 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2196 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2197 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2198 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2199 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2200 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2201 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2202 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2203 break;
2206 case 8:
2207 case 9:
2209 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2210 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2212 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2213 break;
2216 default:
2217 FIXME( "Unhandled level %d\n", level );
2218 HeapFree( GetProcessHeap(), 0, ret );
2219 return NULL;
2222 return ret;
2225 /***********************************************************
2226 * free_printer_info
2228 static void free_printer_info( void *data, DWORD level )
2230 if (!data) return;
2232 switch (level)
2234 case 2:
2236 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2238 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2239 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2240 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2241 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2242 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2243 HeapFree( GetProcessHeap(), 0, piW->pComment );
2244 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2245 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2246 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2247 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2248 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2249 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2250 break;
2253 case 8:
2254 case 9:
2256 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2258 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2259 break;
2262 default:
2263 FIXME( "Unhandled level %d\n", level );
2266 HeapFree( GetProcessHeap(), 0, data );
2267 return;
2270 /******************************************************************
2271 * DeviceCapabilities [WINSPOOL.@]
2272 * DeviceCapabilitiesA [WINSPOOL.@]
2275 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2276 LPSTR pOutput, LPDEVMODEA lpdm)
2278 INT ret;
2280 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice), debugstr_a(pPort), cap, pOutput, lpdm);
2282 if (!GDI_CallDeviceCapabilities16)
2284 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2285 (LPCSTR)104 );
2286 if (!GDI_CallDeviceCapabilities16) return -1;
2288 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2290 /* If DC_PAPERSIZE map POINT16s to POINTs */
2291 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2292 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2293 POINT *pt = (POINT *)pOutput;
2294 INT i;
2295 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2296 for(i = 0; i < ret; i++, pt++)
2298 pt->x = tmp[i].x;
2299 pt->y = tmp[i].y;
2301 HeapFree( GetProcessHeap(), 0, tmp );
2303 return ret;
2307 /*****************************************************************************
2308 * DeviceCapabilitiesW [WINSPOOL.@]
2310 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2313 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2314 WORD fwCapability, LPWSTR pOutput,
2315 const DEVMODEW *pDevMode)
2317 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2318 LPSTR pDeviceA = strdupWtoA(pDevice);
2319 LPSTR pPortA = strdupWtoA(pPort);
2320 INT ret;
2322 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice), debugstr_w(pPort), fwCapability, pOutput, pDevMode);
2324 if(pOutput && (fwCapability == DC_BINNAMES ||
2325 fwCapability == DC_FILEDEPENDENCIES ||
2326 fwCapability == DC_PAPERNAMES)) {
2327 /* These need A -> W translation */
2328 INT size = 0, i;
2329 LPSTR pOutputA;
2330 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2331 dmA);
2332 if(ret == -1)
2333 return ret;
2334 switch(fwCapability) {
2335 case DC_BINNAMES:
2336 size = 24;
2337 break;
2338 case DC_PAPERNAMES:
2339 case DC_FILEDEPENDENCIES:
2340 size = 64;
2341 break;
2343 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2344 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2345 dmA);
2346 for(i = 0; i < ret; i++)
2347 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2348 pOutput + (i * size), size);
2349 HeapFree(GetProcessHeap(), 0, pOutputA);
2350 } else {
2351 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2352 (LPSTR)pOutput, dmA);
2354 HeapFree(GetProcessHeap(),0,pPortA);
2355 HeapFree(GetProcessHeap(),0,pDeviceA);
2356 HeapFree(GetProcessHeap(),0,dmA);
2357 return ret;
2360 /******************************************************************
2361 * DocumentPropertiesA [WINSPOOL.@]
2363 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2365 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2366 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2367 LPDEVMODEA pDevModeInput,DWORD fMode )
2369 LPSTR lpName = pDeviceName, dupname = NULL;
2370 static CHAR port[] = "LPT1:";
2371 LONG ret;
2373 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2374 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2377 if(!pDeviceName || !*pDeviceName) {
2378 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2379 if(!lpNameW) {
2380 ERR("no name from hPrinter?\n");
2381 SetLastError(ERROR_INVALID_HANDLE);
2382 return -1;
2384 lpName = dupname = strdupWtoA(lpNameW);
2387 if (!GDI_CallExtDeviceMode16)
2389 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2390 (LPCSTR)102 );
2391 if (!GDI_CallExtDeviceMode16) {
2392 ERR("No CallExtDeviceMode16?\n");
2393 ret = -1;
2394 goto end;
2397 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2398 pDevModeInput, NULL, fMode);
2400 end:
2401 HeapFree(GetProcessHeap(), 0, dupname);
2402 return ret;
2406 /*****************************************************************************
2407 * DocumentPropertiesW (WINSPOOL.@)
2409 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2411 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2412 LPWSTR pDeviceName,
2413 LPDEVMODEW pDevModeOutput,
2414 LPDEVMODEW pDevModeInput, DWORD fMode)
2417 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2418 LPDEVMODEA pDevModeInputA;
2419 LPDEVMODEA pDevModeOutputA = NULL;
2420 LONG ret;
2422 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2423 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2424 fMode);
2425 if(pDevModeOutput) {
2426 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2427 if(ret < 0) return ret;
2428 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2430 pDevModeInputA = (fMode & DM_IN_BUFFER) ? DEVMODEdupWtoA(pDevModeInput) : NULL;
2431 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2432 pDevModeInputA, fMode);
2433 if(pDevModeOutput) {
2434 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2435 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2437 if(fMode == 0 && ret > 0)
2438 ret += (CCHDEVICENAME + CCHFORMNAME);
2439 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2440 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2441 return ret;
2444 /*****************************************************************************
2445 * IsValidDevmodeA [WINSPOOL.@]
2447 * Validate a DEVMODE structure and fix errors if possible.
2450 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2452 FIXME("(%p,%ld): stub\n", pDevMode, size);
2454 if(!pDevMode)
2455 return FALSE;
2457 return TRUE;
2460 /*****************************************************************************
2461 * IsValidDevmodeW [WINSPOOL.@]
2463 * Validate a DEVMODE structure and fix errors if possible.
2466 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2468 FIXME("(%p,%ld): stub\n", pDevMode, size);
2470 if(!pDevMode)
2471 return FALSE;
2473 return TRUE;
2476 /******************************************************************
2477 * OpenPrinterA [WINSPOOL.@]
2479 * See OpenPrinterW.
2482 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2483 LPPRINTER_DEFAULTSA pDefault)
2485 UNICODE_STRING lpPrinterNameW;
2486 UNICODE_STRING usBuffer;
2487 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2488 PWSTR pwstrPrinterNameW;
2489 BOOL ret;
2491 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName), phPrinter, pDefault);
2493 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2495 if(pDefault) {
2496 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2497 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2498 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2499 pDefaultW = &DefaultW;
2501 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2502 if(pDefault) {
2503 RtlFreeUnicodeString(&usBuffer);
2504 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2506 RtlFreeUnicodeString(&lpPrinterNameW);
2507 return ret;
2510 /******************************************************************
2511 * OpenPrinterW [WINSPOOL.@]
2513 * Open a Printer / Printserver or a Printer-Object
2515 * PARAMS
2516 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2517 * phPrinter [O] The resulting Handle is stored here
2518 * pDefault [I] PTR to Default Printer Settings or NULL
2520 * RETURNS
2521 * Success: TRUE
2522 * Failure: FALSE
2524 * NOTES
2525 * lpPrinterName is one of:
2526 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2527 *| Printer: "PrinterName"
2528 *| Printer-Object: "PrinterName,Job xxx"
2529 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2530 *| XcvPort: "Servername,XcvPort PortName"
2532 * BUGS
2533 *| Printer-Object not supported
2534 *| pDefaults is ignored
2537 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2539 HKEY key;
2541 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2543 if(!phPrinter) {
2544 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2545 SetLastError(ERROR_INVALID_PARAMETER);
2546 return FALSE;
2549 /* Get the unique handle of the printer or Printserver */
2550 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2552 if (*phPrinter && WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key ) == ERROR_SUCCESS)
2554 DWORD deleting = 0, size = sizeof( deleting ), type;
2555 DWORD status;
2556 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2557 WaitForSingleObject( init_mutex, INFINITE );
2558 status = get_dword_from_reg( key, StatusW );
2559 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2560 ReleaseMutex( init_mutex );
2561 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2562 update_driver( *phPrinter );
2563 RegCloseKey( key );
2566 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2567 return (*phPrinter != 0);
2570 /******************************************************************
2571 * AddMonitorA [WINSPOOL.@]
2573 * See AddMonitorW.
2576 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2578 LPWSTR nameW = NULL;
2579 INT len;
2580 BOOL res;
2581 LPMONITOR_INFO_2A mi2a;
2582 MONITOR_INFO_2W mi2w;
2584 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2585 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2586 debugstr_a(mi2a ? mi2a->pName : NULL),
2587 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2588 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2590 if (Level != 2) {
2591 SetLastError(ERROR_INVALID_LEVEL);
2592 return FALSE;
2595 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2596 if (mi2a == NULL) {
2597 return FALSE;
2600 if (pName) {
2601 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2602 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2603 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2606 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2607 if (mi2a->pName) {
2608 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2609 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2610 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2612 if (mi2a->pEnvironment) {
2613 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2614 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2615 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2617 if (mi2a->pDLLName) {
2618 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2619 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2620 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2623 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2625 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2626 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2627 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2629 HeapFree(GetProcessHeap(), 0, nameW);
2630 return (res);
2633 /******************************************************************************
2634 * AddMonitorW [WINSPOOL.@]
2636 * Install a Printmonitor
2638 * PARAMS
2639 * pName [I] Servername or NULL (local Computer)
2640 * Level [I] Structure-Level (Must be 2)
2641 * pMonitors [I] PTR to MONITOR_INFO_2
2643 * RETURNS
2644 * Success: TRUE
2645 * Failure: FALSE
2647 * NOTES
2648 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2651 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2653 LPMONITOR_INFO_2W mi2w;
2655 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2656 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2657 debugstr_w(mi2w ? mi2w->pName : NULL),
2658 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2659 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2661 if ((backend == NULL) && !load_backend()) return FALSE;
2663 if (Level != 2) {
2664 SetLastError(ERROR_INVALID_LEVEL);
2665 return FALSE;
2668 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2669 if (mi2w == NULL) {
2670 return FALSE;
2673 return backend->fpAddMonitor(pName, Level, pMonitors);
2676 /******************************************************************
2677 * DeletePrinterDriverA [WINSPOOL.@]
2680 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2682 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2685 /******************************************************************
2686 * DeletePrinterDriverW [WINSPOOL.@]
2689 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2691 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2694 /******************************************************************
2695 * DeleteMonitorA [WINSPOOL.@]
2697 * See DeleteMonitorW.
2700 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2702 LPWSTR nameW = NULL;
2703 LPWSTR EnvironmentW = NULL;
2704 LPWSTR MonitorNameW = NULL;
2705 BOOL res;
2706 INT len;
2708 if (pName) {
2709 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2710 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2711 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2714 if (pEnvironment) {
2715 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2716 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2717 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2719 if (pMonitorName) {
2720 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2721 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2722 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2725 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2727 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2728 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2729 HeapFree(GetProcessHeap(), 0, nameW);
2730 return (res);
2733 /******************************************************************
2734 * DeleteMonitorW [WINSPOOL.@]
2736 * Delete a specific Printmonitor from a Printing-Environment
2738 * PARAMS
2739 * pName [I] Servername or NULL (local Computer)
2740 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2741 * pMonitorName [I] Name of the Monitor, that should be deleted
2743 * RETURNS
2744 * Success: TRUE
2745 * Failure: FALSE
2747 * NOTES
2748 * pEnvironment is ignored in Windows for the local Computer.
2751 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2754 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2755 debugstr_w(pMonitorName));
2757 if ((backend == NULL) && !load_backend()) return FALSE;
2759 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2763 /******************************************************************
2764 * DeletePortA [WINSPOOL.@]
2766 * See DeletePortW.
2769 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2771 LPWSTR nameW = NULL;
2772 LPWSTR portW = NULL;
2773 INT len;
2774 DWORD res;
2776 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2778 /* convert servername to unicode */
2779 if (pName) {
2780 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2781 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2782 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2785 /* convert portname to unicode */
2786 if (pPortName) {
2787 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2788 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2789 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2792 res = DeletePortW(nameW, hWnd, portW);
2793 HeapFree(GetProcessHeap(), 0, nameW);
2794 HeapFree(GetProcessHeap(), 0, portW);
2795 return res;
2798 /******************************************************************
2799 * DeletePortW [WINSPOOL.@]
2801 * Delete a specific Port
2803 * PARAMS
2804 * pName [I] Servername or NULL (local Computer)
2805 * hWnd [I] Handle to parent Window for the Dialog-Box
2806 * pPortName [I] Name of the Port, that should be deleted
2808 * RETURNS
2809 * Success: TRUE
2810 * Failure: FALSE
2813 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2815 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2817 if ((backend == NULL) && !load_backend()) return FALSE;
2819 if (!pPortName) {
2820 SetLastError(RPC_X_NULL_REF_POINTER);
2821 return FALSE;
2824 return backend->fpDeletePort(pName, hWnd, pPortName);
2827 /******************************************************************************
2828 * WritePrinter [WINSPOOL.@]
2830 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2832 opened_printer_t *printer;
2833 BOOL ret = FALSE;
2835 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2837 EnterCriticalSection(&printer_handles_cs);
2838 printer = get_opened_printer(hPrinter);
2839 if(!printer)
2841 SetLastError(ERROR_INVALID_HANDLE);
2842 goto end;
2845 if(!printer->doc)
2847 SetLastError(ERROR_SPL_NO_STARTDOC);
2848 goto end;
2851 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2852 end:
2853 LeaveCriticalSection(&printer_handles_cs);
2854 return ret;
2857 /*****************************************************************************
2858 * AddFormA [WINSPOOL.@]
2860 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2862 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2863 return TRUE;
2866 /*****************************************************************************
2867 * AddFormW [WINSPOOL.@]
2869 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2871 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2872 return TRUE;
2875 /*****************************************************************************
2876 * AddJobA [WINSPOOL.@]
2878 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2880 BOOL ret;
2881 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2882 DWORD needed;
2884 if(Level != 1) {
2885 SetLastError(ERROR_INVALID_LEVEL);
2886 return FALSE;
2889 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2891 if(ret) {
2892 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2893 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2894 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2895 if(*pcbNeeded > cbBuf) {
2896 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2897 ret = FALSE;
2898 } else {
2899 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2900 addjobA->JobId = addjobW->JobId;
2901 addjobA->Path = (char *)(addjobA + 1);
2902 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2905 return ret;
2908 /*****************************************************************************
2909 * AddJobW [WINSPOOL.@]
2911 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2913 opened_printer_t *printer;
2914 job_t *job;
2915 BOOL ret = FALSE;
2916 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2917 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2918 WCHAR path[MAX_PATH], filename[MAX_PATH];
2919 DWORD len;
2920 ADDJOB_INFO_1W *addjob;
2922 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2924 EnterCriticalSection(&printer_handles_cs);
2926 printer = get_opened_printer(hPrinter);
2928 if(!printer) {
2929 SetLastError(ERROR_INVALID_HANDLE);
2930 goto end;
2933 if(Level != 1) {
2934 SetLastError(ERROR_INVALID_LEVEL);
2935 goto end;
2938 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2939 if(!job)
2940 goto end;
2942 job->job_id = InterlockedIncrement(&next_job_id);
2944 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2945 if(path[len - 1] != '\\')
2946 path[len++] = '\\';
2947 memcpy(path + len, spool_path, sizeof(spool_path));
2948 sprintfW(filename, fmtW, path, job->job_id);
2950 len = strlenW(filename);
2951 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2952 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2953 job->portname = NULL;
2954 job->document_title = strdupW(default_doc_title);
2955 job->printer_name = strdupW(printer->name);
2956 job->devmode = dup_devmode( printer->devmode );
2957 list_add_tail(&printer->queue->jobs, &job->entry);
2959 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2960 if(*pcbNeeded <= cbBuf) {
2961 addjob = (ADDJOB_INFO_1W*)pData;
2962 addjob->JobId = job->job_id;
2963 addjob->Path = (WCHAR *)(addjob + 1);
2964 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2965 ret = TRUE;
2966 } else
2967 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2969 end:
2970 LeaveCriticalSection(&printer_handles_cs);
2971 return ret;
2974 /*****************************************************************************
2975 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2977 * Return the PATH for the Print-Processors
2979 * See GetPrintProcessorDirectoryW.
2983 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2984 DWORD level, LPBYTE Info,
2985 DWORD cbBuf, LPDWORD pcbNeeded)
2987 LPWSTR serverW = NULL;
2988 LPWSTR envW = NULL;
2989 BOOL ret;
2990 INT len;
2992 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2993 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2996 if (server) {
2997 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2998 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2999 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
3002 if (env) {
3003 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
3004 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3005 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
3008 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
3009 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
3011 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
3012 cbBuf, pcbNeeded);
3014 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
3015 cbBuf, NULL, NULL) > 0;
3018 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3019 HeapFree(GetProcessHeap(), 0, envW);
3020 HeapFree(GetProcessHeap(), 0, serverW);
3021 return ret;
3024 /*****************************************************************************
3025 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3027 * Return the PATH for the Print-Processors
3029 * PARAMS
3030 * server [I] Servername (NT only) or NULL (local Computer)
3031 * env [I] Printing-Environment (see below) or NULL (Default)
3032 * level [I] Structure-Level (must be 1)
3033 * Info [O] PTR to Buffer that receives the Result
3034 * cbBuf [I] Size of Buffer at "Info"
3035 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3036 * required for the Buffer at "Info"
3038 * RETURNS
3039 * Success: TRUE and in pcbNeeded the Bytes used in Info
3040 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3041 * if cbBuf is too small
3043 * Native Values returned in Info on Success:
3044 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3045 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3046 *| win9x(Windows 4.0): "%winsysdir%"
3048 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3050 * BUGS
3051 * Only NULL or "" is supported for server
3054 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
3055 DWORD level, LPBYTE Info,
3056 DWORD cbBuf, LPDWORD pcbNeeded)
3059 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
3060 Info, cbBuf, pcbNeeded);
3062 if ((backend == NULL) && !load_backend()) return FALSE;
3064 if (level != 1) {
3065 /* (Level != 1) is ignored in win9x */
3066 SetLastError(ERROR_INVALID_LEVEL);
3067 return FALSE;
3070 if (pcbNeeded == NULL) {
3071 /* (pcbNeeded == NULL) is ignored in win9x */
3072 SetLastError(RPC_X_NULL_REF_POINTER);
3073 return FALSE;
3076 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
3079 /*****************************************************************************
3080 * WINSPOOL_OpenDriverReg [internal]
3082 * opens the registry for the printer drivers depending on the given input
3083 * variable pEnvironment
3085 * RETURNS:
3086 * the opened hkey on success
3087 * NULL on error
3089 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
3091 HKEY retval = NULL;
3092 LPWSTR buffer;
3093 const printenv_t * env;
3095 TRACE("(%s)\n", debugstr_w(pEnvironment));
3097 env = validate_envW(pEnvironment);
3098 if (!env) return NULL;
3100 buffer = HeapAlloc( GetProcessHeap(), 0,
3101 (strlenW(DriversW) + strlenW(env->envname) +
3102 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
3103 if(buffer) {
3104 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
3105 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
3106 HeapFree(GetProcessHeap(), 0, buffer);
3108 return retval;
3111 /*****************************************************************************
3112 * set_devices_and_printerports [internal]
3114 * set the [Devices] and [PrinterPorts] entries for a printer.
3117 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
3119 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
3120 WCHAR *devline;
3121 HKEY hkey;
3123 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
3125 /* FIXME: the driver must change to "winspool" */
3126 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
3127 if (devline) {
3128 lstrcpyW(devline, driver_nt);
3129 lstrcatW(devline, commaW);
3130 lstrcatW(devline, pi->pPortName);
3132 TRACE("using %s\n", debugstr_w(devline));
3133 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
3134 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
3135 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3136 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3137 RegCloseKey(hkey);
3140 lstrcatW(devline, timeout_15_45);
3141 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
3142 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
3143 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
3144 (lstrlenW(devline) + 1) * sizeof(WCHAR));
3145 RegCloseKey(hkey);
3147 HeapFree(GetProcessHeap(), 0, devline);
3151 /*****************************************************************************
3152 * AddPrinterW [WINSPOOL.@]
3154 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
3156 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3157 LPDEVMODEW dm;
3158 HANDLE retval;
3159 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3160 LONG size;
3162 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3164 if(pName && *pName) {
3165 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3166 SetLastError(ERROR_INVALID_PARAMETER);
3167 return 0;
3169 if(Level != 2) {
3170 ERR("Level = %d, unsupported!\n", Level);
3171 SetLastError(ERROR_INVALID_LEVEL);
3172 return 0;
3174 if(!pPrinter) {
3175 SetLastError(ERROR_INVALID_PARAMETER);
3176 return 0;
3178 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3179 ERROR_SUCCESS) {
3180 ERR("Can't create Printers key\n");
3181 return 0;
3183 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3184 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3185 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3186 RegCloseKey(hkeyPrinter);
3187 RegCloseKey(hkeyPrinters);
3188 return 0;
3190 RegCloseKey(hkeyPrinter);
3192 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3193 if(!hkeyDrivers) {
3194 ERR("Can't create Drivers key\n");
3195 RegCloseKey(hkeyPrinters);
3196 return 0;
3198 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3199 ERROR_SUCCESS) {
3200 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3201 RegCloseKey(hkeyPrinters);
3202 RegCloseKey(hkeyDrivers);
3203 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3204 return 0;
3206 RegCloseKey(hkeyDriver);
3207 RegCloseKey(hkeyDrivers);
3209 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3210 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3211 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3212 RegCloseKey(hkeyPrinters);
3213 return 0;
3216 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3217 ERROR_SUCCESS) {
3218 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3219 SetLastError(ERROR_INVALID_PRINTER_NAME);
3220 RegCloseKey(hkeyPrinters);
3221 return 0;
3224 set_devices_and_printerports(pi);
3226 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3227 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3228 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3229 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3230 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3231 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3232 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3233 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3234 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3235 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3236 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3237 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3238 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3239 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3240 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3241 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3242 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3243 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3245 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3247 if (size < 0)
3249 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3250 size = sizeof(DEVMODEW);
3252 if(pi->pDevMode)
3253 dm = pi->pDevMode;
3254 else
3256 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3257 dm->dmSize = size;
3258 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3260 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3261 HeapFree( GetProcessHeap(), 0, dm );
3262 dm = NULL;
3264 else
3266 /* set devmode to printer name */
3267 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3271 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3272 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3274 RegCloseKey(hkeyPrinter);
3275 RegCloseKey(hkeyPrinters);
3276 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3277 ERR("OpenPrinter failing\n");
3278 return 0;
3280 return retval;
3283 /*****************************************************************************
3284 * AddPrinterA [WINSPOOL.@]
3286 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3288 UNICODE_STRING pNameW;
3289 PWSTR pwstrNameW;
3290 PRINTER_INFO_2W *piW;
3291 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3292 HANDLE ret;
3294 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3295 if(Level != 2) {
3296 ERR("Level = %d, unsupported!\n", Level);
3297 SetLastError(ERROR_INVALID_LEVEL);
3298 return 0;
3300 pwstrNameW = asciitounicode(&pNameW,pName);
3301 piW = printer_info_AtoW( piA, Level );
3303 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3305 free_printer_info( piW, Level );
3306 RtlFreeUnicodeString(&pNameW);
3307 return ret;
3311 /*****************************************************************************
3312 * ClosePrinter [WINSPOOL.@]
3314 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3316 UINT_PTR i = (UINT_PTR)hPrinter;
3317 opened_printer_t *printer = NULL;
3319 TRACE("(%p)\n", hPrinter);
3321 EnterCriticalSection(&printer_handles_cs);
3323 if ((i > 0) && (i <= nb_printer_handles))
3324 printer = printer_handles[i - 1];
3327 if(printer)
3329 struct list *cursor, *cursor2;
3331 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3333 if(printer->doc)
3334 EndDocPrinter(hPrinter);
3336 if(InterlockedDecrement(&printer->queue->ref) == 0)
3338 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3340 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3341 ScheduleJob(hPrinter, job->job_id);
3343 HeapFree(GetProcessHeap(), 0, printer->queue);
3346 if (printer->backend_printer) {
3347 backend->fpClosePrinter(printer->backend_printer);
3350 free_printer_entry( printer );
3351 printer_handles[i - 1] = NULL;
3352 LeaveCriticalSection(&printer_handles_cs);
3353 return TRUE;
3356 LeaveCriticalSection(&printer_handles_cs);
3357 SetLastError(ERROR_INVALID_HANDLE);
3358 return FALSE;
3361 /*****************************************************************************
3362 * DeleteFormA [WINSPOOL.@]
3364 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3366 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3367 return TRUE;
3370 /*****************************************************************************
3371 * DeleteFormW [WINSPOOL.@]
3373 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3375 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3376 return TRUE;
3379 /*****************************************************************************
3380 * DeletePrinter [WINSPOOL.@]
3382 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3384 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3385 HKEY hkeyPrinters, hkey;
3386 WCHAR def[MAX_PATH];
3387 DWORD size = sizeof( def ) / sizeof( def[0] );
3389 if(!lpNameW) {
3390 SetLastError(ERROR_INVALID_HANDLE);
3391 return FALSE;
3393 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3394 RegDeleteTreeW(hkeyPrinters, lpNameW);
3395 RegCloseKey(hkeyPrinters);
3397 WriteProfileStringW(devicesW, lpNameW, NULL);
3398 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3400 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3401 RegDeleteValueW(hkey, lpNameW);
3402 RegCloseKey(hkey);
3405 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3406 RegDeleteValueW(hkey, lpNameW);
3407 RegCloseKey(hkey);
3410 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3412 WriteProfileStringW( windowsW, deviceW, NULL );
3413 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3415 RegDeleteValueW( hkey, deviceW );
3416 RegCloseKey( hkey );
3418 SetDefaultPrinterW( NULL );
3421 return TRUE;
3424 /*****************************************************************************
3425 * SetPrinterA [WINSPOOL.@]
3427 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3429 BYTE *dataW = data;
3430 BOOL ret;
3432 if (level != 0)
3434 dataW = printer_info_AtoW( data, level );
3435 if (!dataW) return FALSE;
3438 ret = SetPrinterW( printer, level, dataW, command );
3440 if (dataW != data) free_printer_info( dataW, level );
3442 return ret;
3445 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3447 set_reg_szW( key, NameW, pi->pPrinterName );
3448 set_reg_szW( key, Share_NameW, pi->pShareName );
3449 set_reg_szW( key, PortW, pi->pPortName );
3450 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3451 set_reg_szW( key, DescriptionW, pi->pComment );
3452 set_reg_szW( key, LocationW, pi->pLocation );
3454 if (pi->pDevMode)
3455 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3457 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3458 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3459 set_reg_szW( key, DatatypeW, pi->pDatatype );
3460 set_reg_szW( key, ParametersW, pi->pParameters );
3462 set_reg_DWORD( key, AttributesW, pi->Attributes );
3463 set_reg_DWORD( key, PriorityW, pi->Priority );
3464 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3465 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3466 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3469 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3471 if (!pi->pDevMode) return FALSE;
3473 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3474 return TRUE;
3477 /******************************************************************************
3478 * SetPrinterW [WINSPOOL.@]
3480 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3482 HKEY key;
3483 BOOL ret = FALSE;
3485 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3487 if (command != 0) FIXME( "Ignoring command %d\n", command );
3489 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3490 return FALSE;
3492 switch (level)
3494 case 2:
3496 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3497 set_printer_2( key, pi2 );
3498 ret = TRUE;
3499 break;
3502 case 8:
3503 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
3504 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3505 /* fall through */
3506 case 9:
3508 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3509 ret = set_printer_9( key, pi );
3510 break;
3513 default:
3514 FIXME( "Unimplemented level %d\n", level );
3515 SetLastError( ERROR_INVALID_LEVEL );
3518 RegCloseKey( key );
3519 return ret;
3522 /*****************************************************************************
3523 * SetJobA [WINSPOOL.@]
3525 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3526 LPBYTE pJob, DWORD Command)
3528 BOOL ret;
3529 LPBYTE JobW;
3530 UNICODE_STRING usBuffer;
3532 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3534 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3535 are all ignored by SetJob, so we don't bother copying them */
3536 switch(Level)
3538 case 0:
3539 JobW = NULL;
3540 break;
3541 case 1:
3543 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3544 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3546 JobW = (LPBYTE)info1W;
3547 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3548 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3549 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3550 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3551 info1W->Status = info1A->Status;
3552 info1W->Priority = info1A->Priority;
3553 info1W->Position = info1A->Position;
3554 info1W->PagesPrinted = info1A->PagesPrinted;
3555 break;
3557 case 2:
3559 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3560 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3562 JobW = (LPBYTE)info2W;
3563 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3564 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3565 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3566 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3567 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3568 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3569 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3570 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3571 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3572 info2W->Status = info2A->Status;
3573 info2W->Priority = info2A->Priority;
3574 info2W->Position = info2A->Position;
3575 info2W->StartTime = info2A->StartTime;
3576 info2W->UntilTime = info2A->UntilTime;
3577 info2W->PagesPrinted = info2A->PagesPrinted;
3578 break;
3580 case 3:
3581 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3582 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3583 break;
3584 default:
3585 SetLastError(ERROR_INVALID_LEVEL);
3586 return FALSE;
3589 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3591 switch(Level)
3593 case 1:
3595 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3596 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3597 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3598 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3599 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3600 break;
3602 case 2:
3604 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3605 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3606 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3607 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3608 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3609 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3610 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3611 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3612 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3613 break;
3616 HeapFree(GetProcessHeap(), 0, JobW);
3618 return ret;
3621 /*****************************************************************************
3622 * SetJobW [WINSPOOL.@]
3624 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3625 LPBYTE pJob, DWORD Command)
3627 BOOL ret = FALSE;
3628 job_t *job;
3630 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3631 FIXME("Ignoring everything other than document title\n");
3633 EnterCriticalSection(&printer_handles_cs);
3634 job = get_job(hPrinter, JobId);
3635 if(!job)
3636 goto end;
3638 switch(Level)
3640 case 0:
3641 break;
3642 case 1:
3644 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3645 HeapFree(GetProcessHeap(), 0, job->document_title);
3646 job->document_title = strdupW(info1->pDocument);
3647 break;
3649 case 2:
3651 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3652 HeapFree(GetProcessHeap(), 0, job->document_title);
3653 job->document_title = strdupW(info2->pDocument);
3654 HeapFree(GetProcessHeap(), 0, job->devmode);
3655 job->devmode = dup_devmode( info2->pDevMode );
3656 break;
3658 case 3:
3659 break;
3660 default:
3661 SetLastError(ERROR_INVALID_LEVEL);
3662 goto end;
3664 ret = TRUE;
3665 end:
3666 LeaveCriticalSection(&printer_handles_cs);
3667 return ret;
3670 /*****************************************************************************
3671 * EndDocPrinter [WINSPOOL.@]
3673 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3675 opened_printer_t *printer;
3676 BOOL ret = FALSE;
3677 TRACE("(%p)\n", hPrinter);
3679 EnterCriticalSection(&printer_handles_cs);
3681 printer = get_opened_printer(hPrinter);
3682 if(!printer)
3684 SetLastError(ERROR_INVALID_HANDLE);
3685 goto end;
3688 if(!printer->doc)
3690 SetLastError(ERROR_SPL_NO_STARTDOC);
3691 goto end;
3694 CloseHandle(printer->doc->hf);
3695 ScheduleJob(hPrinter, printer->doc->job_id);
3696 HeapFree(GetProcessHeap(), 0, printer->doc);
3697 printer->doc = NULL;
3698 ret = TRUE;
3699 end:
3700 LeaveCriticalSection(&printer_handles_cs);
3701 return ret;
3704 /*****************************************************************************
3705 * EndPagePrinter [WINSPOOL.@]
3707 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3709 FIXME("(%p): stub\n", hPrinter);
3710 return TRUE;
3713 /*****************************************************************************
3714 * StartDocPrinterA [WINSPOOL.@]
3716 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3718 UNICODE_STRING usBuffer;
3719 DOC_INFO_2W doc2W;
3720 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3721 DWORD ret;
3723 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3724 or one (DOC_INFO_3) extra DWORDs */
3726 switch(Level) {
3727 case 2:
3728 doc2W.JobId = doc2->JobId;
3729 /* fall through */
3730 case 3:
3731 doc2W.dwMode = doc2->dwMode;
3732 /* fall through */
3733 case 1:
3734 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3735 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3736 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3737 break;
3739 default:
3740 SetLastError(ERROR_INVALID_LEVEL);
3741 return FALSE;
3744 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3746 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3747 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3748 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3750 return ret;
3753 /*****************************************************************************
3754 * StartDocPrinterW [WINSPOOL.@]
3756 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3758 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3759 opened_printer_t *printer;
3760 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3761 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3762 JOB_INFO_1W job_info;
3763 DWORD needed, ret = 0;
3764 HANDLE hf;
3765 WCHAR *filename;
3766 job_t *job;
3768 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3769 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3770 debugstr_w(doc->pDatatype));
3772 if(Level < 1 || Level > 3)
3774 SetLastError(ERROR_INVALID_LEVEL);
3775 return 0;
3778 EnterCriticalSection(&printer_handles_cs);
3779 printer = get_opened_printer(hPrinter);
3780 if(!printer)
3782 SetLastError(ERROR_INVALID_HANDLE);
3783 goto end;
3786 if(printer->doc)
3788 SetLastError(ERROR_INVALID_PRINTER_STATE);
3789 goto end;
3792 /* Even if we're printing to a file we still add a print job, we'll
3793 just ignore the spool file name */
3795 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3797 ERR("AddJob failed gle %u\n", GetLastError());
3798 goto end;
3801 /* use pOutputFile only, when it is a real filename */
3802 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3803 filename = doc->pOutputFile;
3804 else
3805 filename = addjob->Path;
3807 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3808 if(hf == INVALID_HANDLE_VALUE)
3809 goto end;
3811 memset(&job_info, 0, sizeof(job_info));
3812 job_info.pDocument = doc->pDocName;
3813 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3815 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3816 printer->doc->hf = hf;
3817 ret = printer->doc->job_id = addjob->JobId;
3818 job = get_job(hPrinter, ret);
3819 job->portname = strdupW(doc->pOutputFile);
3821 end:
3822 LeaveCriticalSection(&printer_handles_cs);
3824 return ret;
3827 /*****************************************************************************
3828 * StartPagePrinter [WINSPOOL.@]
3830 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3832 FIXME("(%p): stub\n", hPrinter);
3833 return TRUE;
3836 /*****************************************************************************
3837 * GetFormA [WINSPOOL.@]
3839 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3840 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3842 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3843 Level,pForm,cbBuf,pcbNeeded);
3844 return FALSE;
3847 /*****************************************************************************
3848 * GetFormW [WINSPOOL.@]
3850 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3851 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3853 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3854 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3855 return FALSE;
3858 /*****************************************************************************
3859 * SetFormA [WINSPOOL.@]
3861 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3862 LPBYTE pForm)
3864 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3865 return FALSE;
3868 /*****************************************************************************
3869 * SetFormW [WINSPOOL.@]
3871 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3872 LPBYTE pForm)
3874 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3875 return FALSE;
3878 /*****************************************************************************
3879 * ReadPrinter [WINSPOOL.@]
3881 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3882 LPDWORD pNoBytesRead)
3884 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3885 return FALSE;
3888 /*****************************************************************************
3889 * ResetPrinterA [WINSPOOL.@]
3891 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3893 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3894 return FALSE;
3897 /*****************************************************************************
3898 * ResetPrinterW [WINSPOOL.@]
3900 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3902 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3903 return FALSE;
3906 /*****************************************************************************
3907 * get_filename_from_reg [internal]
3909 * Get ValueName from hkey storing result in out
3910 * when the Value in the registry has only a filename, use driverdir as prefix
3911 * outlen is space left in out
3912 * String is stored either as unicode or ascii
3916 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3917 LPBYTE out, DWORD outlen, LPDWORD needed)
3919 WCHAR filename[MAX_PATH];
3920 DWORD size;
3921 DWORD type;
3922 LONG ret;
3923 LPWSTR buffer = filename;
3924 LPWSTR ptr;
3926 *needed = 0;
3927 size = sizeof(filename);
3928 buffer[0] = '\0';
3929 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3930 if (ret == ERROR_MORE_DATA) {
3931 TRACE("need dynamic buffer: %u\n", size);
3932 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3933 if (!buffer) {
3934 /* No Memory is bad */
3935 return FALSE;
3937 buffer[0] = '\0';
3938 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3941 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3942 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3943 return FALSE;
3946 ptr = buffer;
3947 while (ptr) {
3948 /* do we have a full path ? */
3949 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3950 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3952 if (!ret) {
3953 /* we must build the full Path */
3954 *needed += dirlen;
3955 if ((out) && (outlen > dirlen)) {
3956 lstrcpyW((LPWSTR)out, driverdir);
3957 out += dirlen;
3958 outlen -= dirlen;
3960 else
3961 out = NULL;
3964 /* write the filename */
3965 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3966 if ((out) && (outlen >= size)) {
3967 lstrcpyW((LPWSTR)out, ptr);
3968 out += size;
3969 outlen -= size;
3971 else
3972 out = NULL;
3973 *needed += size;
3974 ptr += lstrlenW(ptr)+1;
3975 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3978 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3980 /* write the multisz-termination */
3981 if (type == REG_MULTI_SZ) {
3982 size = sizeof(WCHAR);
3984 *needed += size;
3985 if (out && (outlen >= size)) {
3986 memset (out, 0, size);
3989 return TRUE;
3992 /*****************************************************************************
3993 * WINSPOOL_GetStringFromReg
3995 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3996 * String is stored as unicode.
3998 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3999 DWORD buflen, DWORD *needed)
4001 DWORD sz = buflen, type;
4002 LONG ret;
4004 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4005 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
4006 WARN("Got ret = %d\n", ret);
4007 *needed = 0;
4008 return FALSE;
4010 /* add space for terminating '\0' */
4011 sz += sizeof(WCHAR);
4012 *needed = sz;
4014 if (ptr)
4015 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
4017 return TRUE;
4020 /*****************************************************************************
4021 * WINSPOOL_GetDefaultDevMode
4023 * Get a default DevMode values for wineps.
4025 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr, DWORD buflen, DWORD *needed)
4027 static const WCHAR winepsW[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4029 if (buflen >= sizeof(DEVMODEW))
4031 DEVMODEW *dm = (DEVMODEW *)ptr;
4033 /* the driver will update registry with real values */
4034 memset(dm, 0, sizeof(*dm));
4035 dm->dmSize = sizeof(*dm);
4036 lstrcpyW(dm->dmDeviceName, winepsW);
4038 *needed = sizeof(DEVMODEW);
4041 /*****************************************************************************
4042 * WINSPOOL_GetDevModeFromReg
4044 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4045 * DevMode is stored either as unicode or ascii.
4047 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
4048 LPBYTE ptr,
4049 DWORD buflen, DWORD *needed)
4051 DWORD sz = buflen, type;
4052 LONG ret;
4054 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
4055 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
4056 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
4057 if (sz < sizeof(DEVMODEA))
4059 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
4060 return FALSE;
4062 /* ensures that dmSize is not erratically bogus if registry is invalid */
4063 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
4064 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
4065 sz += (CCHDEVICENAME + CCHFORMNAME);
4066 if (ptr && (buflen >= sz)) {
4067 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
4068 memcpy(ptr, dmW, sz);
4069 HeapFree(GetProcessHeap(),0,dmW);
4071 *needed = sz;
4072 return TRUE;
4075 /*********************************************************************
4076 * WINSPOOL_GetPrinter_1
4078 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4080 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
4081 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4083 DWORD size, left = cbBuf;
4084 BOOL space = (cbBuf > 0);
4085 LPBYTE ptr = buf;
4087 *pcbNeeded = 0;
4089 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4090 if(space && size <= left) {
4091 pi1->pName = (LPWSTR)ptr;
4092 ptr += size;
4093 left -= size;
4094 } else
4095 space = FALSE;
4096 *pcbNeeded += size;
4099 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4100 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4101 if(space && size <= left) {
4102 pi1->pDescription = (LPWSTR)ptr;
4103 ptr += size;
4104 left -= size;
4105 } else
4106 space = FALSE;
4107 *pcbNeeded += size;
4110 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4111 if(space && size <= left) {
4112 pi1->pComment = (LPWSTR)ptr;
4113 ptr += size;
4114 left -= size;
4115 } else
4116 space = FALSE;
4117 *pcbNeeded += size;
4120 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
4122 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
4123 memset(pi1, 0, sizeof(*pi1));
4125 return space;
4127 /*********************************************************************
4128 * WINSPOOL_GetPrinter_2
4130 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4132 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
4133 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4135 DWORD size, left = cbBuf;
4136 BOOL space = (cbBuf > 0);
4137 LPBYTE ptr = buf;
4139 *pcbNeeded = 0;
4141 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4142 if(space && size <= left) {
4143 pi2->pPrinterName = (LPWSTR)ptr;
4144 ptr += size;
4145 left -= size;
4146 } else
4147 space = FALSE;
4148 *pcbNeeded += size;
4150 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4151 if(space && size <= left) {
4152 pi2->pShareName = (LPWSTR)ptr;
4153 ptr += size;
4154 left -= size;
4155 } else
4156 space = FALSE;
4157 *pcbNeeded += size;
4159 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4160 if(space && size <= left) {
4161 pi2->pPortName = (LPWSTR)ptr;
4162 ptr += size;
4163 left -= size;
4164 } else
4165 space = FALSE;
4166 *pcbNeeded += size;
4168 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4169 if(space && size <= left) {
4170 pi2->pDriverName = (LPWSTR)ptr;
4171 ptr += size;
4172 left -= size;
4173 } else
4174 space = FALSE;
4175 *pcbNeeded += size;
4177 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4178 if(space && size <= left) {
4179 pi2->pComment = (LPWSTR)ptr;
4180 ptr += size;
4181 left -= size;
4182 } else
4183 space = FALSE;
4184 *pcbNeeded += size;
4186 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4187 if(space && size <= left) {
4188 pi2->pLocation = (LPWSTR)ptr;
4189 ptr += size;
4190 left -= size;
4191 } else
4192 space = FALSE;
4193 *pcbNeeded += size;
4195 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4196 if(space && size <= left) {
4197 pi2->pDevMode = (LPDEVMODEW)ptr;
4198 ptr += size;
4199 left -= size;
4200 } else
4201 space = FALSE;
4202 *pcbNeeded += size;
4204 else
4206 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4207 if(space && size <= left) {
4208 pi2->pDevMode = (LPDEVMODEW)ptr;
4209 ptr += size;
4210 left -= size;
4211 } else
4212 space = FALSE;
4213 *pcbNeeded += size;
4215 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4216 if(space && size <= left) {
4217 pi2->pSepFile = (LPWSTR)ptr;
4218 ptr += size;
4219 left -= size;
4220 } else
4221 space = FALSE;
4222 *pcbNeeded += size;
4224 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4225 if(space && size <= left) {
4226 pi2->pPrintProcessor = (LPWSTR)ptr;
4227 ptr += size;
4228 left -= size;
4229 } else
4230 space = FALSE;
4231 *pcbNeeded += size;
4233 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4234 if(space && size <= left) {
4235 pi2->pDatatype = (LPWSTR)ptr;
4236 ptr += size;
4237 left -= size;
4238 } else
4239 space = FALSE;
4240 *pcbNeeded += size;
4242 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4243 if(space && size <= left) {
4244 pi2->pParameters = (LPWSTR)ptr;
4245 ptr += size;
4246 left -= size;
4247 } else
4248 space = FALSE;
4249 *pcbNeeded += size;
4251 if(pi2) {
4252 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4253 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4254 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4255 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4256 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4259 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4260 memset(pi2, 0, sizeof(*pi2));
4262 return space;
4265 /*********************************************************************
4266 * WINSPOOL_GetPrinter_4
4268 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4270 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4271 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4273 DWORD size, left = cbBuf;
4274 BOOL space = (cbBuf > 0);
4275 LPBYTE ptr = buf;
4277 *pcbNeeded = 0;
4279 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4280 if(space && size <= left) {
4281 pi4->pPrinterName = (LPWSTR)ptr;
4282 ptr += size;
4283 left -= size;
4284 } else
4285 space = FALSE;
4286 *pcbNeeded += size;
4288 if(pi4) {
4289 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4292 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4293 memset(pi4, 0, sizeof(*pi4));
4295 return space;
4298 /*********************************************************************
4299 * WINSPOOL_GetPrinter_5
4301 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4303 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4304 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4306 DWORD size, left = cbBuf;
4307 BOOL space = (cbBuf > 0);
4308 LPBYTE ptr = buf;
4310 *pcbNeeded = 0;
4312 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4313 if(space && size <= left) {
4314 pi5->pPrinterName = (LPWSTR)ptr;
4315 ptr += size;
4316 left -= size;
4317 } else
4318 space = FALSE;
4319 *pcbNeeded += size;
4321 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4322 if(space && size <= left) {
4323 pi5->pPortName = (LPWSTR)ptr;
4324 ptr += size;
4325 left -= size;
4326 } else
4327 space = FALSE;
4328 *pcbNeeded += size;
4330 if(pi5) {
4331 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4332 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4333 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4336 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4337 memset(pi5, 0, sizeof(*pi5));
4339 return space;
4342 /*********************************************************************
4343 * WINSPOOL_GetPrinter_7
4345 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4347 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4348 DWORD cbBuf, LPDWORD pcbNeeded)
4350 DWORD size, left = cbBuf;
4351 BOOL space = (cbBuf > 0);
4352 LPBYTE ptr = buf;
4354 *pcbNeeded = 0;
4356 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4358 ptr = NULL;
4359 size = sizeof(pi7->pszObjectGUID);
4361 if (space && size <= left) {
4362 pi7->pszObjectGUID = (LPWSTR)ptr;
4363 ptr += size;
4364 left -= size;
4365 } else
4366 space = FALSE;
4367 *pcbNeeded += size;
4368 if (pi7) {
4369 /* We do not have a Directory Service */
4370 pi7->dwAction = DSPRINT_UNPUBLISH;
4373 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4374 memset(pi7, 0, sizeof(*pi7));
4376 return space;
4379 /*********************************************************************
4380 * WINSPOOL_GetPrinter_9
4382 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4384 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4385 DWORD cbBuf, LPDWORD pcbNeeded)
4387 DWORD size;
4388 BOOL space = (cbBuf > 0);
4390 *pcbNeeded = 0;
4392 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4393 if(space && size <= cbBuf) {
4394 pi9->pDevMode = (LPDEVMODEW)buf;
4395 } else
4396 space = FALSE;
4397 *pcbNeeded += size;
4399 else
4401 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4402 if(space && size <= cbBuf) {
4403 pi9->pDevMode = (LPDEVMODEW)buf;
4404 } else
4405 space = FALSE;
4406 *pcbNeeded += size;
4409 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4410 memset(pi9, 0, sizeof(*pi9));
4412 return space;
4415 /*****************************************************************************
4416 * GetPrinterW [WINSPOOL.@]
4418 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4419 DWORD cbBuf, LPDWORD pcbNeeded)
4421 DWORD size, needed = 0, err;
4422 LPBYTE ptr = NULL;
4423 HKEY hkeyPrinter;
4424 BOOL ret;
4426 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4428 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4429 if (err)
4431 SetLastError( err );
4432 return FALSE;
4435 switch(Level) {
4436 case 2:
4438 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4440 size = sizeof(PRINTER_INFO_2W);
4441 if(size <= cbBuf) {
4442 ptr = pPrinter + size;
4443 cbBuf -= size;
4444 memset(pPrinter, 0, size);
4445 } else {
4446 pi2 = NULL;
4447 cbBuf = 0;
4449 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4450 needed += size;
4451 break;
4454 case 4:
4456 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4458 size = sizeof(PRINTER_INFO_4W);
4459 if(size <= cbBuf) {
4460 ptr = pPrinter + size;
4461 cbBuf -= size;
4462 memset(pPrinter, 0, size);
4463 } else {
4464 pi4 = NULL;
4465 cbBuf = 0;
4467 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4468 needed += size;
4469 break;
4473 case 5:
4475 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4477 size = sizeof(PRINTER_INFO_5W);
4478 if(size <= cbBuf) {
4479 ptr = pPrinter + size;
4480 cbBuf -= size;
4481 memset(pPrinter, 0, size);
4482 } else {
4483 pi5 = NULL;
4484 cbBuf = 0;
4487 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4488 needed += size;
4489 break;
4493 case 6:
4495 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4497 size = sizeof(PRINTER_INFO_6);
4498 if (size <= cbBuf) {
4499 /* FIXME: We do not update the status yet */
4500 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4501 ret = TRUE;
4502 } else {
4503 ret = FALSE;
4506 needed += size;
4507 break;
4510 case 7:
4512 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4514 size = sizeof(PRINTER_INFO_7W);
4515 if (size <= cbBuf) {
4516 ptr = pPrinter + size;
4517 cbBuf -= size;
4518 memset(pPrinter, 0, size);
4519 } else {
4520 pi7 = NULL;
4521 cbBuf = 0;
4524 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4525 needed += size;
4526 break;
4530 case 8:
4531 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4532 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4533 /* fall through */
4534 case 9:
4536 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4538 size = sizeof(PRINTER_INFO_9W);
4539 if(size <= cbBuf) {
4540 ptr = pPrinter + size;
4541 cbBuf -= size;
4542 memset(pPrinter, 0, size);
4543 } else {
4544 pi9 = NULL;
4545 cbBuf = 0;
4548 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4549 needed += size;
4550 break;
4554 default:
4555 FIXME("Unimplemented level %d\n", Level);
4556 SetLastError(ERROR_INVALID_LEVEL);
4557 RegCloseKey(hkeyPrinter);
4558 return FALSE;
4561 RegCloseKey(hkeyPrinter);
4563 TRACE("returning %d needed = %d\n", ret, needed);
4564 if(pcbNeeded) *pcbNeeded = needed;
4565 if(!ret)
4566 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4567 return ret;
4570 /*****************************************************************************
4571 * GetPrinterA [WINSPOOL.@]
4573 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4574 DWORD cbBuf, LPDWORD pcbNeeded)
4576 BOOL ret;
4577 LPBYTE buf = NULL;
4579 if (cbBuf)
4580 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4582 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4583 if (ret)
4584 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4585 HeapFree(GetProcessHeap(), 0, buf);
4587 return ret;
4590 /*****************************************************************************
4591 * WINSPOOL_EnumPrintersW
4593 * Implementation of EnumPrintersW
4595 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4596 DWORD dwLevel, LPBYTE lpbPrinters,
4597 DWORD cbBuf, LPDWORD lpdwNeeded,
4598 LPDWORD lpdwReturned)
4601 HKEY hkeyPrinters, hkeyPrinter;
4602 WCHAR PrinterName[255];
4603 DWORD needed = 0, number = 0;
4604 DWORD used, i, left;
4605 PBYTE pi, buf;
4607 if(lpbPrinters)
4608 memset(lpbPrinters, 0, cbBuf);
4609 if(lpdwReturned)
4610 *lpdwReturned = 0;
4611 if(lpdwNeeded)
4612 *lpdwNeeded = 0;
4614 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4615 if(dwType == PRINTER_ENUM_DEFAULT)
4616 return TRUE;
4618 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4619 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4620 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4621 if (!dwType) {
4622 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4623 return TRUE;
4628 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4629 FIXME("dwType = %08x\n", dwType);
4630 SetLastError(ERROR_INVALID_FLAGS);
4631 return FALSE;
4634 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4635 ERROR_SUCCESS) {
4636 ERR("Can't create Printers key\n");
4637 return FALSE;
4640 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4641 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4642 RegCloseKey(hkeyPrinters);
4643 ERR("Can't query Printers key\n");
4644 return FALSE;
4646 TRACE("Found %d printers\n", number);
4648 switch(dwLevel) {
4649 case 1:
4650 used = number * sizeof(PRINTER_INFO_1W);
4651 break;
4652 case 2:
4653 used = number * sizeof(PRINTER_INFO_2W);
4654 break;
4655 case 4:
4656 used = number * sizeof(PRINTER_INFO_4W);
4657 break;
4658 case 5:
4659 used = number * sizeof(PRINTER_INFO_5W);
4660 break;
4662 default:
4663 SetLastError(ERROR_INVALID_LEVEL);
4664 RegCloseKey(hkeyPrinters);
4665 return FALSE;
4667 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4669 for(i = 0; i < number; i++) {
4670 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4671 ERROR_SUCCESS) {
4672 ERR("Can't enum key number %d\n", i);
4673 RegCloseKey(hkeyPrinters);
4674 return FALSE;
4676 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4677 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4678 ERROR_SUCCESS) {
4679 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4680 RegCloseKey(hkeyPrinters);
4681 return FALSE;
4684 if(cbBuf > used) {
4685 buf = lpbPrinters + used;
4686 left = cbBuf - used;
4687 } else {
4688 buf = NULL;
4689 left = 0;
4692 switch(dwLevel) {
4693 case 1:
4694 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4695 left, &needed);
4696 used += needed;
4697 if(pi) pi += sizeof(PRINTER_INFO_1W);
4698 break;
4699 case 2:
4700 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4701 left, &needed);
4702 used += needed;
4703 if(pi) pi += sizeof(PRINTER_INFO_2W);
4704 break;
4705 case 4:
4706 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4707 left, &needed);
4708 used += needed;
4709 if(pi) pi += sizeof(PRINTER_INFO_4W);
4710 break;
4711 case 5:
4712 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4713 left, &needed);
4714 used += needed;
4715 if(pi) pi += sizeof(PRINTER_INFO_5W);
4716 break;
4717 default:
4718 ERR("Shouldn't be here!\n");
4719 RegCloseKey(hkeyPrinter);
4720 RegCloseKey(hkeyPrinters);
4721 return FALSE;
4723 RegCloseKey(hkeyPrinter);
4725 RegCloseKey(hkeyPrinters);
4727 if(lpdwNeeded)
4728 *lpdwNeeded = used;
4730 if(used > cbBuf) {
4731 if(lpbPrinters)
4732 memset(lpbPrinters, 0, cbBuf);
4733 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4734 return FALSE;
4736 if(lpdwReturned)
4737 *lpdwReturned = number;
4738 SetLastError(ERROR_SUCCESS);
4739 return TRUE;
4743 /******************************************************************
4744 * EnumPrintersW [WINSPOOL.@]
4746 * Enumerates the available printers, print servers and print
4747 * providers, depending on the specified flags, name and level.
4749 * RETURNS:
4751 * If level is set to 1:
4752 * Returns an array of PRINTER_INFO_1 data structures in the
4753 * lpbPrinters buffer.
4755 * If level is set to 2:
4756 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4757 * Returns an array of PRINTER_INFO_2 data structures in the
4758 * lpbPrinters buffer. Note that according to MSDN also an
4759 * OpenPrinter should be performed on every remote printer.
4761 * If level is set to 4 (officially WinNT only):
4762 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4763 * Fast: Only the registry is queried to retrieve printer names,
4764 * no connection to the driver is made.
4765 * Returns an array of PRINTER_INFO_4 data structures in the
4766 * lpbPrinters buffer.
4768 * If level is set to 5 (officially WinNT4/Win9x only):
4769 * Fast: Only the registry is queried to retrieve printer names,
4770 * no connection to the driver is made.
4771 * Returns an array of PRINTER_INFO_5 data structures in the
4772 * lpbPrinters buffer.
4774 * If level set to 3 or 6+:
4775 * returns zero (failure!)
4777 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4778 * for information.
4780 * BUGS:
4781 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4782 * - Only levels 2, 4 and 5 are implemented at the moment.
4783 * - 16-bit printer drivers are not enumerated.
4784 * - Returned amount of bytes used/needed does not match the real Windoze
4785 * implementation (as in this implementation, all strings are part
4786 * of the buffer, whereas Win32 keeps them somewhere else)
4787 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4789 * NOTE:
4790 * - In a regular Wine installation, no registry settings for printers
4791 * exist, which makes this function return an empty list.
4793 BOOL WINAPI EnumPrintersW(
4794 DWORD dwType, /* [in] Types of print objects to enumerate */
4795 LPWSTR lpszName, /* [in] name of objects to enumerate */
4796 DWORD dwLevel, /* [in] type of printer info structure */
4797 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4798 DWORD cbBuf, /* [in] max size of buffer in bytes */
4799 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4800 LPDWORD lpdwReturned /* [out] number of entries returned */
4803 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4804 lpdwNeeded, lpdwReturned);
4807 /******************************************************************
4808 * EnumPrintersA [WINSPOOL.@]
4810 * See EnumPrintersW
4813 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4814 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4816 BOOL ret;
4817 UNICODE_STRING pNameU;
4818 LPWSTR pNameW;
4819 LPBYTE pPrintersW;
4821 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4822 pPrinters, cbBuf, pcbNeeded, pcReturned);
4824 pNameW = asciitounicode(&pNameU, pName);
4826 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4827 MS Office need this */
4828 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4830 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4832 RtlFreeUnicodeString(&pNameU);
4833 if (ret) {
4834 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4836 HeapFree(GetProcessHeap(), 0, pPrintersW);
4837 return ret;
4840 /*****************************************************************************
4841 * WINSPOOL_GetDriverInfoFromReg [internal]
4843 * Enters the information from the registry into the DRIVER_INFO struct
4845 * RETURNS
4846 * zero if the printer driver does not exist in the registry
4847 * (only if Level > 1) otherwise nonzero
4849 static BOOL WINSPOOL_GetDriverInfoFromReg(
4850 HKEY hkeyDrivers,
4851 LPWSTR DriverName,
4852 const printenv_t * env,
4853 DWORD Level,
4854 LPBYTE ptr, /* DRIVER_INFO */
4855 LPBYTE pDriverStrings, /* strings buffer */
4856 DWORD cbBuf, /* size of string buffer */
4857 LPDWORD pcbNeeded) /* space needed for str. */
4859 DWORD size, tmp;
4860 HKEY hkeyDriver;
4861 WCHAR driverdir[MAX_PATH];
4862 DWORD dirlen;
4863 LPBYTE strPtr = pDriverStrings;
4864 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4866 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4867 debugstr_w(DriverName), env,
4868 Level, di, pDriverStrings, cbBuf);
4870 if (di) ZeroMemory(di, di_sizeof[Level]);
4872 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4873 if (*pcbNeeded <= cbBuf)
4874 strcpyW((LPWSTR)strPtr, DriverName);
4876 /* pName for level 1 has a different offset! */
4877 if (Level == 1) {
4878 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4879 return TRUE;
4882 /* .cVersion and .pName for level > 1 */
4883 if (di) {
4884 di->cVersion = env->driverversion;
4885 di->pName = (LPWSTR) strPtr;
4886 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4889 /* Reserve Space for the largest subdir and a Backslash*/
4890 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4891 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4892 /* Should never Fail */
4893 return FALSE;
4895 lstrcatW(driverdir, env->versionsubdir);
4896 lstrcatW(driverdir, backslashW);
4898 /* dirlen must not include the terminating zero */
4899 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4901 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4902 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4903 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4904 return FALSE;
4907 /* pEnvironment */
4908 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4910 *pcbNeeded += size;
4911 if (*pcbNeeded <= cbBuf) {
4912 lstrcpyW((LPWSTR)strPtr, env->envname);
4913 if (di) di->pEnvironment = (LPWSTR)strPtr;
4914 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4917 /* .pDriverPath is the Graphics rendering engine.
4918 The full Path is required to avoid a crash in some apps */
4919 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4920 *pcbNeeded += size;
4921 if (*pcbNeeded <= cbBuf)
4922 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4924 if (di) di->pDriverPath = (LPWSTR)strPtr;
4925 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4928 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4929 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4930 *pcbNeeded += size;
4931 if (*pcbNeeded <= cbBuf)
4932 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4934 if (di) di->pDataFile = (LPWSTR)strPtr;
4935 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4938 /* .pConfigFile is the Driver user Interface */
4939 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4940 *pcbNeeded += size;
4941 if (*pcbNeeded <= cbBuf)
4942 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4944 if (di) di->pConfigFile = (LPWSTR)strPtr;
4945 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4948 if (Level == 2 ) {
4949 RegCloseKey(hkeyDriver);
4950 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4951 return TRUE;
4954 if (Level == 5 ) {
4955 RegCloseKey(hkeyDriver);
4956 FIXME("level 5: incomplete\n");
4957 return TRUE;
4960 /* .pHelpFile */
4961 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4962 *pcbNeeded += size;
4963 if (*pcbNeeded <= cbBuf)
4964 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4966 if (di) di->pHelpFile = (LPWSTR)strPtr;
4967 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4970 /* .pDependentFiles */
4971 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4972 *pcbNeeded += size;
4973 if (*pcbNeeded <= cbBuf)
4974 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4976 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4977 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4979 else if (GetVersion() & 0x80000000) {
4980 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4981 size = 2 * sizeof(WCHAR);
4982 *pcbNeeded += size;
4983 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4985 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4986 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4989 /* .pMonitorName is the optional Language Monitor */
4990 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4991 *pcbNeeded += size;
4992 if (*pcbNeeded <= cbBuf)
4993 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4995 if (di) di->pMonitorName = (LPWSTR)strPtr;
4996 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4999 /* .pDefaultDataType */
5000 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
5001 *pcbNeeded += size;
5002 if(*pcbNeeded <= cbBuf)
5003 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
5005 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
5006 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5009 if (Level == 3 ) {
5010 RegCloseKey(hkeyDriver);
5011 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5012 return TRUE;
5015 /* .pszzPreviousNames */
5016 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
5017 *pcbNeeded += size;
5018 if(*pcbNeeded <= cbBuf)
5019 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
5021 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
5022 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5025 if (Level == 4 ) {
5026 RegCloseKey(hkeyDriver);
5027 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5028 return TRUE;
5031 /* support is missing, but not important enough for a FIXME */
5032 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
5034 /* .pszMfgName */
5035 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
5036 *pcbNeeded += size;
5037 if(*pcbNeeded <= cbBuf)
5038 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
5040 if (di) di->pszMfgName = (LPWSTR)strPtr;
5041 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5044 /* .pszOEMUrl */
5045 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
5046 *pcbNeeded += size;
5047 if(*pcbNeeded <= cbBuf)
5048 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
5050 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
5051 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5054 /* .pszHardwareID */
5055 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
5056 *pcbNeeded += size;
5057 if(*pcbNeeded <= cbBuf)
5058 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
5060 if (di) di->pszHardwareID = (LPWSTR)strPtr;
5061 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5064 /* .pszProvider */
5065 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
5066 *pcbNeeded += size;
5067 if(*pcbNeeded <= cbBuf)
5068 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
5070 if (di) di->pszProvider = (LPWSTR)strPtr;
5071 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
5074 if (Level == 6 ) {
5075 RegCloseKey(hkeyDriver);
5076 return TRUE;
5079 /* support is missing, but not important enough for a FIXME */
5080 TRACE("level 8: incomplete\n");
5082 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5083 RegCloseKey(hkeyDriver);
5084 return TRUE;
5087 /*****************************************************************************
5088 * GetPrinterDriverW [WINSPOOL.@]
5090 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5091 DWORD Level, LPBYTE pDriverInfo,
5092 DWORD cbBuf, LPDWORD pcbNeeded)
5094 LPCWSTR name;
5095 WCHAR DriverName[100];
5096 DWORD ret, type, size, needed = 0;
5097 LPBYTE ptr = NULL;
5098 HKEY hkeyPrinter, hkeyDrivers;
5099 const printenv_t * env;
5101 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5102 Level,pDriverInfo,cbBuf, pcbNeeded);
5104 if (cbBuf > 0)
5105 ZeroMemory(pDriverInfo, cbBuf);
5107 if (!(name = get_opened_printer_name(hPrinter))) {
5108 SetLastError(ERROR_INVALID_HANDLE);
5109 return FALSE;
5112 if (Level < 1 || Level == 7 || Level > 8) {
5113 SetLastError(ERROR_INVALID_LEVEL);
5114 return FALSE;
5117 env = validate_envW(pEnvironment);
5118 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5120 ret = open_printer_reg_key( name, &hkeyPrinter );
5121 if (ret)
5123 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
5124 SetLastError( ret );
5125 return FALSE;
5128 size = sizeof(DriverName);
5129 DriverName[0] = 0;
5130 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5131 (LPBYTE)DriverName, &size);
5132 RegCloseKey(hkeyPrinter);
5133 if(ret != ERROR_SUCCESS) {
5134 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5135 return FALSE;
5138 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5139 if(!hkeyDrivers) {
5140 ERR("Can't create Drivers key\n");
5141 return FALSE;
5144 size = di_sizeof[Level];
5145 if ((size <= cbBuf) && pDriverInfo)
5146 ptr = pDriverInfo + size;
5148 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5149 env, Level, pDriverInfo, ptr,
5150 (cbBuf < size) ? 0 : cbBuf - size,
5151 &needed)) {
5152 RegCloseKey(hkeyDrivers);
5153 return FALSE;
5156 RegCloseKey(hkeyDrivers);
5158 if(pcbNeeded) *pcbNeeded = size + needed;
5159 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5160 if(cbBuf >= size + needed) return TRUE;
5161 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5162 return FALSE;
5165 /*****************************************************************************
5166 * GetPrinterDriverA [WINSPOOL.@]
5168 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5169 DWORD Level, LPBYTE pDriverInfo,
5170 DWORD cbBuf, LPDWORD pcbNeeded)
5172 BOOL ret;
5173 UNICODE_STRING pEnvW;
5174 PWSTR pwstrEnvW;
5175 LPBYTE buf = NULL;
5177 if (cbBuf)
5179 ZeroMemory(pDriverInfo, cbBuf);
5180 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5183 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5184 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5185 cbBuf, pcbNeeded);
5186 if (ret)
5187 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5189 HeapFree(GetProcessHeap(), 0, buf);
5191 RtlFreeUnicodeString(&pEnvW);
5192 return ret;
5195 /*****************************************************************************
5196 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5198 * Return the PATH for the Printer-Drivers (UNICODE)
5200 * PARAMS
5201 * pName [I] Servername (NT only) or NULL (local Computer)
5202 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5203 * Level [I] Structure-Level (must be 1)
5204 * pDriverDirectory [O] PTR to Buffer that receives the Result
5205 * cbBuf [I] Size of Buffer at pDriverDirectory
5206 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5207 * required for pDriverDirectory
5209 * RETURNS
5210 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5211 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5212 * if cbBuf is too small
5214 * Native Values returned in pDriverDirectory on Success:
5215 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5216 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5217 *| win9x(Windows 4.0): "%winsysdir%"
5219 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5221 * FIXME
5222 *- Only NULL or "" is supported for pName
5225 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5226 DWORD Level, LPBYTE pDriverDirectory,
5227 DWORD cbBuf, LPDWORD pcbNeeded)
5229 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5230 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5232 if ((backend == NULL) && !load_backend()) return FALSE;
5234 if (Level != 1) {
5235 /* (Level != 1) is ignored in win9x */
5236 SetLastError(ERROR_INVALID_LEVEL);
5237 return FALSE;
5239 if (pcbNeeded == NULL) {
5240 /* (pcbNeeded == NULL) is ignored in win9x */
5241 SetLastError(RPC_X_NULL_REF_POINTER);
5242 return FALSE;
5245 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5246 pDriverDirectory, cbBuf, pcbNeeded);
5251 /*****************************************************************************
5252 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5254 * Return the PATH for the Printer-Drivers (ANSI)
5256 * See GetPrinterDriverDirectoryW.
5258 * NOTES
5259 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5262 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5263 DWORD Level, LPBYTE pDriverDirectory,
5264 DWORD cbBuf, LPDWORD pcbNeeded)
5266 UNICODE_STRING nameW, environmentW;
5267 BOOL ret;
5268 DWORD pcbNeededW;
5269 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5270 WCHAR *driverDirectoryW = NULL;
5272 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5273 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5275 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5277 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5278 else nameW.Buffer = NULL;
5279 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5280 else environmentW.Buffer = NULL;
5282 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5283 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5284 if (ret) {
5285 DWORD needed;
5286 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5287 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5288 if(pcbNeeded)
5289 *pcbNeeded = needed;
5290 ret = needed <= cbBuf;
5291 } else
5292 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5294 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5296 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5297 RtlFreeUnicodeString(&environmentW);
5298 RtlFreeUnicodeString(&nameW);
5300 return ret;
5303 /*****************************************************************************
5304 * AddPrinterDriverA [WINSPOOL.@]
5306 * See AddPrinterDriverW.
5309 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5311 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5312 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5315 /******************************************************************************
5316 * AddPrinterDriverW (WINSPOOL.@)
5318 * Install a Printer Driver
5320 * PARAMS
5321 * pName [I] Servername or NULL (local Computer)
5322 * level [I] Level for the supplied DRIVER_INFO_*W struct
5323 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5325 * RESULTS
5326 * Success: TRUE
5327 * Failure: FALSE
5330 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5332 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5333 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5336 /*****************************************************************************
5337 * AddPrintProcessorA [WINSPOOL.@]
5339 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5340 LPSTR pPrintProcessorName)
5342 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5343 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5344 return FALSE;
5347 /*****************************************************************************
5348 * AddPrintProcessorW [WINSPOOL.@]
5350 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5351 LPWSTR pPrintProcessorName)
5353 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5354 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5355 return TRUE;
5358 /*****************************************************************************
5359 * AddPrintProvidorA [WINSPOOL.@]
5361 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5363 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5364 return FALSE;
5367 /*****************************************************************************
5368 * AddPrintProvidorW [WINSPOOL.@]
5370 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5372 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5373 return FALSE;
5376 /*****************************************************************************
5377 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5379 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5380 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5382 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5383 pDevModeOutput, pDevModeInput);
5384 return 0;
5387 /*****************************************************************************
5388 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5390 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5391 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5393 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5394 pDevModeOutput, pDevModeInput);
5395 return 0;
5398 /*****************************************************************************
5399 * PrinterProperties [WINSPOOL.@]
5401 * Displays a dialog to set the properties of the printer.
5403 * RETURNS
5404 * nonzero on success or zero on failure
5406 * BUGS
5407 * implemented as stub only
5409 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5410 HANDLE hPrinter /* [in] handle to printer object */
5412 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5413 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5414 return FALSE;
5417 /*****************************************************************************
5418 * EnumJobsA [WINSPOOL.@]
5421 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5422 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5423 LPDWORD pcReturned)
5425 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5426 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5428 if(pcbNeeded) *pcbNeeded = 0;
5429 if(pcReturned) *pcReturned = 0;
5430 return FALSE;
5434 /*****************************************************************************
5435 * EnumJobsW [WINSPOOL.@]
5438 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5439 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5440 LPDWORD pcReturned)
5442 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5443 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5445 if(pcbNeeded) *pcbNeeded = 0;
5446 if(pcReturned) *pcReturned = 0;
5447 return FALSE;
5450 /*****************************************************************************
5451 * WINSPOOL_EnumPrinterDrivers [internal]
5453 * Delivers information about all printer drivers installed on the
5454 * localhost or a given server
5456 * RETURNS
5457 * nonzero on success or zero on failure. If the buffer for the returned
5458 * information is too small the function will return an error
5460 * BUGS
5461 * - only implemented for localhost, foreign hosts will return an error
5463 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5464 DWORD Level, LPBYTE pDriverInfo,
5465 DWORD driver_index,
5466 DWORD cbBuf, LPDWORD pcbNeeded,
5467 LPDWORD pcFound, DWORD data_offset)
5469 { HKEY hkeyDrivers;
5470 DWORD i, size = 0;
5471 const printenv_t * env;
5473 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5474 debugstr_w(pName), debugstr_w(pEnvironment),
5475 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5477 env = validate_envW(pEnvironment);
5478 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5480 *pcFound = 0;
5482 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5483 if(!hkeyDrivers) {
5484 ERR("Can't open Drivers key\n");
5485 return FALSE;
5488 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5489 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5490 RegCloseKey(hkeyDrivers);
5491 ERR("Can't query Drivers key\n");
5492 return FALSE;
5494 TRACE("Found %d Drivers\n", *pcFound);
5496 /* get size of single struct
5497 * unicode and ascii structure have the same size
5499 size = di_sizeof[Level];
5501 if (data_offset == 0)
5502 data_offset = size * (*pcFound);
5503 *pcbNeeded = data_offset;
5505 for( i = 0; i < *pcFound; i++) {
5506 WCHAR DriverNameW[255];
5507 PBYTE table_ptr = NULL;
5508 PBYTE data_ptr = NULL;
5509 DWORD needed = 0;
5511 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5512 != ERROR_SUCCESS) {
5513 ERR("Can't enum key number %d\n", i);
5514 RegCloseKey(hkeyDrivers);
5515 return FALSE;
5518 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5519 table_ptr = pDriverInfo + (driver_index + i) * size;
5520 if (pDriverInfo && *pcbNeeded <= cbBuf)
5521 data_ptr = pDriverInfo + *pcbNeeded;
5523 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5524 env, Level, table_ptr, data_ptr,
5525 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5526 &needed)) {
5527 RegCloseKey(hkeyDrivers);
5528 return FALSE;
5531 *pcbNeeded += needed;
5534 RegCloseKey(hkeyDrivers);
5536 if(cbBuf < *pcbNeeded){
5537 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5538 return FALSE;
5541 return TRUE;
5544 /*****************************************************************************
5545 * EnumPrinterDriversW [WINSPOOL.@]
5547 * see function EnumPrinterDrivers for RETURNS, BUGS
5549 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5550 LPBYTE pDriverInfo, DWORD cbBuf,
5551 LPDWORD pcbNeeded, LPDWORD pcReturned)
5553 static const WCHAR allW[] = {'a','l','l',0};
5554 BOOL ret;
5555 DWORD found;
5557 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5559 SetLastError(RPC_X_NULL_REF_POINTER);
5560 return FALSE;
5563 /* check for local drivers */
5564 if((pName) && (pName[0])) {
5565 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5566 SetLastError(ERROR_ACCESS_DENIED);
5567 return FALSE;
5570 /* check input parameter */
5571 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5572 SetLastError(ERROR_INVALID_LEVEL);
5573 return FALSE;
5576 if(pDriverInfo && cbBuf > 0)
5577 memset( pDriverInfo, 0, cbBuf);
5579 /* Exception: pull all printers */
5580 if (pEnvironment && !strcmpW(pEnvironment, allW))
5582 DWORD i, needed, bufsize = cbBuf;
5583 DWORD total_found = 0;
5584 DWORD data_offset;
5586 /* Precompute the overall total; we need this to know
5587 where pointers end and data begins (i.e. data_offset) */
5588 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5590 needed = found = 0;
5591 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5592 NULL, 0, 0, &needed, &found, 0);
5593 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5594 total_found += found;
5597 data_offset = di_sizeof[Level] * total_found;
5599 *pcReturned = 0;
5600 *pcbNeeded = 0;
5601 total_found = 0;
5602 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5604 needed = found = 0;
5605 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5606 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5607 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5608 else if (ret)
5609 *pcReturned += found;
5610 *pcbNeeded = needed;
5611 data_offset = needed;
5612 total_found += found;
5614 return ret;
5617 /* Normal behavior */
5618 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5619 0, cbBuf, pcbNeeded, &found, 0);
5620 if (ret)
5621 *pcReturned = found;
5623 return ret;
5626 /*****************************************************************************
5627 * EnumPrinterDriversA [WINSPOOL.@]
5629 * see function EnumPrinterDrivers for RETURNS, BUGS
5631 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5632 LPBYTE pDriverInfo, DWORD cbBuf,
5633 LPDWORD pcbNeeded, LPDWORD pcReturned)
5635 BOOL ret;
5636 UNICODE_STRING pNameW, pEnvironmentW;
5637 PWSTR pwstrNameW, pwstrEnvironmentW;
5638 LPBYTE buf = NULL;
5640 if (cbBuf)
5641 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5643 pwstrNameW = asciitounicode(&pNameW, pName);
5644 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5646 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5647 buf, cbBuf, pcbNeeded, pcReturned);
5648 if (ret)
5649 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5651 HeapFree(GetProcessHeap(), 0, buf);
5653 RtlFreeUnicodeString(&pNameW);
5654 RtlFreeUnicodeString(&pEnvironmentW);
5656 return ret;
5659 /******************************************************************************
5660 * EnumPortsA (WINSPOOL.@)
5662 * See EnumPortsW.
5665 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5666 LPDWORD pcbNeeded, LPDWORD pcReturned)
5668 BOOL res;
5669 LPBYTE bufferW = NULL;
5670 LPWSTR nameW = NULL;
5671 DWORD needed = 0;
5672 DWORD numentries = 0;
5673 INT len;
5675 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5676 cbBuf, pcbNeeded, pcReturned);
5678 /* convert servername to unicode */
5679 if (pName) {
5680 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5681 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5682 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5684 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5685 needed = cbBuf * sizeof(WCHAR);
5686 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5687 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5689 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5690 if (pcbNeeded) needed = *pcbNeeded;
5691 /* HeapReAlloc return NULL, when bufferW was NULL */
5692 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5693 HeapAlloc(GetProcessHeap(), 0, needed);
5695 /* Try again with the large Buffer */
5696 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5698 needed = pcbNeeded ? *pcbNeeded : 0;
5699 numentries = pcReturned ? *pcReturned : 0;
5702 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5703 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5705 if (res) {
5706 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5707 DWORD entrysize = 0;
5708 DWORD index;
5709 LPSTR ptr;
5710 LPPORT_INFO_2W pi2w;
5711 LPPORT_INFO_2A pi2a;
5713 needed = 0;
5714 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5716 /* First pass: calculate the size for all Entries */
5717 pi2w = (LPPORT_INFO_2W) bufferW;
5718 pi2a = (LPPORT_INFO_2A) pPorts;
5719 index = 0;
5720 while (index < numentries) {
5721 index++;
5722 needed += entrysize; /* PORT_INFO_?A */
5723 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5725 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5726 NULL, 0, NULL, NULL);
5727 if (Level > 1) {
5728 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5729 NULL, 0, NULL, NULL);
5730 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5731 NULL, 0, NULL, NULL);
5733 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5734 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5735 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5738 /* check for errors and quit on failure */
5739 if (cbBuf < needed) {
5740 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5741 res = FALSE;
5742 goto cleanup;
5744 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5745 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5746 cbBuf -= len ; /* free Bytes in the user-Buffer */
5747 pi2w = (LPPORT_INFO_2W) bufferW;
5748 pi2a = (LPPORT_INFO_2A) pPorts;
5749 index = 0;
5750 /* Second Pass: Fill the User Buffer (if we have one) */
5751 while ((index < numentries) && pPorts) {
5752 index++;
5753 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5754 pi2a->pPortName = ptr;
5755 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5756 ptr, cbBuf , NULL, NULL);
5757 ptr += len;
5758 cbBuf -= len;
5759 if (Level > 1) {
5760 pi2a->pMonitorName = ptr;
5761 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5762 ptr, cbBuf, NULL, NULL);
5763 ptr += len;
5764 cbBuf -= len;
5766 pi2a->pDescription = ptr;
5767 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5768 ptr, cbBuf, NULL, NULL);
5769 ptr += len;
5770 cbBuf -= len;
5772 pi2a->fPortType = pi2w->fPortType;
5773 pi2a->Reserved = 0; /* documented: "must be zero" */
5776 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5777 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5778 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5782 cleanup:
5783 if (pcbNeeded) *pcbNeeded = needed;
5784 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5786 HeapFree(GetProcessHeap(), 0, nameW);
5787 HeapFree(GetProcessHeap(), 0, bufferW);
5789 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5790 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5792 return (res);
5796 /******************************************************************************
5797 * EnumPortsW (WINSPOOL.@)
5799 * Enumerate available Ports
5801 * PARAMS
5802 * pName [I] Servername or NULL (local Computer)
5803 * Level [I] Structure-Level (1 or 2)
5804 * pPorts [O] PTR to Buffer that receives the Result
5805 * cbBuf [I] Size of Buffer at pPorts
5806 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5807 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5809 * RETURNS
5810 * Success: TRUE
5811 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5814 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5817 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5818 cbBuf, pcbNeeded, pcReturned);
5820 if ((backend == NULL) && !load_backend()) return FALSE;
5822 /* Level is not checked in win9x */
5823 if (!Level || (Level > 2)) {
5824 WARN("level (%d) is ignored in win9x\n", Level);
5825 SetLastError(ERROR_INVALID_LEVEL);
5826 return FALSE;
5828 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5829 SetLastError(RPC_X_NULL_REF_POINTER);
5830 return FALSE;
5833 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5836 /******************************************************************************
5837 * GetDefaultPrinterW (WINSPOOL.@)
5839 * FIXME
5840 * This function must read the value from data 'device' of key
5841 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5843 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5845 BOOL retval = TRUE;
5846 DWORD insize, len;
5847 WCHAR *buffer, *ptr;
5849 if (!namesize)
5851 SetLastError(ERROR_INVALID_PARAMETER);
5852 return FALSE;
5855 /* make the buffer big enough for the stuff from the profile/registry,
5856 * the content must fit into the local buffer to compute the correct
5857 * size even if the extern buffer is too small or not given.
5858 * (20 for ,driver,port) */
5859 insize = *namesize;
5860 len = max(100, (insize + 20));
5861 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5863 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5865 SetLastError (ERROR_FILE_NOT_FOUND);
5866 retval = FALSE;
5867 goto end;
5869 TRACE("%s\n", debugstr_w(buffer));
5871 if ((ptr = strchrW(buffer, ',')) == NULL)
5873 SetLastError(ERROR_INVALID_NAME);
5874 retval = FALSE;
5875 goto end;
5878 *ptr = 0;
5879 *namesize = strlenW(buffer) + 1;
5880 if(!name || (*namesize > insize))
5882 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5883 retval = FALSE;
5884 goto end;
5886 strcpyW(name, buffer);
5888 end:
5889 HeapFree( GetProcessHeap(), 0, buffer);
5890 return retval;
5894 /******************************************************************************
5895 * GetDefaultPrinterA (WINSPOOL.@)
5897 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5899 BOOL retval = TRUE;
5900 DWORD insize = 0;
5901 WCHAR *bufferW = NULL;
5903 if (!namesize)
5905 SetLastError(ERROR_INVALID_PARAMETER);
5906 return FALSE;
5909 if(name && *namesize) {
5910 insize = *namesize;
5911 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5914 if(!GetDefaultPrinterW( bufferW, namesize)) {
5915 retval = FALSE;
5916 goto end;
5919 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5920 NULL, NULL);
5921 if (!*namesize)
5923 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5924 retval = FALSE;
5926 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5928 end:
5929 HeapFree( GetProcessHeap(), 0, bufferW);
5930 return retval;
5934 /******************************************************************************
5935 * SetDefaultPrinterW (WINSPOOL.204)
5937 * Set the Name of the Default Printer
5939 * PARAMS
5940 * pszPrinter [I] Name of the Printer or NULL
5942 * RETURNS
5943 * Success: True
5944 * Failure: FALSE
5946 * NOTES
5947 * When the Parameter is NULL or points to an Empty String and
5948 * a Default Printer was already present, then this Function changes nothing.
5949 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5950 * the First enumerated local Printer is used.
5953 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5955 WCHAR default_printer[MAX_PATH];
5956 LPWSTR buffer = NULL;
5957 HKEY hreg;
5958 DWORD size;
5959 DWORD namelen;
5960 LONG lres;
5962 TRACE("(%s)\n", debugstr_w(pszPrinter));
5963 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5965 default_printer[0] = '\0';
5966 size = sizeof(default_printer)/sizeof(WCHAR);
5968 /* if we have a default Printer, do nothing. */
5969 if (GetDefaultPrinterW(default_printer, &size))
5970 return TRUE;
5972 pszPrinter = NULL;
5973 /* we have no default Printer: search local Printers and use the first */
5974 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5976 default_printer[0] = '\0';
5977 size = sizeof(default_printer)/sizeof(WCHAR);
5978 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5980 pszPrinter = default_printer;
5981 TRACE("using %s\n", debugstr_w(pszPrinter));
5983 RegCloseKey(hreg);
5986 if (pszPrinter == NULL) {
5987 TRACE("no local printer found\n");
5988 SetLastError(ERROR_FILE_NOT_FOUND);
5989 return FALSE;
5993 /* "pszPrinter" is never empty or NULL here. */
5994 namelen = lstrlenW(pszPrinter);
5995 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5996 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5997 if (!buffer ||
5998 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5999 HeapFree(GetProcessHeap(), 0, buffer);
6000 SetLastError(ERROR_FILE_NOT_FOUND);
6001 return FALSE;
6004 /* read the devices entry for the printer (driver,port) to build the string for the
6005 default device entry (printer,driver,port) */
6006 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
6007 buffer[namelen] = ',';
6008 namelen++; /* move index to the start of the driver */
6010 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
6011 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
6012 if (!lres) {
6013 TRACE("set device to %s\n", debugstr_w(buffer));
6015 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
6016 TRACE("failed to set the device entry: %d\n", GetLastError());
6017 lres = ERROR_INVALID_PRINTER_NAME;
6020 /* remove the next section, when INIFileMapping is implemented */
6022 HKEY hdev;
6023 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
6024 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
6025 RegCloseKey(hdev);
6029 else
6031 if (lres != ERROR_FILE_NOT_FOUND)
6032 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
6034 SetLastError(ERROR_INVALID_PRINTER_NAME);
6037 RegCloseKey(hreg);
6038 HeapFree(GetProcessHeap(), 0, buffer);
6039 return (lres == ERROR_SUCCESS);
6042 /******************************************************************************
6043 * SetDefaultPrinterA (WINSPOOL.202)
6045 * See SetDefaultPrinterW.
6048 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
6050 LPWSTR bufferW = NULL;
6051 BOOL res;
6053 TRACE("(%s)\n", debugstr_a(pszPrinter));
6054 if(pszPrinter) {
6055 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
6056 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6057 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
6059 res = SetDefaultPrinterW(bufferW);
6060 HeapFree(GetProcessHeap(), 0, bufferW);
6061 return res;
6064 /******************************************************************************
6065 * SetPrinterDataExA (WINSPOOL.@)
6067 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6068 LPCSTR pValueName, DWORD Type,
6069 LPBYTE pData, DWORD cbData)
6071 HKEY hkeyPrinter, hkeySubkey;
6072 DWORD ret;
6074 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
6075 debugstr_a(pValueName), Type, pData, cbData);
6077 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6078 != ERROR_SUCCESS)
6079 return ret;
6081 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
6082 != ERROR_SUCCESS) {
6083 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
6084 RegCloseKey(hkeyPrinter);
6085 return ret;
6087 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
6088 RegCloseKey(hkeySubkey);
6089 RegCloseKey(hkeyPrinter);
6090 return ret;
6093 /******************************************************************************
6094 * SetPrinterDataExW (WINSPOOL.@)
6096 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6097 LPCWSTR pValueName, DWORD Type,
6098 LPBYTE pData, DWORD cbData)
6100 HKEY hkeyPrinter, hkeySubkey;
6101 DWORD ret;
6103 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
6104 debugstr_w(pValueName), Type, pData, cbData);
6106 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6107 != ERROR_SUCCESS)
6108 return ret;
6110 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6111 != ERROR_SUCCESS) {
6112 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
6113 RegCloseKey(hkeyPrinter);
6114 return ret;
6116 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
6117 RegCloseKey(hkeySubkey);
6118 RegCloseKey(hkeyPrinter);
6119 return ret;
6122 /******************************************************************************
6123 * SetPrinterDataA (WINSPOOL.@)
6125 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
6126 LPBYTE pData, DWORD cbData)
6128 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
6129 pData, cbData);
6132 /******************************************************************************
6133 * SetPrinterDataW (WINSPOOL.@)
6135 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6136 LPBYTE pData, DWORD cbData)
6138 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6139 pData, cbData);
6142 /******************************************************************************
6143 * GetPrinterDataExA (WINSPOOL.@)
6145 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6146 LPCSTR pValueName, LPDWORD pType,
6147 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6149 opened_printer_t *printer;
6150 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6151 DWORD ret;
6153 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6154 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6156 printer = get_opened_printer(hPrinter);
6157 if(!printer) return ERROR_INVALID_HANDLE;
6159 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6160 if (ret) return ret;
6162 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6164 if (printer->name) {
6166 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6167 if (ret) {
6168 RegCloseKey(hkeyPrinters);
6169 return ret;
6171 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6172 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6173 RegCloseKey(hkeyPrinter);
6174 RegCloseKey(hkeyPrinters);
6175 return ret;
6178 *pcbNeeded = nSize;
6179 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6180 0, pType, pData, pcbNeeded);
6182 if (!ret && !pData) ret = ERROR_MORE_DATA;
6184 RegCloseKey(hkeySubkey);
6185 RegCloseKey(hkeyPrinter);
6186 RegCloseKey(hkeyPrinters);
6188 TRACE("--> %d\n", ret);
6189 return ret;
6192 /******************************************************************************
6193 * GetPrinterDataExW (WINSPOOL.@)
6195 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6196 LPCWSTR pValueName, LPDWORD pType,
6197 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6199 opened_printer_t *printer;
6200 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6201 DWORD ret;
6203 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6204 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6206 printer = get_opened_printer(hPrinter);
6207 if(!printer) return ERROR_INVALID_HANDLE;
6209 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6210 if (ret) return ret;
6212 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6214 if (printer->name) {
6216 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6217 if (ret) {
6218 RegCloseKey(hkeyPrinters);
6219 return ret;
6221 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6222 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6223 RegCloseKey(hkeyPrinter);
6224 RegCloseKey(hkeyPrinters);
6225 return ret;
6228 *pcbNeeded = nSize;
6229 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6230 0, pType, pData, pcbNeeded);
6232 if (!ret && !pData) ret = ERROR_MORE_DATA;
6234 RegCloseKey(hkeySubkey);
6235 RegCloseKey(hkeyPrinter);
6236 RegCloseKey(hkeyPrinters);
6238 TRACE("--> %d\n", ret);
6239 return ret;
6242 /******************************************************************************
6243 * GetPrinterDataA (WINSPOOL.@)
6245 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6246 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6248 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6249 pData, nSize, pcbNeeded);
6252 /******************************************************************************
6253 * GetPrinterDataW (WINSPOOL.@)
6255 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6256 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6258 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6259 pData, nSize, pcbNeeded);
6262 /*******************************************************************************
6263 * EnumPrinterDataExW [WINSPOOL.@]
6265 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6266 LPBYTE pEnumValues, DWORD cbEnumValues,
6267 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6269 HKEY hkPrinter, hkSubKey;
6270 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6271 cbValueNameLen, cbMaxValueLen, cbValueLen,
6272 cbBufSize, dwType;
6273 LPWSTR lpValueName;
6274 HANDLE hHeap;
6275 PBYTE lpValue;
6276 PPRINTER_ENUM_VALUESW ppev;
6278 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6280 if (pKeyName == NULL || *pKeyName == 0)
6281 return ERROR_INVALID_PARAMETER;
6283 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6284 if (ret != ERROR_SUCCESS)
6286 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6287 hPrinter, ret);
6288 return ret;
6291 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6292 if (ret != ERROR_SUCCESS)
6294 r = RegCloseKey (hkPrinter);
6295 if (r != ERROR_SUCCESS)
6296 WARN ("RegCloseKey returned %i\n", r);
6297 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6298 debugstr_w (pKeyName), ret);
6299 return ret;
6302 ret = RegCloseKey (hkPrinter);
6303 if (ret != ERROR_SUCCESS)
6305 ERR ("RegCloseKey returned %i\n", ret);
6306 r = RegCloseKey (hkSubKey);
6307 if (r != ERROR_SUCCESS)
6308 WARN ("RegCloseKey returned %i\n", r);
6309 return ret;
6312 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6313 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6314 if (ret != ERROR_SUCCESS)
6316 r = RegCloseKey (hkSubKey);
6317 if (r != ERROR_SUCCESS)
6318 WARN ("RegCloseKey returned %i\n", r);
6319 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6320 return ret;
6323 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6324 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6326 if (cValues == 0) /* empty key */
6328 r = RegCloseKey (hkSubKey);
6329 if (r != ERROR_SUCCESS)
6330 WARN ("RegCloseKey returned %i\n", r);
6331 *pcbEnumValues = *pnEnumValues = 0;
6332 return ERROR_SUCCESS;
6335 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6337 hHeap = GetProcessHeap ();
6338 if (hHeap == NULL)
6340 ERR ("GetProcessHeap failed\n");
6341 r = RegCloseKey (hkSubKey);
6342 if (r != ERROR_SUCCESS)
6343 WARN ("RegCloseKey returned %i\n", r);
6344 return ERROR_OUTOFMEMORY;
6347 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6348 if (lpValueName == NULL)
6350 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6351 r = RegCloseKey (hkSubKey);
6352 if (r != ERROR_SUCCESS)
6353 WARN ("RegCloseKey returned %i\n", r);
6354 return ERROR_OUTOFMEMORY;
6357 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6358 if (lpValue == NULL)
6360 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6361 if (HeapFree (hHeap, 0, lpValueName) == 0)
6362 WARN ("HeapFree failed with code %i\n", GetLastError ());
6363 r = RegCloseKey (hkSubKey);
6364 if (r != ERROR_SUCCESS)
6365 WARN ("RegCloseKey returned %i\n", r);
6366 return ERROR_OUTOFMEMORY;
6369 TRACE ("pass 1: calculating buffer required for all names and values\n");
6371 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6373 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6375 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6377 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6378 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6379 NULL, NULL, lpValue, &cbValueLen);
6380 if (ret != ERROR_SUCCESS)
6382 if (HeapFree (hHeap, 0, lpValue) == 0)
6383 WARN ("HeapFree failed with code %i\n", GetLastError ());
6384 if (HeapFree (hHeap, 0, lpValueName) == 0)
6385 WARN ("HeapFree failed with code %i\n", GetLastError ());
6386 r = RegCloseKey (hkSubKey);
6387 if (r != ERROR_SUCCESS)
6388 WARN ("RegCloseKey returned %i\n", r);
6389 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6390 return ret;
6393 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6394 debugstr_w (lpValueName), dwIndex,
6395 cbValueNameLen + 1, cbValueLen);
6397 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6398 cbBufSize += cbValueLen;
6401 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6403 *pcbEnumValues = cbBufSize;
6404 *pnEnumValues = cValues;
6406 if (cbEnumValues < cbBufSize) /* buffer too small */
6408 if (HeapFree (hHeap, 0, lpValue) == 0)
6409 WARN ("HeapFree failed with code %i\n", GetLastError ());
6410 if (HeapFree (hHeap, 0, lpValueName) == 0)
6411 WARN ("HeapFree failed with code %i\n", GetLastError ());
6412 r = RegCloseKey (hkSubKey);
6413 if (r != ERROR_SUCCESS)
6414 WARN ("RegCloseKey returned %i\n", r);
6415 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6416 return ERROR_MORE_DATA;
6419 TRACE ("pass 2: copying all names and values to buffer\n");
6421 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6422 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6424 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6426 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6427 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6428 NULL, &dwType, lpValue, &cbValueLen);
6429 if (ret != ERROR_SUCCESS)
6431 if (HeapFree (hHeap, 0, lpValue) == 0)
6432 WARN ("HeapFree failed with code %i\n", GetLastError ());
6433 if (HeapFree (hHeap, 0, lpValueName) == 0)
6434 WARN ("HeapFree failed with code %i\n", GetLastError ());
6435 r = RegCloseKey (hkSubKey);
6436 if (r != ERROR_SUCCESS)
6437 WARN ("RegCloseKey returned %i\n", r);
6438 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6439 return ret;
6442 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6443 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6444 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6445 pEnumValues += cbValueNameLen;
6447 /* return # of *bytes* (including trailing \0), not # of chars */
6448 ppev[dwIndex].cbValueName = cbValueNameLen;
6450 ppev[dwIndex].dwType = dwType;
6452 memcpy (pEnumValues, lpValue, cbValueLen);
6453 ppev[dwIndex].pData = pEnumValues;
6454 pEnumValues += cbValueLen;
6456 ppev[dwIndex].cbData = cbValueLen;
6458 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6459 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6462 if (HeapFree (hHeap, 0, lpValue) == 0)
6464 ret = GetLastError ();
6465 ERR ("HeapFree failed with code %i\n", ret);
6466 if (HeapFree (hHeap, 0, lpValueName) == 0)
6467 WARN ("HeapFree failed with code %i\n", GetLastError ());
6468 r = RegCloseKey (hkSubKey);
6469 if (r != ERROR_SUCCESS)
6470 WARN ("RegCloseKey returned %i\n", r);
6471 return ret;
6474 if (HeapFree (hHeap, 0, lpValueName) == 0)
6476 ret = GetLastError ();
6477 ERR ("HeapFree failed with code %i\n", ret);
6478 r = RegCloseKey (hkSubKey);
6479 if (r != ERROR_SUCCESS)
6480 WARN ("RegCloseKey returned %i\n", r);
6481 return ret;
6484 ret = RegCloseKey (hkSubKey);
6485 if (ret != ERROR_SUCCESS)
6487 ERR ("RegCloseKey returned %i\n", ret);
6488 return ret;
6491 return ERROR_SUCCESS;
6494 /*******************************************************************************
6495 * EnumPrinterDataExA [WINSPOOL.@]
6497 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6498 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6499 * what Windows 2000 SP1 does.
6502 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6503 LPBYTE pEnumValues, DWORD cbEnumValues,
6504 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6506 INT len;
6507 LPWSTR pKeyNameW;
6508 DWORD ret, dwIndex, dwBufSize;
6509 HANDLE hHeap;
6510 LPSTR pBuffer;
6512 TRACE ("%p %s\n", hPrinter, pKeyName);
6514 if (pKeyName == NULL || *pKeyName == 0)
6515 return ERROR_INVALID_PARAMETER;
6517 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6518 if (len == 0)
6520 ret = GetLastError ();
6521 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6522 return ret;
6525 hHeap = GetProcessHeap ();
6526 if (hHeap == NULL)
6528 ERR ("GetProcessHeap failed\n");
6529 return ERROR_OUTOFMEMORY;
6532 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6533 if (pKeyNameW == NULL)
6535 ERR ("Failed to allocate %i bytes from process heap\n",
6536 (LONG)(len * sizeof (WCHAR)));
6537 return ERROR_OUTOFMEMORY;
6540 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6542 ret = GetLastError ();
6543 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6544 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6545 WARN ("HeapFree failed with code %i\n", GetLastError ());
6546 return ret;
6549 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6550 pcbEnumValues, pnEnumValues);
6551 if (ret != ERROR_SUCCESS)
6553 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6554 WARN ("HeapFree failed with code %i\n", GetLastError ());
6555 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6556 return ret;
6559 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6561 ret = GetLastError ();
6562 ERR ("HeapFree failed with code %i\n", ret);
6563 return ret;
6566 if (*pnEnumValues == 0) /* empty key */
6567 return ERROR_SUCCESS;
6569 dwBufSize = 0;
6570 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6572 PPRINTER_ENUM_VALUESW ppev =
6573 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6575 if (dwBufSize < ppev->cbValueName)
6576 dwBufSize = ppev->cbValueName;
6578 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6579 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6580 dwBufSize = ppev->cbData;
6583 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6585 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6586 if (pBuffer == NULL)
6588 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6589 return ERROR_OUTOFMEMORY;
6592 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6594 PPRINTER_ENUM_VALUESW ppev =
6595 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6597 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6598 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6599 NULL);
6600 if (len == 0)
6602 ret = GetLastError ();
6603 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6604 if (HeapFree (hHeap, 0, pBuffer) == 0)
6605 WARN ("HeapFree failed with code %i\n", GetLastError ());
6606 return ret;
6609 memcpy (ppev->pValueName, pBuffer, len);
6611 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6613 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6614 ppev->dwType != REG_MULTI_SZ)
6615 continue;
6617 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6618 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6619 if (len == 0)
6621 ret = GetLastError ();
6622 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6623 if (HeapFree (hHeap, 0, pBuffer) == 0)
6624 WARN ("HeapFree failed with code %i\n", GetLastError ());
6625 return ret;
6628 memcpy (ppev->pData, pBuffer, len);
6630 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6631 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6634 if (HeapFree (hHeap, 0, pBuffer) == 0)
6636 ret = GetLastError ();
6637 ERR ("HeapFree failed with code %i\n", ret);
6638 return ret;
6641 return ERROR_SUCCESS;
6644 /******************************************************************************
6645 * AbortPrinter (WINSPOOL.@)
6647 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6649 FIXME("(%p), stub!\n", hPrinter);
6650 return TRUE;
6653 /******************************************************************************
6654 * AddPortA (WINSPOOL.@)
6656 * See AddPortW.
6659 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6661 LPWSTR nameW = NULL;
6662 LPWSTR monitorW = NULL;
6663 DWORD len;
6664 BOOL res;
6666 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6668 if (pName) {
6669 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6670 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6671 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6674 if (pMonitorName) {
6675 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6676 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6677 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6679 res = AddPortW(nameW, hWnd, monitorW);
6680 HeapFree(GetProcessHeap(), 0, nameW);
6681 HeapFree(GetProcessHeap(), 0, monitorW);
6682 return res;
6685 /******************************************************************************
6686 * AddPortW (WINSPOOL.@)
6688 * Add a Port for a specific Monitor
6690 * PARAMS
6691 * pName [I] Servername or NULL (local Computer)
6692 * hWnd [I] Handle to parent Window for the Dialog-Box
6693 * pMonitorName [I] Name of the Monitor that manage the Port
6695 * RETURNS
6696 * Success: TRUE
6697 * Failure: FALSE
6700 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6702 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6704 if ((backend == NULL) && !load_backend()) return FALSE;
6706 if (!pMonitorName) {
6707 SetLastError(RPC_X_NULL_REF_POINTER);
6708 return FALSE;
6711 return backend->fpAddPort(pName, hWnd, pMonitorName);
6714 /******************************************************************************
6715 * AddPortExA (WINSPOOL.@)
6717 * See AddPortExW.
6720 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6722 PORT_INFO_2W pi2W;
6723 PORT_INFO_2A * pi2A;
6724 LPWSTR nameW = NULL;
6725 LPWSTR monitorW = NULL;
6726 DWORD len;
6727 BOOL res;
6729 pi2A = (PORT_INFO_2A *) pBuffer;
6731 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6732 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6734 if ((level < 1) || (level > 2)) {
6735 SetLastError(ERROR_INVALID_LEVEL);
6736 return FALSE;
6739 if (!pi2A) {
6740 SetLastError(ERROR_INVALID_PARAMETER);
6741 return FALSE;
6744 if (pName) {
6745 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6746 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6747 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6750 if (pMonitorName) {
6751 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6752 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6753 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6756 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6758 if (pi2A->pPortName) {
6759 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6760 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6761 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6764 if (level > 1) {
6765 if (pi2A->pMonitorName) {
6766 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6767 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6768 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6771 if (pi2A->pDescription) {
6772 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6773 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6774 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6776 pi2W.fPortType = pi2A->fPortType;
6777 pi2W.Reserved = pi2A->Reserved;
6780 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6782 HeapFree(GetProcessHeap(), 0, nameW);
6783 HeapFree(GetProcessHeap(), 0, monitorW);
6784 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6785 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6786 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6787 return res;
6791 /******************************************************************************
6792 * AddPortExW (WINSPOOL.@)
6794 * Add a Port for a specific Monitor, without presenting a user interface
6796 * PARAMS
6797 * pName [I] Servername or NULL (local Computer)
6798 * level [I] Structure-Level (1 or 2) for pBuffer
6799 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6800 * pMonitorName [I] Name of the Monitor that manage the Port
6802 * RETURNS
6803 * Success: TRUE
6804 * Failure: FALSE
6807 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6809 PORT_INFO_2W * pi2;
6811 pi2 = (PORT_INFO_2W *) pBuffer;
6813 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6814 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6815 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6816 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6818 if ((backend == NULL) && !load_backend()) return FALSE;
6820 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6821 SetLastError(ERROR_INVALID_PARAMETER);
6822 return FALSE;
6825 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6828 /******************************************************************************
6829 * AddPrinterConnectionA (WINSPOOL.@)
6831 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6833 FIXME("%s\n", debugstr_a(pName));
6834 return FALSE;
6837 /******************************************************************************
6838 * AddPrinterConnectionW (WINSPOOL.@)
6840 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6842 FIXME("%s\n", debugstr_w(pName));
6843 return FALSE;
6846 /******************************************************************************
6847 * AddPrinterDriverExW (WINSPOOL.@)
6849 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6851 * PARAMS
6852 * pName [I] Servername or NULL (local Computer)
6853 * level [I] Level for the supplied DRIVER_INFO_*W struct
6854 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6855 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6857 * RESULTS
6858 * Success: TRUE
6859 * Failure: FALSE
6862 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6864 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6866 if ((backend == NULL) && !load_backend()) return FALSE;
6868 if (level < 2 || level == 5 || level == 7 || level > 8) {
6869 SetLastError(ERROR_INVALID_LEVEL);
6870 return FALSE;
6873 if (!pDriverInfo) {
6874 SetLastError(ERROR_INVALID_PARAMETER);
6875 return FALSE;
6878 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6881 /******************************************************************************
6882 * AddPrinterDriverExA (WINSPOOL.@)
6884 * See AddPrinterDriverExW.
6887 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6889 DRIVER_INFO_8A *diA;
6890 DRIVER_INFO_8W diW;
6891 LPWSTR nameW = NULL;
6892 DWORD lenA;
6893 DWORD len;
6894 BOOL res = FALSE;
6896 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6898 diA = (DRIVER_INFO_8A *) pDriverInfo;
6899 ZeroMemory(&diW, sizeof(diW));
6901 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6902 SetLastError(ERROR_INVALID_LEVEL);
6903 return FALSE;
6906 if (diA == NULL) {
6907 SetLastError(ERROR_INVALID_PARAMETER);
6908 return FALSE;
6911 /* convert servername to unicode */
6912 if (pName) {
6913 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6914 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6915 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6918 /* common fields */
6919 diW.cVersion = diA->cVersion;
6921 if (diA->pName) {
6922 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6923 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6924 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6927 if (diA->pEnvironment) {
6928 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6929 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6930 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6933 if (diA->pDriverPath) {
6934 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6935 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6936 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6939 if (diA->pDataFile) {
6940 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6941 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6942 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6945 if (diA->pConfigFile) {
6946 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6947 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6948 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6951 if ((Level > 2) && diA->pHelpFile) {
6952 len = MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, NULL, 0);
6953 diW.pHelpFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6954 MultiByteToWideChar(CP_ACP, 0, diA->pHelpFile, -1, diW.pHelpFile, len);
6957 if ((Level > 2) && diA->pDependentFiles) {
6958 lenA = multi_sz_lenA(diA->pDependentFiles);
6959 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6960 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6961 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6964 if ((Level > 2) && diA->pMonitorName) {
6965 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6966 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6967 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6970 if ((Level > 2) && diA->pDefaultDataType) {
6971 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6972 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6973 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6976 if ((Level > 3) && diA->pszzPreviousNames) {
6977 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6978 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6979 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6980 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6983 if (Level > 5) {
6984 diW.ftDriverDate = diA->ftDriverDate;
6985 diW.dwlDriverVersion = diA->dwlDriverVersion;
6988 if ((Level > 5) && diA->pszMfgName) {
6989 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6990 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6991 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6994 if ((Level > 5) && diA->pszOEMUrl) {
6995 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6996 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6997 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
7000 if ((Level > 5) && diA->pszHardwareID) {
7001 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
7002 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7003 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
7006 if ((Level > 5) && diA->pszProvider) {
7007 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
7008 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7009 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
7012 if ((Level > 7) && diA->pszPrintProcessor) {
7013 len = MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, NULL, 0);
7014 diW.pszPrintProcessor = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7015 MultiByteToWideChar(CP_ACP, 0, diA->pszPrintProcessor, -1, diW.pszPrintProcessor, len);
7018 if ((Level > 7) && diA->pszVendorSetup) {
7019 len = MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, NULL, 0);
7020 diW.pszVendorSetup = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7021 MultiByteToWideChar(CP_ACP, 0, diA->pszVendorSetup, -1, diW.pszVendorSetup, len);
7024 if ((Level > 7) && diA->pszzColorProfiles) {
7025 lenA = multi_sz_lenA(diA->pszzColorProfiles);
7026 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, NULL, 0);
7027 diW.pszzColorProfiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7028 MultiByteToWideChar(CP_ACP, 0, diA->pszzColorProfiles, lenA, diW.pszzColorProfiles, len);
7031 if ((Level > 7) && diA->pszInfPath) {
7032 len = MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, NULL, 0);
7033 diW.pszInfPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7034 MultiByteToWideChar(CP_ACP, 0, diA->pszInfPath, -1, diW.pszInfPath, len);
7037 if ((Level > 7) && diA->pszzCoreDriverDependencies) {
7038 lenA = multi_sz_lenA(diA->pszzCoreDriverDependencies);
7039 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, NULL, 0);
7040 diW.pszzCoreDriverDependencies = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7041 MultiByteToWideChar(CP_ACP, 0, diA->pszzCoreDriverDependencies, lenA, diW.pszzCoreDriverDependencies, len);
7044 if (Level > 7) {
7045 diW.dwPrinterDriverAttributes = diA->dwPrinterDriverAttributes;
7046 diW.ftMinInboxDriverVerDate = diA->ftMinInboxDriverVerDate;
7047 diW.dwlMinInboxDriverVerVersion = diA->dwlMinInboxDriverVerVersion;
7050 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
7051 TRACE("got %u with %u\n", res, GetLastError());
7052 HeapFree(GetProcessHeap(), 0, nameW);
7053 HeapFree(GetProcessHeap(), 0, diW.pName);
7054 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
7055 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
7056 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
7057 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
7058 HeapFree(GetProcessHeap(), 0, diW.pHelpFile);
7059 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
7060 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
7061 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
7062 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
7063 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
7064 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
7065 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
7066 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
7067 HeapFree(GetProcessHeap(), 0, diW.pszPrintProcessor);
7068 HeapFree(GetProcessHeap(), 0, diW.pszVendorSetup);
7069 HeapFree(GetProcessHeap(), 0, diW.pszzColorProfiles);
7070 HeapFree(GetProcessHeap(), 0, diW.pszInfPath);
7071 HeapFree(GetProcessHeap(), 0, diW.pszzCoreDriverDependencies);
7073 TRACE("=> %u with %u\n", res, GetLastError());
7074 return res;
7077 /******************************************************************************
7078 * ConfigurePortA (WINSPOOL.@)
7080 * See ConfigurePortW.
7083 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
7085 LPWSTR nameW = NULL;
7086 LPWSTR portW = NULL;
7087 INT len;
7088 DWORD res;
7090 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
7092 /* convert servername to unicode */
7093 if (pName) {
7094 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7095 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7096 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7099 /* convert portname to unicode */
7100 if (pPortName) {
7101 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
7102 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7103 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
7106 res = ConfigurePortW(nameW, hWnd, portW);
7107 HeapFree(GetProcessHeap(), 0, nameW);
7108 HeapFree(GetProcessHeap(), 0, portW);
7109 return res;
7112 /******************************************************************************
7113 * ConfigurePortW (WINSPOOL.@)
7115 * Display the Configuration-Dialog for a specific Port
7117 * PARAMS
7118 * pName [I] Servername or NULL (local Computer)
7119 * hWnd [I] Handle to parent Window for the Dialog-Box
7120 * pPortName [I] Name of the Port, that should be configured
7122 * RETURNS
7123 * Success: TRUE
7124 * Failure: FALSE
7127 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
7130 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
7132 if ((backend == NULL) && !load_backend()) return FALSE;
7134 if (!pPortName) {
7135 SetLastError(RPC_X_NULL_REF_POINTER);
7136 return FALSE;
7139 return backend->fpConfigurePort(pName, hWnd, pPortName);
7142 /******************************************************************************
7143 * ConnectToPrinterDlg (WINSPOOL.@)
7145 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
7147 FIXME("%p %x\n", hWnd, Flags);
7148 return NULL;
7151 /******************************************************************************
7152 * DeletePrinterConnectionA (WINSPOOL.@)
7154 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
7156 FIXME("%s\n", debugstr_a(pName));
7157 return TRUE;
7160 /******************************************************************************
7161 * DeletePrinterConnectionW (WINSPOOL.@)
7163 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
7165 FIXME("%s\n", debugstr_w(pName));
7166 return TRUE;
7169 /******************************************************************************
7170 * DeletePrinterDriverExW (WINSPOOL.@)
7172 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7173 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7175 HKEY hkey_drivers;
7176 BOOL ret = FALSE;
7178 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7179 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7181 if(pName && pName[0])
7183 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7184 SetLastError(ERROR_INVALID_PARAMETER);
7185 return FALSE;
7188 if(dwDeleteFlag)
7190 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7191 SetLastError(ERROR_INVALID_PARAMETER);
7192 return FALSE;
7195 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7197 if(!hkey_drivers)
7199 ERR("Can't open drivers key\n");
7200 return FALSE;
7203 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7204 ret = TRUE;
7206 RegCloseKey(hkey_drivers);
7208 return ret;
7211 /******************************************************************************
7212 * DeletePrinterDriverExA (WINSPOOL.@)
7214 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7215 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7217 UNICODE_STRING NameW, EnvW, DriverW;
7218 BOOL ret;
7220 asciitounicode(&NameW, pName);
7221 asciitounicode(&EnvW, pEnvironment);
7222 asciitounicode(&DriverW, pDriverName);
7224 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7226 RtlFreeUnicodeString(&DriverW);
7227 RtlFreeUnicodeString(&EnvW);
7228 RtlFreeUnicodeString(&NameW);
7230 return ret;
7233 /******************************************************************************
7234 * DeletePrinterDataExW (WINSPOOL.@)
7236 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7237 LPCWSTR pValueName)
7239 FIXME("%p %s %s\n", hPrinter,
7240 debugstr_w(pKeyName), debugstr_w(pValueName));
7241 return ERROR_INVALID_PARAMETER;
7244 /******************************************************************************
7245 * DeletePrinterDataExA (WINSPOOL.@)
7247 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7248 LPCSTR pValueName)
7250 FIXME("%p %s %s\n", hPrinter,
7251 debugstr_a(pKeyName), debugstr_a(pValueName));
7252 return ERROR_INVALID_PARAMETER;
7255 /******************************************************************************
7256 * DeletePrintProcessorA (WINSPOOL.@)
7258 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7260 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7261 debugstr_a(pPrintProcessorName));
7262 return TRUE;
7265 /******************************************************************************
7266 * DeletePrintProcessorW (WINSPOOL.@)
7268 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7270 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7271 debugstr_w(pPrintProcessorName));
7272 return TRUE;
7275 /******************************************************************************
7276 * DeletePrintProvidorA (WINSPOOL.@)
7278 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7280 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7281 debugstr_a(pPrintProviderName));
7282 return TRUE;
7285 /******************************************************************************
7286 * DeletePrintProvidorW (WINSPOOL.@)
7288 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7290 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7291 debugstr_w(pPrintProviderName));
7292 return TRUE;
7295 /******************************************************************************
7296 * EnumFormsA (WINSPOOL.@)
7298 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7299 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7301 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7302 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7303 return FALSE;
7306 /******************************************************************************
7307 * EnumFormsW (WINSPOOL.@)
7309 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7310 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7312 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7313 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7314 return FALSE;
7317 /*****************************************************************************
7318 * EnumMonitorsA [WINSPOOL.@]
7320 * See EnumMonitorsW.
7323 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7324 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7326 BOOL res;
7327 LPBYTE bufferW = NULL;
7328 LPWSTR nameW = NULL;
7329 DWORD needed = 0;
7330 DWORD numentries = 0;
7331 INT len;
7333 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7334 cbBuf, pcbNeeded, pcReturned);
7336 /* convert servername to unicode */
7337 if (pName) {
7338 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7339 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7340 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7342 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7343 needed = cbBuf * sizeof(WCHAR);
7344 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7345 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7347 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7348 if (pcbNeeded) needed = *pcbNeeded;
7349 /* HeapReAlloc return NULL, when bufferW was NULL */
7350 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7351 HeapAlloc(GetProcessHeap(), 0, needed);
7353 /* Try again with the large Buffer */
7354 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7356 numentries = pcReturned ? *pcReturned : 0;
7357 needed = 0;
7359 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7360 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7362 if (res) {
7363 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7364 DWORD entrysize = 0;
7365 DWORD index;
7366 LPSTR ptr;
7367 LPMONITOR_INFO_2W mi2w;
7368 LPMONITOR_INFO_2A mi2a;
7370 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7371 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7373 /* First pass: calculate the size for all Entries */
7374 mi2w = (LPMONITOR_INFO_2W) bufferW;
7375 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7376 index = 0;
7377 while (index < numentries) {
7378 index++;
7379 needed += entrysize; /* MONITOR_INFO_?A */
7380 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7382 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7383 NULL, 0, NULL, NULL);
7384 if (Level > 1) {
7385 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7386 NULL, 0, NULL, NULL);
7387 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7388 NULL, 0, NULL, NULL);
7390 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7391 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7392 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7395 /* check for errors and quit on failure */
7396 if (cbBuf < needed) {
7397 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7398 res = FALSE;
7399 goto emA_cleanup;
7401 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7402 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7403 cbBuf -= len ; /* free Bytes in the user-Buffer */
7404 mi2w = (LPMONITOR_INFO_2W) bufferW;
7405 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7406 index = 0;
7407 /* Second Pass: Fill the User Buffer (if we have one) */
7408 while ((index < numentries) && pMonitors) {
7409 index++;
7410 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7411 mi2a->pName = ptr;
7412 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7413 ptr, cbBuf , NULL, NULL);
7414 ptr += len;
7415 cbBuf -= len;
7416 if (Level > 1) {
7417 mi2a->pEnvironment = ptr;
7418 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7419 ptr, cbBuf, NULL, NULL);
7420 ptr += len;
7421 cbBuf -= len;
7423 mi2a->pDLLName = ptr;
7424 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7425 ptr, cbBuf, NULL, NULL);
7426 ptr += len;
7427 cbBuf -= len;
7429 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7430 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7431 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7434 emA_cleanup:
7435 if (pcbNeeded) *pcbNeeded = needed;
7436 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7438 HeapFree(GetProcessHeap(), 0, nameW);
7439 HeapFree(GetProcessHeap(), 0, bufferW);
7441 TRACE("returning %d with %d (%d byte for %d entries)\n",
7442 (res), GetLastError(), needed, numentries);
7444 return (res);
7448 /*****************************************************************************
7449 * EnumMonitorsW [WINSPOOL.@]
7451 * Enumerate available Port-Monitors
7453 * PARAMS
7454 * pName [I] Servername or NULL (local Computer)
7455 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7456 * pMonitors [O] PTR to Buffer that receives the Result
7457 * cbBuf [I] Size of Buffer at pMonitors
7458 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7459 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7461 * RETURNS
7462 * Success: TRUE
7463 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7466 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7467 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7470 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7471 cbBuf, pcbNeeded, pcReturned);
7473 if ((backend == NULL) && !load_backend()) return FALSE;
7475 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7476 SetLastError(RPC_X_NULL_REF_POINTER);
7477 return FALSE;
7480 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7483 /******************************************************************************
7484 * SpoolerInit (WINSPOOL.@)
7486 * Initialize the Spooler
7488 * RETURNS
7489 * Success: TRUE
7490 * Failure: FALSE
7492 * NOTES
7493 * The function fails on windows, when the spooler service is not running
7496 BOOL WINAPI SpoolerInit(void)
7499 if ((backend == NULL) && !load_backend()) return FALSE;
7500 return TRUE;
7503 /******************************************************************************
7504 * XcvDataW (WINSPOOL.@)
7506 * Execute commands in the Printmonitor DLL
7508 * PARAMS
7509 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7510 * pszDataName [i] Name of the command to execute
7511 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7512 * cbInputData [i] Size in Bytes of Buffer at pInputData
7513 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7514 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7515 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7516 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7518 * RETURNS
7519 * Success: TRUE
7520 * Failure: FALSE
7522 * NOTES
7523 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7524 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7526 * Minimal List of commands, that a Printmonitor DLL should support:
7528 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7529 *| "AddPort" : Add a Port
7530 *| "DeletePort": Delete a Port
7532 * Many Printmonitors support additional commands. Examples for localspl.dll:
7533 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7534 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7537 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7538 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7539 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7541 opened_printer_t *printer;
7543 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7544 pInputData, cbInputData, pOutputData,
7545 cbOutputData, pcbOutputNeeded, pdwStatus);
7547 if ((backend == NULL) && !load_backend()) return FALSE;
7549 printer = get_opened_printer(hXcv);
7550 if (!printer || (!printer->backend_printer)) {
7551 SetLastError(ERROR_INVALID_HANDLE);
7552 return FALSE;
7555 if (!pcbOutputNeeded) {
7556 SetLastError(ERROR_INVALID_PARAMETER);
7557 return FALSE;
7560 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7561 SetLastError(RPC_X_NULL_REF_POINTER);
7562 return FALSE;
7565 *pcbOutputNeeded = 0;
7567 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7568 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7572 /*****************************************************************************
7573 * EnumPrinterDataA [WINSPOOL.@]
7576 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7577 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7578 DWORD cbData, LPDWORD pcbData )
7580 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7581 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7582 return ERROR_NO_MORE_ITEMS;
7585 /*****************************************************************************
7586 * EnumPrinterDataW [WINSPOOL.@]
7589 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7590 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7591 DWORD cbData, LPDWORD pcbData )
7593 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7594 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7595 return ERROR_NO_MORE_ITEMS;
7598 /*****************************************************************************
7599 * EnumPrinterKeyA [WINSPOOL.@]
7602 DWORD WINAPI EnumPrinterKeyA(HANDLE printer, const CHAR *key, CHAR *subkey, DWORD size, DWORD *needed)
7604 FIXME("%p %s %p %x %p\n", printer, debugstr_a(key), subkey, size, needed);
7605 return ERROR_CALL_NOT_IMPLEMENTED;
7608 /*****************************************************************************
7609 * EnumPrinterKeyW [WINSPOOL.@]
7612 DWORD WINAPI EnumPrinterKeyW(HANDLE printer, const WCHAR *key, WCHAR *subkey, DWORD size, DWORD *needed)
7614 FIXME("%p %s %p %x %p\n", printer, debugstr_w(key), subkey, size, needed);
7615 return ERROR_CALL_NOT_IMPLEMENTED;
7618 /*****************************************************************************
7619 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7622 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7623 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7624 LPDWORD pcbNeeded, LPDWORD pcReturned)
7626 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7627 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7628 pcbNeeded, pcReturned);
7629 return FALSE;
7632 /*****************************************************************************
7633 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7636 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7637 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7638 LPDWORD pcbNeeded, LPDWORD pcReturned)
7640 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7641 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7642 pcbNeeded, pcReturned);
7643 return FALSE;
7646 /*****************************************************************************
7647 * EnumPrintProcessorsA [WINSPOOL.@]
7649 * See EnumPrintProcessorsW.
7652 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7653 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7655 BOOL res;
7656 LPBYTE bufferW = NULL;
7657 LPWSTR nameW = NULL;
7658 LPWSTR envW = NULL;
7659 DWORD needed = 0;
7660 DWORD numentries = 0;
7661 INT len;
7663 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7664 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7666 /* convert names to unicode */
7667 if (pName) {
7668 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7669 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7670 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7672 if (pEnvironment) {
7673 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7674 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7675 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7678 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7679 needed = cbBuf * sizeof(WCHAR);
7680 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7681 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7683 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7684 if (pcbNeeded) needed = *pcbNeeded;
7685 /* HeapReAlloc return NULL, when bufferW was NULL */
7686 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7687 HeapAlloc(GetProcessHeap(), 0, needed);
7689 /* Try again with the large Buffer */
7690 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7692 numentries = pcReturned ? *pcReturned : 0;
7693 needed = 0;
7695 if (res) {
7696 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7697 DWORD index;
7698 LPSTR ptr;
7699 PPRINTPROCESSOR_INFO_1W ppiw;
7700 PPRINTPROCESSOR_INFO_1A ppia;
7702 /* First pass: calculate the size for all Entries */
7703 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7704 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7705 index = 0;
7706 while (index < numentries) {
7707 index++;
7708 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7709 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7711 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7712 NULL, 0, NULL, NULL);
7714 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7715 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7718 /* check for errors and quit on failure */
7719 if (cbBuf < needed) {
7720 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7721 res = FALSE;
7722 goto epp_cleanup;
7725 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7726 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7727 cbBuf -= len ; /* free Bytes in the user-Buffer */
7728 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7729 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7730 index = 0;
7731 /* Second Pass: Fill the User Buffer (if we have one) */
7732 while ((index < numentries) && pPPInfo) {
7733 index++;
7734 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7735 ppia->pName = ptr;
7736 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7737 ptr, cbBuf , NULL, NULL);
7738 ptr += len;
7739 cbBuf -= len;
7741 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7742 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7746 epp_cleanup:
7747 if (pcbNeeded) *pcbNeeded = needed;
7748 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7750 HeapFree(GetProcessHeap(), 0, nameW);
7751 HeapFree(GetProcessHeap(), 0, envW);
7752 HeapFree(GetProcessHeap(), 0, bufferW);
7754 TRACE("returning %d with %d (%d byte for %d entries)\n",
7755 (res), GetLastError(), needed, numentries);
7757 return (res);
7760 /*****************************************************************************
7761 * EnumPrintProcessorsW [WINSPOOL.@]
7763 * Enumerate available Print Processors
7765 * PARAMS
7766 * pName [I] Servername or NULL (local Computer)
7767 * pEnvironment [I] Printing-Environment or NULL (Default)
7768 * Level [I] Structure-Level (Only 1 is allowed)
7769 * pPPInfo [O] PTR to Buffer that receives the Result
7770 * cbBuf [I] Size of Buffer at pPPInfo
7771 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7772 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7774 * RETURNS
7775 * Success: TRUE
7776 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7779 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7780 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7783 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7784 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7786 if ((backend == NULL) && !load_backend()) return FALSE;
7788 if (!pcbNeeded || !pcReturned) {
7789 SetLastError(RPC_X_NULL_REF_POINTER);
7790 return FALSE;
7793 if (!pPPInfo && (cbBuf > 0)) {
7794 SetLastError(ERROR_INVALID_USER_BUFFER);
7795 return FALSE;
7798 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7799 cbBuf, pcbNeeded, pcReturned);
7802 /*****************************************************************************
7803 * ExtDeviceMode [WINSPOOL.@]
7806 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7807 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7808 DWORD fMode)
7810 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7811 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7812 debugstr_a(pProfile), fMode);
7813 return -1;
7816 /*****************************************************************************
7817 * FindClosePrinterChangeNotification [WINSPOOL.@]
7820 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7822 FIXME("Stub: %p\n", hChange);
7823 return TRUE;
7826 /*****************************************************************************
7827 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7830 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7831 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7833 FIXME("Stub: %p %x %x %p\n",
7834 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7835 return INVALID_HANDLE_VALUE;
7838 /*****************************************************************************
7839 * FindNextPrinterChangeNotification [WINSPOOL.@]
7842 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7843 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7845 FIXME("Stub: %p %p %p %p\n",
7846 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7847 return FALSE;
7850 /*****************************************************************************
7851 * FreePrinterNotifyInfo [WINSPOOL.@]
7854 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7856 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7857 return TRUE;
7860 /*****************************************************************************
7861 * string_to_buf
7863 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7864 * ansi depending on the unicode parameter.
7866 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7868 if(!str)
7870 *size = 0;
7871 return TRUE;
7874 if(unicode)
7876 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7877 if(*size <= cb)
7879 memcpy(ptr, str, *size);
7880 return TRUE;
7882 return FALSE;
7884 else
7886 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7887 if(*size <= cb)
7889 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7890 return TRUE;
7892 return FALSE;
7896 /*****************************************************************************
7897 * get_job_info_1
7899 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7900 LPDWORD pcbNeeded, BOOL unicode)
7902 DWORD size, left = cbBuf;
7903 BOOL space = (cbBuf > 0);
7904 LPBYTE ptr = buf;
7906 *pcbNeeded = 0;
7908 if(space)
7910 ji1->JobId = job->job_id;
7913 string_to_buf(job->document_title, ptr, left, &size, unicode);
7914 if(space && size <= left)
7916 ji1->pDocument = (LPWSTR)ptr;
7917 ptr += size;
7918 left -= size;
7920 else
7921 space = FALSE;
7922 *pcbNeeded += size;
7924 if (job->printer_name)
7926 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7927 if(space && size <= left)
7929 ji1->pPrinterName = (LPWSTR)ptr;
7930 ptr += size;
7931 left -= size;
7933 else
7934 space = FALSE;
7935 *pcbNeeded += size;
7938 return space;
7941 /*****************************************************************************
7942 * get_job_info_2
7944 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7945 LPDWORD pcbNeeded, BOOL unicode)
7947 DWORD size, left = cbBuf;
7948 DWORD shift;
7949 BOOL space = (cbBuf > 0);
7950 LPBYTE ptr = buf;
7951 LPDEVMODEA dmA = NULL;
7952 LPDEVMODEW devmode;
7954 *pcbNeeded = 0;
7956 if(space)
7958 ji2->JobId = job->job_id;
7961 string_to_buf(job->document_title, ptr, left, &size, unicode);
7962 if(space && size <= left)
7964 ji2->pDocument = (LPWSTR)ptr;
7965 ptr += size;
7966 left -= size;
7968 else
7969 space = FALSE;
7970 *pcbNeeded += size;
7972 if (job->printer_name)
7974 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7975 if(space && size <= left)
7977 ji2->pPrinterName = (LPWSTR)ptr;
7978 ptr += size;
7979 left -= size;
7981 else
7982 space = FALSE;
7983 *pcbNeeded += size;
7986 if (job->devmode)
7988 if (!unicode)
7990 dmA = DEVMODEdupWtoA(job->devmode);
7991 devmode = (LPDEVMODEW) dmA;
7992 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7994 else
7996 devmode = job->devmode;
7997 size = devmode->dmSize + devmode->dmDriverExtra;
8000 if (!devmode)
8001 FIXME("Can't convert DEVMODE W to A\n");
8002 else
8004 /* align DEVMODE to a DWORD boundary */
8005 shift = (4 - (*pcbNeeded & 3)) & 3;
8006 size += shift;
8008 if (size <= left)
8010 ptr += shift;
8011 memcpy(ptr, devmode, size-shift);
8012 ji2->pDevMode = (LPDEVMODEW)ptr;
8013 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
8014 ptr += size-shift;
8015 left -= size;
8017 else
8018 space = FALSE;
8019 *pcbNeeded +=size;
8023 return space;
8026 /*****************************************************************************
8027 * get_job_info
8029 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8030 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
8032 BOOL ret = FALSE;
8033 DWORD needed = 0, size;
8034 job_t *job;
8035 LPBYTE ptr = pJob;
8037 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
8039 EnterCriticalSection(&printer_handles_cs);
8040 job = get_job(hPrinter, JobId);
8041 if(!job)
8042 goto end;
8044 switch(Level)
8046 case 1:
8047 size = sizeof(JOB_INFO_1W);
8048 if(cbBuf >= size)
8050 cbBuf -= size;
8051 ptr += size;
8052 memset(pJob, 0, size);
8054 else
8055 cbBuf = 0;
8056 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
8057 needed += size;
8058 break;
8060 case 2:
8061 size = sizeof(JOB_INFO_2W);
8062 if(cbBuf >= size)
8064 cbBuf -= size;
8065 ptr += size;
8066 memset(pJob, 0, size);
8068 else
8069 cbBuf = 0;
8070 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
8071 needed += size;
8072 break;
8074 case 3:
8075 size = sizeof(JOB_INFO_3);
8076 if(cbBuf >= size)
8078 cbBuf -= size;
8079 memset(pJob, 0, size);
8080 ret = TRUE;
8082 else
8083 cbBuf = 0;
8084 needed = size;
8085 break;
8087 default:
8088 SetLastError(ERROR_INVALID_LEVEL);
8089 goto end;
8091 if(pcbNeeded)
8092 *pcbNeeded = needed;
8093 end:
8094 LeaveCriticalSection(&printer_handles_cs);
8095 return ret;
8098 /*****************************************************************************
8099 * GetJobA [WINSPOOL.@]
8102 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8103 DWORD cbBuf, LPDWORD pcbNeeded)
8105 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
8108 /*****************************************************************************
8109 * GetJobW [WINSPOOL.@]
8112 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
8113 DWORD cbBuf, LPDWORD pcbNeeded)
8115 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
8118 /*****************************************************************************
8119 * schedule_pipe
8121 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
8123 #ifdef HAVE_FORK
8124 char *unixname, *cmdA;
8125 DWORD len;
8126 int fds[2] = {-1, -1}, file_fd = -1, no_read;
8127 BOOL ret = FALSE;
8128 char buf[1024];
8129 pid_t pid, wret;
8130 int status;
8132 if(!(unixname = wine_get_unix_file_name(filename)))
8133 return FALSE;
8135 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
8136 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
8137 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
8139 TRACE("printing with: %s\n", cmdA);
8141 if((file_fd = open(unixname, O_RDONLY)) == -1)
8142 goto end;
8144 if (pipe(fds))
8146 ERR("pipe() failed!\n");
8147 goto end;
8150 if ((pid = fork()) == 0)
8152 close(0);
8153 dup2(fds[0], 0);
8154 close(fds[1]);
8156 /* reset signals that we previously set to SIG_IGN */
8157 signal(SIGPIPE, SIG_DFL);
8159 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
8160 _exit(1);
8162 else if (pid == -1)
8164 ERR("fork() failed!\n");
8165 goto end;
8168 close(fds[0]);
8169 fds[0] = -1;
8170 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
8171 write(fds[1], buf, no_read);
8173 close(fds[1]);
8174 fds[1] = -1;
8176 /* reap child */
8177 do {
8178 wret = waitpid(pid, &status, 0);
8179 } while (wret < 0 && errno == EINTR);
8180 if (wret < 0)
8182 ERR("waitpid() failed!\n");
8183 goto end;
8185 if (!WIFEXITED(status) || WEXITSTATUS(status))
8187 ERR("child process failed! %d\n", status);
8188 goto end;
8191 ret = TRUE;
8193 end:
8194 if(file_fd != -1) close(file_fd);
8195 if(fds[0] != -1) close(fds[0]);
8196 if(fds[1] != -1) close(fds[1]);
8198 HeapFree(GetProcessHeap(), 0, cmdA);
8199 HeapFree(GetProcessHeap(), 0, unixname);
8200 return ret;
8201 #else
8202 return FALSE;
8203 #endif
8206 /*****************************************************************************
8207 * schedule_lpr
8209 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8211 WCHAR *cmd;
8212 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8213 BOOL r;
8215 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8216 sprintfW(cmd, fmtW, printer_name);
8218 r = schedule_pipe(cmd, filename);
8220 HeapFree(GetProcessHeap(), 0, cmd);
8221 return r;
8224 #ifdef SONAME_LIBCUPS
8225 /*****************************************************************************
8226 * get_cups_jobs_ticket_options
8228 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8229 * The CUPS scheduler only looks for these in Print-File requests, and since
8230 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8231 * parsed.
8233 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8235 FILE *fp = fopen( file, "r" );
8236 char buf[257]; /* DSC max of 256 + '\0' */
8237 const char *ps_adobe = "%!PS-Adobe-";
8238 const char *cups_job = "%cupsJobTicket:";
8240 if (!fp) return num_options;
8241 if (!fgets( buf, sizeof(buf), fp )) goto end;
8242 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8243 while (fgets( buf, sizeof(buf), fp ))
8245 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8246 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8249 end:
8250 fclose( fp );
8251 return num_options;
8254 static int get_cups_default_options( const char *printer, int num_options, cups_option_t **options )
8256 cups_dest_t *dest;
8257 int i;
8259 if (!pcupsGetNamedDest) return num_options;
8261 dest = pcupsGetNamedDest( NULL, printer, NULL );
8262 if (!dest) return num_options;
8264 for (i = 0; i < dest->num_options; i++)
8266 if (!pcupsGetOption( dest->options[i].name, num_options, *options ))
8267 num_options = pcupsAddOption( dest->options[i].name, dest->options[i].value,
8268 num_options, options );
8271 pcupsFreeDests( 1, dest );
8272 return num_options;
8274 #endif
8276 /*****************************************************************************
8277 * schedule_cups
8279 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8281 #ifdef SONAME_LIBCUPS
8282 if(pcupsPrintFile)
8284 char *unixname, *queue, *unix_doc_title;
8285 DWORD len;
8286 BOOL ret;
8287 int num_options = 0, i;
8288 cups_option_t *options = NULL;
8290 if(!(unixname = wine_get_unix_file_name(filename)))
8291 return FALSE;
8293 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8294 queue = HeapAlloc(GetProcessHeap(), 0, len);
8295 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8297 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8298 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8299 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8301 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8302 num_options = get_cups_default_options( queue, num_options, &options );
8304 TRACE( "printing via cups with options:\n" );
8305 for (i = 0; i < num_options; i++)
8306 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8308 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8309 if (ret == 0 && pcupsLastErrorString)
8310 WARN("cupsPrintFile failed with error %s\n", debugstr_a(pcupsLastErrorString()));
8312 pcupsFreeOptions( num_options, options );
8314 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8315 HeapFree(GetProcessHeap(), 0, queue);
8316 HeapFree(GetProcessHeap(), 0, unixname);
8317 return ret;
8319 else
8320 #endif
8322 return schedule_lpr(printer_name, filename);
8326 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8328 LPWSTR filename;
8330 switch(msg)
8332 case WM_INITDIALOG:
8333 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8334 return TRUE;
8336 case WM_COMMAND:
8337 if(HIWORD(wparam) == BN_CLICKED)
8339 if(LOWORD(wparam) == IDOK)
8341 HANDLE hf;
8342 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8343 LPWSTR *output;
8345 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8346 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8348 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8350 WCHAR caption[200], message[200];
8351 int mb_ret;
8353 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8354 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8355 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8356 if(mb_ret == IDCANCEL)
8358 HeapFree(GetProcessHeap(), 0, filename);
8359 return TRUE;
8362 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8363 if(hf == INVALID_HANDLE_VALUE)
8365 WCHAR caption[200], message[200];
8367 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8368 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8369 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8370 HeapFree(GetProcessHeap(), 0, filename);
8371 return TRUE;
8373 CloseHandle(hf);
8374 DeleteFileW(filename);
8375 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8376 *output = filename;
8377 EndDialog(hwnd, IDOK);
8378 return TRUE;
8380 if(LOWORD(wparam) == IDCANCEL)
8382 EndDialog(hwnd, IDCANCEL);
8383 return TRUE;
8386 return FALSE;
8388 return FALSE;
8391 /*****************************************************************************
8392 * get_filename
8394 static BOOL get_filename(LPWSTR *filename)
8396 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8397 file_dlg_proc, (LPARAM)filename) == IDOK;
8400 /*****************************************************************************
8401 * schedule_file
8403 static BOOL schedule_file(LPCWSTR filename)
8405 LPWSTR output = NULL;
8407 if(get_filename(&output))
8409 BOOL r;
8410 TRACE("copy to %s\n", debugstr_w(output));
8411 r = CopyFileW(filename, output, FALSE);
8412 HeapFree(GetProcessHeap(), 0, output);
8413 return r;
8415 return FALSE;
8418 /*****************************************************************************
8419 * schedule_unixfile
8421 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8423 int in_fd, out_fd, no_read;
8424 char buf[1024];
8425 BOOL ret = FALSE;
8426 char *unixname, *outputA;
8427 DWORD len;
8429 if(!(unixname = wine_get_unix_file_name(filename)))
8430 return FALSE;
8432 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8433 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8434 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8436 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8437 in_fd = open(unixname, O_RDONLY);
8438 if(out_fd == -1 || in_fd == -1)
8439 goto end;
8441 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8442 write(out_fd, buf, no_read);
8444 ret = TRUE;
8445 end:
8446 if(in_fd != -1) close(in_fd);
8447 if(out_fd != -1) close(out_fd);
8448 HeapFree(GetProcessHeap(), 0, outputA);
8449 HeapFree(GetProcessHeap(), 0, unixname);
8450 return ret;
8453 /*****************************************************************************
8454 * ScheduleJob [WINSPOOL.@]
8457 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8459 opened_printer_t *printer;
8460 BOOL ret = FALSE;
8461 struct list *cursor, *cursor2;
8463 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8464 EnterCriticalSection(&printer_handles_cs);
8465 printer = get_opened_printer(hPrinter);
8466 if(!printer)
8467 goto end;
8469 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8471 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8472 HANDLE hf;
8474 if(job->job_id != dwJobID) continue;
8476 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8477 if(hf != INVALID_HANDLE_VALUE)
8479 PRINTER_INFO_5W *pi5 = NULL;
8480 LPWSTR portname = job->portname;
8481 DWORD needed;
8482 HKEY hkey;
8483 WCHAR output[1024];
8484 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8485 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8487 if (!portname)
8489 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8490 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8491 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8492 portname = pi5->pPortName;
8494 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8495 debugstr_w(portname));
8497 output[0] = 0;
8499 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8500 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8502 DWORD type, count = sizeof(output);
8503 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8504 RegCloseKey(hkey);
8506 if(output[0] == '|')
8508 ret = schedule_pipe(output + 1, job->filename);
8510 else if(output[0])
8512 ret = schedule_unixfile(output, job->filename);
8514 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8516 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8518 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8520 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8522 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8524 ret = schedule_file(job->filename);
8526 else if(isalpha(portname[0]) && portname[1] == ':')
8528 TRACE("copying to %s\n", debugstr_w(portname));
8529 ret = CopyFileW(job->filename, portname, FALSE);
8531 else
8533 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8535 HeapFree(GetProcessHeap(), 0, pi5);
8536 CloseHandle(hf);
8537 DeleteFileW(job->filename);
8539 list_remove(cursor);
8540 HeapFree(GetProcessHeap(), 0, job->document_title);
8541 HeapFree(GetProcessHeap(), 0, job->printer_name);
8542 HeapFree(GetProcessHeap(), 0, job->portname);
8543 HeapFree(GetProcessHeap(), 0, job->filename);
8544 HeapFree(GetProcessHeap(), 0, job->devmode);
8545 HeapFree(GetProcessHeap(), 0, job);
8546 break;
8548 end:
8549 LeaveCriticalSection(&printer_handles_cs);
8550 return ret;
8553 /*****************************************************************************
8554 * StartDocDlgA [WINSPOOL.@]
8556 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8558 UNICODE_STRING usBuffer;
8559 DOCINFOW docW = { 0 };
8560 LPWSTR retW;
8561 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8562 LPSTR ret = NULL;
8564 docW.cbSize = sizeof(docW);
8565 if (doc->lpszDocName)
8567 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8568 if (!(docW.lpszDocName = docnameW)) goto failed;
8570 if (doc->lpszOutput)
8572 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8573 if (!(docW.lpszOutput = outputW)) goto failed;
8575 if (doc->lpszDatatype)
8577 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8578 if (!(docW.lpszDatatype = datatypeW)) goto failed;
8580 docW.fwType = doc->fwType;
8582 retW = StartDocDlgW(hPrinter, &docW);
8584 if(retW)
8586 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8587 ret = HeapAlloc(GetProcessHeap(), 0, len);
8588 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8589 HeapFree(GetProcessHeap(), 0, retW);
8592 failed:
8593 HeapFree(GetProcessHeap(), 0, datatypeW);
8594 HeapFree(GetProcessHeap(), 0, outputW);
8595 HeapFree(GetProcessHeap(), 0, docnameW);
8597 return ret;
8600 /*****************************************************************************
8601 * StartDocDlgW [WINSPOOL.@]
8603 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8604 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8605 * port is "FILE:". Also returns the full path if passed a relative path.
8607 * The caller should free the returned string from the process heap.
8609 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8611 LPWSTR ret = NULL;
8612 DWORD len, attr;
8614 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8616 PRINTER_INFO_5W *pi5;
8617 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8618 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8619 return NULL;
8620 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8621 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8622 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8624 HeapFree(GetProcessHeap(), 0, pi5);
8625 return NULL;
8627 HeapFree(GetProcessHeap(), 0, pi5);
8630 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8632 LPWSTR name;
8634 if (get_filename(&name))
8636 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8638 HeapFree(GetProcessHeap(), 0, name);
8639 return NULL;
8641 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8642 GetFullPathNameW(name, len, ret, NULL);
8643 HeapFree(GetProcessHeap(), 0, name);
8645 return ret;
8648 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8649 return NULL;
8651 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8652 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8654 attr = GetFileAttributesW(ret);
8655 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8657 HeapFree(GetProcessHeap(), 0, ret);
8658 ret = NULL;
8660 return ret;
8663 /*****************************************************************************
8664 * UploadPrinterDriverPackageA [WINSPOOL.@]
8666 HRESULT WINAPI UploadPrinterDriverPackageA( LPCSTR server, LPCSTR path, LPCSTR env,
8667 DWORD flags, HWND hwnd, LPSTR dst, PULONG dstlen )
8669 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server), debugstr_a(path), debugstr_a(env),
8670 flags, hwnd, dst, dstlen);
8671 return E_NOTIMPL;
8674 /*****************************************************************************
8675 * UploadPrinterDriverPackageW [WINSPOOL.@]
8677 HRESULT WINAPI UploadPrinterDriverPackageW( LPCWSTR server, LPCWSTR path, LPCWSTR env,
8678 DWORD flags, HWND hwnd, LPWSTR dst, PULONG dstlen )
8680 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server), debugstr_w(path), debugstr_w(env),
8681 flags, hwnd, dst, dstlen);
8682 return E_NOTIMPL;