msvcp90: Added _Stofx implementation.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blobd1afe56df4d6be16e6ddf2fdf288e902232c7d0b
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
48 #define NONAMELESSUNION
49 #define NONAMELESSSTRUCT
50 #include "wine/library.h"
51 #include "windef.h"
52 #include "winbase.h"
53 #include "winuser.h"
54 #include "winerror.h"
55 #include "winreg.h"
56 #include "wingdi.h"
57 #include "winspool.h"
58 #include "winternl.h"
59 #include "wine/windef16.h"
60 #include "wine/unicode.h"
61 #include "wine/debug.h"
62 #include "wine/list.h"
63 #include "winnls.h"
65 #include "ddk/winsplp.h"
66 #include "wspool.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
70 /* ############################### */
72 static CRITICAL_SECTION printer_handles_cs;
73 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
75 0, 0, &printer_handles_cs,
76 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
77 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
79 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
81 /* ############################### */
83 typedef struct {
84 DWORD job_id;
85 HANDLE hf;
86 } started_doc_t;
88 typedef struct {
89 struct list jobs;
90 LONG ref;
91 } jobqueue_t;
93 typedef struct {
94 LPWSTR name;
95 LPWSTR printername;
96 HANDLE backend_printer;
97 jobqueue_t *queue;
98 started_doc_t *doc;
99 DEVMODEW *devmode;
100 } opened_printer_t;
102 typedef struct {
103 struct list entry;
104 DWORD job_id;
105 WCHAR *filename;
106 WCHAR *portname;
107 WCHAR *document_title;
108 WCHAR *printer_name;
109 LPDEVMODEW devmode;
110 } job_t;
113 typedef struct {
114 LPCWSTR envname;
115 LPCWSTR subdir;
116 DWORD driverversion;
117 LPCWSTR versionregpath;
118 LPCWSTR versionsubdir;
119 } printenv_t;
121 /* ############################### */
123 static opened_printer_t **printer_handles;
124 static UINT nb_printer_handles;
125 static LONG next_job_id = 1;
127 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
128 WORD fwCapability, LPSTR lpszOutput,
129 LPDEVMODEA lpdm );
130 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
131 LPSTR lpszDevice, LPSTR lpszPort,
132 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
133 DWORD fwMode );
135 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
136 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
137 'c','o','n','t','r','o','l','\\',
138 'P','r','i','n','t','\\',
139 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
140 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
142 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
143 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
144 'C','o','n','t','r','o','l','\\',
145 'P','r','i','n','t','\\',
146 'P','r','i','n','t','e','r','s',0};
148 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
150 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
151 'M','i','c','r','o','s','o','f','t','\\',
152 'W','i','n','d','o','w','s',' ','N','T','\\',
153 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
154 'W','i','n','d','o','w','s',0};
156 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
157 'M','i','c','r','o','s','o','f','t','\\',
158 'W','i','n','d','o','w','s',' ','N','T','\\',
159 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
160 'D','e','v','i','c','e','s',0};
162 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
163 'M','i','c','r','o','s','o','f','t','\\',
164 'W','i','n','d','o','w','s',' ','N','T','\\',
165 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
166 'P','o','r','t','s',0};
168 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
169 'M','i','c','r','o','s','o','f','t','\\',
170 'W','i','n','d','o','w','s',' ','N','T','\\',
171 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
172 'P','r','i','n','t','e','r','P','o','r','t','s',0};
174 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
175 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
176 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
177 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
178 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
179 static const WCHAR subdir_x64W[] = {'x','6','4',0};
180 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
181 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
182 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
183 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
184 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
186 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
188 static const WCHAR AttributesW[] = {'A','t','t','r','i','b','u','t','e','s',0};
189 static const WCHAR backslashW[] = {'\\',0};
190 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
191 'i','o','n',' ','F','i','l','e',0};
192 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
193 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
194 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
195 static const WCHAR Default_PriorityW[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
196 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
197 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
198 static const WCHAR dnsTimeoutW[] = {'d','n','s','T','i','m','e','o','u','t',0};
199 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
200 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
201 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
202 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
203 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
204 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
205 static const WCHAR NameW[] = {'N','a','m','e',0};
206 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
207 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
208 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
209 static const WCHAR PortW[] = {'P','o','r','t',0};
210 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
211 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
212 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
213 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
214 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
215 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
216 static const WCHAR PriorityW[] = {'P','r','i','o','r','i','t','y',0};
217 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
218 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
219 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
220 static const WCHAR StartTimeW[] = {'S','t','a','r','t','T','i','m','e',0};
221 static const WCHAR StatusW[] = {'S','t','a','t','u','s',0};
222 static const WCHAR txTimeoutW[] = {'t','x','T','i','m','e','o','u','t',0};
223 static const WCHAR UntilTimeW[] = {'U','n','t','i','l','T','i','m','e',0};
224 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
225 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
226 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
227 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
228 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
229 static WCHAR rawW[] = {'R','A','W',0};
230 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
231 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
232 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
233 static const WCHAR commaW[] = {',',0};
234 static WCHAR emptyStringW[] = {0};
236 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
238 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
239 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
240 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
242 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
243 'D','o','c','u','m','e','n','t',0};
245 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
246 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
247 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
248 0, sizeof(DRIVER_INFO_8W)};
251 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
252 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
253 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
254 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
255 sizeof(PRINTER_INFO_9W)};
257 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
258 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
259 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
261 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
263 /******************************************************************
264 * validate the user-supplied printing-environment [internal]
266 * PARAMS
267 * env [I] PTR to Environment-String or NULL
269 * RETURNS
270 * Failure: NULL
271 * Success: PTR to printenv_t
273 * NOTES
274 * An empty string is handled the same way as NULL.
275 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
279 static const printenv_t * validate_envW(LPCWSTR env)
281 const printenv_t *result = NULL;
282 unsigned int i;
284 TRACE("testing %s\n", debugstr_w(env));
285 if (env && env[0])
287 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
289 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
291 result = all_printenv[i];
292 break;
296 if (result == NULL) {
297 FIXME("unsupported Environment: %s\n", debugstr_w(env));
298 SetLastError(ERROR_INVALID_ENVIRONMENT);
300 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
302 else
304 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
306 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
308 return result;
312 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
313 if passed a NULL string. This returns NULLs to the result.
315 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
317 if ( (src) )
319 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
320 return usBufferPtr->Buffer;
322 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
323 return NULL;
326 static LPWSTR strdupW(LPCWSTR p)
328 LPWSTR ret;
329 DWORD len;
331 if(!p) return NULL;
332 len = (strlenW(p) + 1) * sizeof(WCHAR);
333 ret = HeapAlloc(GetProcessHeap(), 0, len);
334 memcpy(ret, p, len);
335 return ret;
338 static LPSTR strdupWtoA( LPCWSTR str )
340 LPSTR ret;
341 INT len;
343 if (!str) return NULL;
344 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
345 ret = HeapAlloc( GetProcessHeap(), 0, len );
346 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
347 return ret;
350 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
352 DEVMODEW *ret;
354 if (!dm) return NULL;
355 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
356 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
357 return ret;
360 /***********************************************************
361 * DEVMODEdupWtoA
362 * Creates an ansi copy of supplied devmode
364 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
366 LPDEVMODEA dmA;
367 DWORD size;
369 if (!dmW) return NULL;
370 size = dmW->dmSize - CCHDEVICENAME -
371 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
373 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
374 if (!dmA) return NULL;
376 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
377 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
379 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
381 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
382 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
384 else
386 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
387 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
388 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
389 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
391 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
394 dmA->dmSize = size;
395 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
396 return dmA;
400 /******************************************************************
401 * verify, that the filename is a local file
404 static inline BOOL is_local_file(LPWSTR name)
406 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
409 /* ################################ */
411 static int multi_sz_lenA(const char *str)
413 const char *ptr = str;
414 if(!str) return 0;
417 ptr += lstrlenA(ptr) + 1;
418 } while(*ptr);
420 return ptr - str + 1;
423 /*****************************************************************************
424 * get_dword_from_reg
426 * Return DWORD associated with name from hkey.
428 static DWORD get_dword_from_reg( HKEY hkey, const WCHAR *name )
430 DWORD sz = sizeof(DWORD), type, value = 0;
431 LONG ret;
433 ret = RegQueryValueExW( hkey, name, 0, &type, (LPBYTE)&value, &sz );
435 if (ret != ERROR_SUCCESS)
437 WARN( "Got ret = %d on name %s\n", ret, debugstr_w(name) );
438 return 0;
440 if (type != REG_DWORD)
442 ERR( "Got type %d\n", type );
443 return 0;
445 return value;
448 static inline DWORD set_reg_DWORD( HKEY hkey, const WCHAR *keyname, const DWORD value )
450 return RegSetValueExW( hkey, keyname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value) );
453 /******************************************************************
454 * get_opened_printer
455 * Get the pointer to the opened printer referred by the handle
457 static opened_printer_t *get_opened_printer(HANDLE hprn)
459 UINT_PTR idx = (UINT_PTR)hprn;
460 opened_printer_t *ret = NULL;
462 EnterCriticalSection(&printer_handles_cs);
464 if ((idx > 0) && (idx <= nb_printer_handles)) {
465 ret = printer_handles[idx - 1];
467 LeaveCriticalSection(&printer_handles_cs);
468 return ret;
471 /******************************************************************
472 * get_opened_printer_name
473 * Get the pointer to the opened printer name referred by the handle
475 static LPCWSTR get_opened_printer_name(HANDLE hprn)
477 opened_printer_t *printer = get_opened_printer(hprn);
478 if(!printer) return NULL;
479 return printer->name;
482 static DWORD open_printer_reg_key( const WCHAR *name, HKEY *key )
484 HKEY printers;
485 DWORD err;
487 *key = NULL;
488 err = RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers );
489 if (err) return err;
491 err = RegOpenKeyW( printers, name, key );
492 if (err) err = ERROR_INVALID_PRINTER_NAME;
493 RegCloseKey( printers );
494 return err;
497 /******************************************************************
498 * WINSPOOL_GetOpenedPrinterRegKey
501 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
503 LPCWSTR name = get_opened_printer_name(hPrinter);
505 if(!name) return ERROR_INVALID_HANDLE;
506 return open_printer_reg_key( name, phkey );
509 static void
510 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
511 char qbuf[200];
513 /* If forcing, or no profile string entry for device yet, set the entry
515 * The always change entry if not WINEPS yet is discussable.
517 if (force ||
518 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
519 !strcmp(qbuf,"*") ||
520 !strstr(qbuf,"WINEPS.DRV")
522 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
523 HKEY hkey;
525 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
526 WriteProfileStringA("windows","device",buf);
527 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
528 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
529 RegCloseKey(hkey);
531 HeapFree(GetProcessHeap(),0,buf);
535 static BOOL add_printer_driver(const WCHAR *name, WCHAR *ppd)
537 DRIVER_INFO_3W di3;
539 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
540 di3.cVersion = 3;
541 di3.pName = (WCHAR*)name;
542 di3.pEnvironment = envname_x86W;
543 di3.pDriverPath = driver_nt;
544 di3.pDataFile = ppd;
545 di3.pConfigFile = driver_nt;
546 di3.pDefaultDataType = rawW;
548 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
549 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
551 di3.cVersion = 0;
552 di3.pEnvironment = envname_win40W;
553 di3.pDriverPath = driver_9x;
554 di3.pConfigFile = driver_9x;
555 if (AddPrinterDriverExW( NULL, 3, (LPBYTE)&di3, APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY ) ||
556 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
558 return TRUE;
561 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
562 return FALSE;
565 static inline char *expand_env_string( char *str, DWORD type )
567 if (type == REG_EXPAND_SZ)
569 char *tmp;
570 DWORD needed = ExpandEnvironmentStringsA( str, NULL, 0 );
571 tmp = HeapAlloc( GetProcessHeap(), 0, needed );
572 if (tmp)
574 ExpandEnvironmentStringsA( str, tmp, needed );
575 HeapFree( GetProcessHeap(), 0, str );
576 return tmp;
579 return str;
582 static char *get_fallback_ppd_name( const char *printer_name )
584 static const WCHAR ppds_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
585 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
586 HKEY hkey;
587 DWORD needed, type;
588 char *ret = NULL;
589 const char *data_dir, *filename;
591 if (RegOpenKeyW( HKEY_CURRENT_USER, ppds_key, &hkey ) == ERROR_SUCCESS )
593 const char *value_name = NULL;
595 if (RegQueryValueExA( hkey, printer_name, 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
596 value_name = printer_name;
597 else if (RegQueryValueExA( hkey, "generic", 0, NULL, NULL, &needed ) == ERROR_SUCCESS)
598 value_name = "generic";
600 if (value_name)
602 ret = HeapAlloc( GetProcessHeap(), 0, needed );
603 if (!ret) return NULL;
604 RegQueryValueExA( hkey, value_name, 0, &type, (BYTE *)ret, &needed );
606 RegCloseKey( hkey );
607 if (ret) return expand_env_string( ret, type );
610 if ((data_dir = wine_get_data_dir())) filename = "/generic.ppd";
611 else if ((data_dir = wine_get_build_dir())) filename = "/dlls/wineps.drv/generic.ppd";
612 else
614 ERR( "Error getting PPD file name for printer '%s'\n", debugstr_a(printer_name) );
615 return NULL;
617 ret = HeapAlloc( GetProcessHeap(), 0, strlen(data_dir) + strlen(filename) + 1 );
618 if (ret)
620 strcpy( ret, data_dir );
621 strcat( ret, filename );
624 return ret;
627 static BOOL copy_file( const char *src, const char *dst )
629 int fds[2] = {-1, -1}, num;
630 char buf[1024];
631 BOOL ret = FALSE;
633 fds[0] = open( src, O_RDONLY );
634 fds[1] = open( dst, O_CREAT | O_TRUNC | O_WRONLY, 0666 );
635 if (fds[0] == -1 || fds[1] == -1) goto fail;
637 while ((num = read( fds[0], buf, sizeof(buf) )) != 0)
639 if (num == -1) goto fail;
640 if (write( fds[1], buf, num ) != num) goto fail;
642 ret = TRUE;
644 fail:
645 if (fds[1] != -1) close( fds[1] );
646 if (fds[0] != -1) close( fds[0] );
647 return ret;
650 static BOOL get_fallback_ppd( const char *printer_name, const WCHAR *ppd )
652 char *src = get_fallback_ppd_name( printer_name );
653 char *dst = wine_get_unix_file_name( ppd );
654 BOOL ret = FALSE;
656 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name), debugstr_w(ppd), debugstr_a(src) );
658 if (!src || !dst) goto fail;
660 if (symlink( src, dst ) == -1)
661 if (errno != ENOSYS || !copy_file( src, dst ))
662 goto fail;
664 ret = TRUE;
665 fail:
666 HeapFree( GetProcessHeap(), 0, dst );
667 HeapFree( GetProcessHeap(), 0, src );
668 return ret;
671 static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
673 static const WCHAR dot_ppd[] = {'.','p','p','d',0};
674 int len = (strlenW( dir ) + strlenW( file_name )) * sizeof(WCHAR) + sizeof(dot_ppd);
675 WCHAR *ppd = HeapAlloc( GetProcessHeap(), 0, len );
677 if (!ppd) return NULL;
678 strcpyW( ppd, dir );
679 strcatW( ppd, file_name );
680 strcatW( ppd, dot_ppd );
682 return ppd;
685 static WCHAR *get_ppd_dir( void )
687 static const WCHAR wine_ppds[] = {'w','i','n','e','_','p','p','d','s','\\',0};
688 DWORD len;
689 WCHAR *dir, tmp_path[MAX_PATH];
690 BOOL res;
692 len = GetTempPathW( sizeof(tmp_path) / sizeof(tmp_path[0]), tmp_path );
693 if (!len) return NULL;
694 dir = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(wine_ppds) ) ;
695 if (!dir) return NULL;
697 memcpy( dir, tmp_path, len * sizeof(WCHAR) );
698 memcpy( dir + len, wine_ppds, sizeof(wine_ppds) );
699 res = CreateDirectoryW( dir, NULL );
700 if (!res && GetLastError() != ERROR_ALREADY_EXISTS)
702 HeapFree( GetProcessHeap(), 0, dir );
703 dir = NULL;
705 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir) );
706 return dir;
709 static void unlink_ppd( const WCHAR *ppd )
711 char *unix_name = wine_get_unix_file_name( ppd );
712 unlink( unix_name );
713 HeapFree( GetProcessHeap(), 0, unix_name );
716 #ifdef SONAME_LIBCUPS
718 static void *cupshandle;
720 #define CUPS_FUNCS \
721 DO_FUNC(cupsFreeDests); \
722 DO_FUNC(cupsFreeOptions); \
723 DO_FUNC(cupsGetDests); \
724 DO_FUNC(cupsGetOption); \
725 DO_FUNC(cupsGetPPD); \
726 DO_FUNC(cupsParseOptions); \
727 DO_FUNC(cupsPrintFile);
728 #define CUPS_OPT_FUNCS \
729 DO_FUNC(cupsGetPPD3);
731 #define DO_FUNC(f) static typeof(f) *p##f
732 CUPS_FUNCS;
733 #undef DO_FUNC
734 static http_status_t (*pcupsGetPPD3)(http_t *,const char *, time_t *, char *, size_t);
736 static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name,
737 time_t *modtime, char *buffer,
738 size_t bufsize )
740 const char *ppd;
742 if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
744 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
746 *modtime = 0;
747 ppd = pcupsGetPPD( name );
749 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
751 if (!ppd) return HTTP_NOT_FOUND;
753 if (rename( ppd, buffer ) == -1)
755 BOOL res = copy_file( ppd, buffer );
756 unlink( ppd );
757 if (!res) return HTTP_NOT_FOUND;
759 return HTTP_OK;
762 static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
764 time_t modtime = 0;
765 http_status_t http_status;
766 char *unix_name = wine_get_unix_file_name( ppd );
768 TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
770 if (!unix_name) return FALSE;
772 http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
773 unix_name, strlen( unix_name ) + 1 );
774 HeapFree( GetProcessHeap(), 0, unix_name );
776 if (http_status == HTTP_OK) return TRUE;
778 TRACE( "failed to get ppd for printer %s from cups, calling fallback\n", debugstr_a(printer_name) );
779 return get_fallback_ppd( printer_name, ppd );
782 static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
784 const char *value;
785 WCHAR *ret;
786 int len;
788 value = pcupsGetOption( name, num_options, options );
789 if (!value) return NULL;
791 len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
792 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
793 if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
795 return ret;
798 static BOOL CUPS_LoadPrinters(void)
800 int i, nrofdests;
801 BOOL hadprinter = FALSE, haddefault = FALSE;
802 cups_dest_t *dests;
803 PRINTER_INFO_2W pi2;
804 WCHAR *port, *ppd_dir = NULL, *ppd;
805 HKEY hkeyPrinter, hkeyPrinters;
806 char loaderror[256];
807 WCHAR nameW[MAX_PATH];
808 HANDLE added_printer;
810 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
811 if (!cupshandle) {
812 TRACE("%s\n", loaderror);
813 return FALSE;
815 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
817 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
818 CUPS_FUNCS;
819 #undef DO_FUNC
820 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 );
821 CUPS_OPT_FUNCS;
822 #undef DO_FUNC
824 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
825 ERROR_SUCCESS) {
826 ERR("Can't create Printers key\n");
827 return FALSE;
830 nrofdests = pcupsGetDests(&dests);
831 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
832 for (i=0;i<nrofdests;i++) {
833 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
835 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
836 lstrcpyW(port, CUPS_Port);
837 lstrcatW(port, nameW);
839 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
840 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
841 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
842 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
843 and continue */
844 TRACE("Printer already exists\n");
845 /* overwrite old LPR:* port */
846 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
847 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
848 /* flag that the PPD file should be checked for an update */
849 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
850 RegCloseKey(hkeyPrinter);
851 } else {
852 BOOL added_driver = FALSE;
854 if (!ppd_dir) ppd_dir = get_ppd_dir();
855 ppd = get_ppd_filename( ppd_dir, nameW );
856 if (get_cups_ppd( dests[i].name, ppd ))
858 added_driver = add_printer_driver( nameW, ppd );
859 unlink_ppd( ppd );
861 HeapFree( GetProcessHeap(), 0, ppd );
862 if (!added_driver) continue;
864 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
865 pi2.pPrinterName = nameW;
866 pi2.pDatatype = rawW;
867 pi2.pPrintProcessor = WinPrintW;
868 pi2.pDriverName = nameW;
869 pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
870 pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
871 pi2.pPortName = port;
872 pi2.pParameters = emptyStringW;
873 pi2.pShareName = emptyStringW;
874 pi2.pSepFile = emptyStringW;
876 added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
877 if (added_printer) ClosePrinter( added_printer );
878 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
879 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
881 HeapFree( GetProcessHeap(), 0, pi2.pComment );
882 HeapFree( GetProcessHeap(), 0, pi2.pLocation );
884 HeapFree( GetProcessHeap(), 0, port );
886 hadprinter = TRUE;
887 if (dests[i].is_default) {
888 SetDefaultPrinterW(nameW);
889 haddefault = TRUE;
893 if (ppd_dir)
895 RemoveDirectoryW( ppd_dir );
896 HeapFree( GetProcessHeap(), 0, ppd_dir );
899 if (hadprinter && !haddefault) {
900 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
901 SetDefaultPrinterW(nameW);
903 pcupsFreeDests(nrofdests, dests);
904 RegCloseKey(hkeyPrinters);
905 return TRUE;
908 #endif
910 static char *get_queue_name( HANDLE printer, BOOL *cups )
912 WCHAR *port, *name = NULL;
913 DWORD err, needed, type;
914 char *ret = NULL;
915 HKEY key;
917 *cups = FALSE;
919 err = WINSPOOL_GetOpenedPrinterRegKey( printer, &key );
920 if (err) return NULL;
921 err = RegQueryValueExW( key, PortW, 0, &type, NULL, &needed );
922 if (err) goto end;
923 port = HeapAlloc( GetProcessHeap(), 0, needed );
924 if (!port) goto end;
925 RegQueryValueExW( key, PortW, 0, &type, (BYTE*)port, &needed );
927 if (!strncmpW( port, CUPS_Port, sizeof(CUPS_Port) / sizeof(WCHAR) -1 ))
929 name = port + sizeof(CUPS_Port) / sizeof(WCHAR) - 1;
930 *cups = TRUE;
932 else if (!strncmpW( port, LPR_Port, sizeof(LPR_Port) / sizeof(WCHAR) -1 ))
933 name = port + sizeof(LPR_Port) / sizeof(WCHAR) - 1;
934 if (name)
936 needed = WideCharToMultiByte( CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL );
937 ret = HeapAlloc( GetProcessHeap(), 0, needed );
938 if(ret) WideCharToMultiByte( CP_UNIXCP, 0, name, -1, ret, needed, NULL, NULL );
940 HeapFree( GetProcessHeap(), 0, port );
941 end:
942 RegCloseKey( key );
943 return ret;
947 static BOOL update_driver( HANDLE printer )
949 BOOL ret, is_cups;
950 const WCHAR *name = get_opened_printer_name( printer );
951 WCHAR *ppd_dir, *ppd;
952 char *queue_name;
954 if (!name) return FALSE;
955 queue_name = get_queue_name( printer, &is_cups );
956 if (!queue_name) return FALSE;
958 ppd_dir = get_ppd_dir();
959 ppd = get_ppd_filename( ppd_dir, name );
961 #ifdef SONAME_LIBCUPS
962 if (is_cups)
963 ret = get_cups_ppd( queue_name, ppd );
964 else
965 #endif
966 ret = get_fallback_ppd( queue_name, ppd );
968 if (ret)
970 TRACE( "updating driver %s\n", debugstr_w( name ) );
971 ret = add_printer_driver( name, ppd );
972 unlink_ppd( ppd );
974 HeapFree( GetProcessHeap(), 0, ppd_dir );
975 HeapFree( GetProcessHeap(), 0, ppd );
976 HeapFree( GetProcessHeap(), 0, queue_name );
977 return ret;
980 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
982 PRINTER_INFO_2A pinfo2a;
983 const char *r;
984 size_t name_len;
985 char *e,*s,*name,*prettyname,*devname;
986 BOOL ret = FALSE, set_default = FALSE;
987 char *port = NULL, *env_default;
988 HKEY hkeyPrinter, hkeyPrinters = NULL;
989 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
990 HANDLE added_printer;
992 while (isspace(*pent)) pent++;
993 r = strchr(pent,':');
994 if (r)
995 name_len = r - pent;
996 else
997 name_len = strlen(pent);
998 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
999 memcpy(name, pent, name_len);
1000 name[name_len] = '\0';
1001 if (r)
1002 pent = r;
1003 else
1004 pent = "";
1006 TRACE("name=%s entry=%s\n",name, pent);
1008 if(ispunct(*name)) { /* a tc entry, not a real printer */
1009 TRACE("skipping tc entry\n");
1010 goto end;
1013 if(strstr(pent,":server")) { /* server only version so skip */
1014 TRACE("skipping server entry\n");
1015 goto end;
1018 /* Determine whether this is a postscript printer. */
1020 ret = TRUE;
1021 env_default = getenv("PRINTER");
1022 prettyname = name;
1023 /* Get longest name, usually the one at the right for later display. */
1024 while((s=strchr(prettyname,'|'))) {
1025 *s = '\0';
1026 e = s;
1027 while(isspace(*--e)) *e = '\0';
1028 TRACE("\t%s\n", debugstr_a(prettyname));
1029 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1030 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1033 e = prettyname + strlen(prettyname);
1034 while(isspace(*--e)) *e = '\0';
1035 TRACE("\t%s\n", debugstr_a(prettyname));
1036 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1038 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1039 * if it is too long, we use it as comment below. */
1040 devname = prettyname;
1041 if (strlen(devname)>=CCHDEVICENAME-1)
1042 devname = name;
1043 if (strlen(devname)>=CCHDEVICENAME-1) {
1044 ret = FALSE;
1045 goto end;
1048 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1049 sprintf(port,"LPR:%s",name);
1051 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1052 ERROR_SUCCESS) {
1053 ERR("Can't create Printers key\n");
1054 ret = FALSE;
1055 goto end;
1058 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
1060 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1061 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1062 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1063 and continue */
1064 TRACE("Printer already exists\n");
1065 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1066 /* flag that the PPD file should be checked for an update */
1067 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1068 RegCloseKey(hkeyPrinter);
1069 } else {
1070 static CHAR data_type[] = "RAW",
1071 print_proc[] = "WinPrint",
1072 comment[] = "WINEPS Printer using LPR",
1073 params[] = "<parameters?>",
1074 share_name[] = "<share name?>",
1075 sep_file[] = "<sep file?>";
1076 BOOL added_driver = FALSE;
1078 if (!ppd_dir) ppd_dir = get_ppd_dir();
1079 ppd = get_ppd_filename( ppd_dir, devnameW );
1080 if (get_fallback_ppd( devname, ppd ))
1082 added_driver = add_printer_driver( devnameW, ppd );
1083 unlink_ppd( ppd );
1085 HeapFree( GetProcessHeap(), 0, ppd );
1086 if (!added_driver) goto end;
1088 memset(&pinfo2a,0,sizeof(pinfo2a));
1089 pinfo2a.pPrinterName = devname;
1090 pinfo2a.pDatatype = data_type;
1091 pinfo2a.pPrintProcessor = print_proc;
1092 pinfo2a.pDriverName = devname;
1093 pinfo2a.pComment = comment;
1094 pinfo2a.pLocation = prettyname;
1095 pinfo2a.pPortName = port;
1096 pinfo2a.pParameters = params;
1097 pinfo2a.pShareName = share_name;
1098 pinfo2a.pSepFile = sep_file;
1100 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1101 if (added_printer) ClosePrinter( added_printer );
1102 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1103 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1106 if (isfirst || set_default)
1107 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1109 end:
1110 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1111 if (ppd_dir)
1113 RemoveDirectoryW( ppd_dir );
1114 HeapFree( GetProcessHeap(), 0, ppd_dir );
1116 HeapFree(GetProcessHeap(), 0, port);
1117 HeapFree(GetProcessHeap(), 0, name);
1118 return ret;
1121 static BOOL
1122 PRINTCAP_LoadPrinters(void) {
1123 BOOL hadprinter = FALSE;
1124 char buf[200];
1125 FILE *f;
1126 char *pent = NULL;
1127 BOOL had_bash = FALSE;
1129 f = fopen("/etc/printcap","r");
1130 if (!f)
1131 return FALSE;
1133 while(fgets(buf,sizeof(buf),f)) {
1134 char *start, *end;
1136 end=strchr(buf,'\n');
1137 if (end) *end='\0';
1139 start = buf;
1140 while(isspace(*start)) start++;
1141 if(*start == '#' || *start == '\0')
1142 continue;
1144 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1145 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1146 HeapFree(GetProcessHeap(),0,pent);
1147 pent = NULL;
1150 if (end && *--end == '\\') {
1151 *end = '\0';
1152 had_bash = TRUE;
1153 } else
1154 had_bash = FALSE;
1156 if (pent) {
1157 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1158 strcat(pent,start);
1159 } else {
1160 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1161 strcpy(pent,start);
1165 if(pent) {
1166 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1167 HeapFree(GetProcessHeap(),0,pent);
1169 fclose(f);
1170 return hadprinter;
1173 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1175 if (value)
1176 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1177 (lstrlenW(value) + 1) * sizeof(WCHAR));
1178 else
1179 return ERROR_FILE_NOT_FOUND;
1182 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1184 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1185 DWORD ret = ERROR_FILE_NOT_FOUND;
1187 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1188 and we support these drivers. NT writes DEVMODEW so somehow
1189 we'll need to distinguish between these when we support NT
1190 drivers */
1192 if (dmA)
1194 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1195 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1196 HeapFree( GetProcessHeap(), 0, dmA );
1199 return ret;
1202 /******************************************************************
1203 * get_servername_from_name (internal)
1205 * for an external server, a copy of the serverpart from the full name is returned
1208 static LPWSTR get_servername_from_name(LPCWSTR name)
1210 LPWSTR server;
1211 LPWSTR ptr;
1212 WCHAR buffer[MAX_PATH];
1213 DWORD len;
1215 if (name == NULL) return NULL;
1216 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1218 server = strdupW(&name[2]); /* skip over both backslash */
1219 if (server == NULL) return NULL;
1221 /* strip '\' and the printername */
1222 ptr = strchrW(server, '\\');
1223 if (ptr) ptr[0] = '\0';
1225 TRACE("found %s\n", debugstr_w(server));
1227 len = sizeof(buffer)/sizeof(buffer[0]);
1228 if (GetComputerNameW(buffer, &len)) {
1229 if (lstrcmpW(buffer, server) == 0) {
1230 /* The requested Servername is our computername */
1231 HeapFree(GetProcessHeap(), 0, server);
1232 return NULL;
1235 return server;
1238 /******************************************************************
1239 * get_basename_from_name (internal)
1241 * skip over the serverpart from the full name
1244 static LPCWSTR get_basename_from_name(LPCWSTR name)
1246 if (name == NULL) return NULL;
1247 if ((name[0] == '\\') && (name[1] == '\\')) {
1248 /* skip over the servername and search for the following '\' */
1249 name = strchrW(&name[2], '\\');
1250 if ((name) && (name[1])) {
1251 /* found a separator ('\') followed by a name:
1252 skip over the separator and return the rest */
1253 name++;
1255 else
1257 /* no basename present (we found only a servername) */
1258 return NULL;
1261 return name;
1264 static void free_printer_entry( opened_printer_t *printer )
1266 /* the queue is shared, so don't free that here */
1267 HeapFree( GetProcessHeap(), 0, printer->printername );
1268 HeapFree( GetProcessHeap(), 0, printer->name );
1269 HeapFree( GetProcessHeap(), 0, printer->devmode );
1270 HeapFree( GetProcessHeap(), 0, printer );
1273 /******************************************************************
1274 * get_opened_printer_entry
1275 * Get the first place empty in the opened printer table
1277 * ToDo:
1278 * - pDefault is ignored
1280 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1282 UINT_PTR handle = nb_printer_handles, i;
1283 jobqueue_t *queue = NULL;
1284 opened_printer_t *printer = NULL;
1285 LPWSTR servername;
1286 LPCWSTR printername;
1288 if ((backend == NULL) && !load_backend()) return NULL;
1290 servername = get_servername_from_name(name);
1291 if (servername) {
1292 FIXME("server %s not supported\n", debugstr_w(servername));
1293 HeapFree(GetProcessHeap(), 0, servername);
1294 SetLastError(ERROR_INVALID_PRINTER_NAME);
1295 return NULL;
1298 printername = get_basename_from_name(name);
1299 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1301 /* an empty printername is invalid */
1302 if (printername && (!printername[0])) {
1303 SetLastError(ERROR_INVALID_PARAMETER);
1304 return NULL;
1307 EnterCriticalSection(&printer_handles_cs);
1309 for (i = 0; i < nb_printer_handles; i++)
1311 if (!printer_handles[i])
1313 if(handle == nb_printer_handles)
1314 handle = i;
1316 else
1318 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1319 queue = printer_handles[i]->queue;
1323 if (handle >= nb_printer_handles)
1325 opened_printer_t **new_array;
1326 if (printer_handles)
1327 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1328 (nb_printer_handles + 16) * sizeof(*new_array) );
1329 else
1330 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1331 (nb_printer_handles + 16) * sizeof(*new_array) );
1333 if (!new_array)
1335 handle = 0;
1336 goto end;
1338 printer_handles = new_array;
1339 nb_printer_handles += 16;
1342 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1344 handle = 0;
1345 goto end;
1348 /* get a printer handle from the backend */
1349 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1350 handle = 0;
1351 goto end;
1354 /* clone the base name. This is NULL for the printserver */
1355 printer->printername = strdupW(printername);
1357 /* clone the full name */
1358 printer->name = strdupW(name);
1359 if (name && (!printer->name)) {
1360 handle = 0;
1361 goto end;
1364 if (pDefault && pDefault->pDevMode)
1365 printer->devmode = dup_devmode( pDefault->pDevMode );
1367 if(queue)
1368 printer->queue = queue;
1369 else
1371 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1372 if (!printer->queue) {
1373 handle = 0;
1374 goto end;
1376 list_init(&printer->queue->jobs);
1377 printer->queue->ref = 0;
1379 InterlockedIncrement(&printer->queue->ref);
1381 printer_handles[handle] = printer;
1382 handle++;
1383 end:
1384 LeaveCriticalSection(&printer_handles_cs);
1385 if (!handle && printer) {
1386 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1387 free_printer_entry( printer );
1390 return (HANDLE)handle;
1393 static void old_printer_check( BOOL delete_phase )
1395 PRINTER_INFO_5W* pi;
1396 DWORD needed, type, num, delete, i, size;
1397 const DWORD one = 1;
1398 HKEY key;
1399 HANDLE hprn;
1401 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1402 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1404 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1405 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1406 for (i = 0; i < num; i++)
1408 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1409 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1410 continue;
1412 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1414 if (!delete_phase)
1416 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1417 RegCloseKey( key );
1419 else
1421 delete = 0;
1422 size = sizeof( delete );
1423 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1424 RegCloseKey( key );
1425 if (delete)
1427 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1428 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1430 DeletePrinter( hprn );
1431 ClosePrinter( hprn );
1433 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1437 HeapFree(GetProcessHeap(), 0, pi);
1440 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1441 'M','U','T','E','X','_','_','\0'};
1442 static HANDLE init_mutex;
1444 void WINSPOOL_LoadSystemPrinters(void)
1446 HKEY hkey, hkeyPrinters;
1447 DWORD needed, num, i;
1448 WCHAR PrinterName[256];
1449 BOOL done = FALSE;
1451 /* FIXME: The init code should be moved to spoolsv.exe */
1452 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1453 if (!init_mutex)
1455 ERR( "Failed to create mutex\n" );
1456 return;
1458 if (GetLastError() == ERROR_ALREADY_EXISTS)
1460 WaitForSingleObject( init_mutex, INFINITE );
1461 ReleaseMutex( init_mutex );
1462 TRACE( "Init already done\n" );
1463 return;
1466 /* This ensures that all printer entries have a valid Name value. If causes
1467 problems later if they don't. If one is found to be missed we create one
1468 and set it equal to the name of the key */
1469 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1470 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1471 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1472 for(i = 0; i < num; i++) {
1473 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1474 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1475 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1476 set_reg_szW(hkey, NameW, PrinterName);
1478 RegCloseKey(hkey);
1483 RegCloseKey(hkeyPrinters);
1486 old_printer_check( FALSE );
1488 #ifdef SONAME_LIBCUPS
1489 done = CUPS_LoadPrinters();
1490 #endif
1492 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1493 PRINTCAP_LoadPrinters();
1495 old_printer_check( TRUE );
1497 ReleaseMutex( init_mutex );
1498 return;
1501 /******************************************************************
1502 * get_job
1504 * Get the pointer to the specified job.
1505 * Should hold the printer_handles_cs before calling.
1507 static job_t *get_job(HANDLE hprn, DWORD JobId)
1509 opened_printer_t *printer = get_opened_printer(hprn);
1510 job_t *job;
1512 if(!printer) return NULL;
1513 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1515 if(job->job_id == JobId)
1516 return job;
1518 return NULL;
1521 /***********************************************************
1522 * DEVMODEcpyAtoW
1524 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1526 BOOL Formname;
1527 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1528 DWORD size;
1530 Formname = (dmA->dmSize > off_formname);
1531 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1532 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1533 dmW->dmDeviceName, CCHDEVICENAME);
1534 if(!Formname) {
1535 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1536 dmA->dmSize - CCHDEVICENAME);
1537 } else {
1538 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1539 off_formname - CCHDEVICENAME);
1540 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1541 dmW->dmFormName, CCHFORMNAME);
1542 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1543 (off_formname + CCHFORMNAME));
1545 dmW->dmSize = size;
1546 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1547 dmA->dmDriverExtra);
1548 return dmW;
1551 /******************************************************************
1552 * convert_printerinfo_W_to_A [internal]
1555 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1556 DWORD level, DWORD outlen, DWORD numentries)
1558 DWORD id = 0;
1559 LPSTR ptr;
1560 INT len;
1562 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1564 len = pi_sizeof[level] * numentries;
1565 ptr = (LPSTR) out + len;
1566 outlen -= len;
1568 /* copy the numbers of all PRINTER_INFO_* first */
1569 memcpy(out, pPrintersW, len);
1571 while (id < numentries) {
1572 switch (level) {
1573 case 1:
1575 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1576 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1578 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1579 if (piW->pDescription) {
1580 piA->pDescription = ptr;
1581 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1582 ptr, outlen, NULL, NULL);
1583 ptr += len;
1584 outlen -= len;
1586 if (piW->pName) {
1587 piA->pName = ptr;
1588 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1589 ptr, outlen, NULL, NULL);
1590 ptr += len;
1591 outlen -= len;
1593 if (piW->pComment) {
1594 piA->pComment = ptr;
1595 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1596 ptr, outlen, NULL, NULL);
1597 ptr += len;
1598 outlen -= len;
1600 break;
1603 case 2:
1605 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1606 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1607 LPDEVMODEA dmA;
1609 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1610 if (piW->pServerName) {
1611 piA->pServerName = ptr;
1612 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1613 ptr, outlen, NULL, NULL);
1614 ptr += len;
1615 outlen -= len;
1617 if (piW->pPrinterName) {
1618 piA->pPrinterName = ptr;
1619 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1620 ptr, outlen, NULL, NULL);
1621 ptr += len;
1622 outlen -= len;
1624 if (piW->pShareName) {
1625 piA->pShareName = ptr;
1626 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1627 ptr, outlen, NULL, NULL);
1628 ptr += len;
1629 outlen -= len;
1631 if (piW->pPortName) {
1632 piA->pPortName = ptr;
1633 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1634 ptr, outlen, NULL, NULL);
1635 ptr += len;
1636 outlen -= len;
1638 if (piW->pDriverName) {
1639 piA->pDriverName = ptr;
1640 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1641 ptr, outlen, NULL, NULL);
1642 ptr += len;
1643 outlen -= len;
1645 if (piW->pComment) {
1646 piA->pComment = ptr;
1647 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1648 ptr, outlen, NULL, NULL);
1649 ptr += len;
1650 outlen -= len;
1652 if (piW->pLocation) {
1653 piA->pLocation = ptr;
1654 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1655 ptr, outlen, NULL, NULL);
1656 ptr += len;
1657 outlen -= len;
1660 dmA = DEVMODEdupWtoA(piW->pDevMode);
1661 if (dmA) {
1662 /* align DEVMODEA to a DWORD boundary */
1663 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1664 ptr += len;
1665 outlen -= len;
1667 piA->pDevMode = (LPDEVMODEA) ptr;
1668 len = dmA->dmSize + dmA->dmDriverExtra;
1669 memcpy(ptr, dmA, len);
1670 HeapFree(GetProcessHeap(), 0, dmA);
1672 ptr += len;
1673 outlen -= len;
1676 if (piW->pSepFile) {
1677 piA->pSepFile = ptr;
1678 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1679 ptr, outlen, NULL, NULL);
1680 ptr += len;
1681 outlen -= len;
1683 if (piW->pPrintProcessor) {
1684 piA->pPrintProcessor = ptr;
1685 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1686 ptr, outlen, NULL, NULL);
1687 ptr += len;
1688 outlen -= len;
1690 if (piW->pDatatype) {
1691 piA->pDatatype = ptr;
1692 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1693 ptr, outlen, NULL, NULL);
1694 ptr += len;
1695 outlen -= len;
1697 if (piW->pParameters) {
1698 piA->pParameters = ptr;
1699 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1700 ptr, outlen, NULL, NULL);
1701 ptr += len;
1702 outlen -= len;
1704 if (piW->pSecurityDescriptor) {
1705 piA->pSecurityDescriptor = NULL;
1706 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1708 break;
1711 case 4:
1713 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1714 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1716 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1718 if (piW->pPrinterName) {
1719 piA->pPrinterName = ptr;
1720 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1721 ptr, outlen, NULL, NULL);
1722 ptr += len;
1723 outlen -= len;
1725 if (piW->pServerName) {
1726 piA->pServerName = ptr;
1727 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1728 ptr, outlen, NULL, NULL);
1729 ptr += len;
1730 outlen -= len;
1732 break;
1735 case 5:
1737 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1738 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1740 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1742 if (piW->pPrinterName) {
1743 piA->pPrinterName = ptr;
1744 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1745 ptr, outlen, NULL, NULL);
1746 ptr += len;
1747 outlen -= len;
1749 if (piW->pPortName) {
1750 piA->pPortName = ptr;
1751 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1752 ptr, outlen, NULL, NULL);
1753 ptr += len;
1754 outlen -= len;
1756 break;
1759 case 6: /* 6A and 6W are the same structure */
1760 break;
1762 case 7:
1764 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1765 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1767 TRACE("(%u) #%u\n", level, id);
1768 if (piW->pszObjectGUID) {
1769 piA->pszObjectGUID = ptr;
1770 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1771 ptr, outlen, NULL, NULL);
1772 ptr += len;
1773 outlen -= len;
1775 break;
1778 case 8:
1779 case 9:
1781 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1782 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1783 LPDEVMODEA dmA;
1785 TRACE("(%u) #%u\n", level, id);
1786 dmA = DEVMODEdupWtoA(piW->pDevMode);
1787 if (dmA) {
1788 /* align DEVMODEA to a DWORD boundary */
1789 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1790 ptr += len;
1791 outlen -= len;
1793 piA->pDevMode = (LPDEVMODEA) ptr;
1794 len = dmA->dmSize + dmA->dmDriverExtra;
1795 memcpy(ptr, dmA, len);
1796 HeapFree(GetProcessHeap(), 0, dmA);
1798 ptr += len;
1799 outlen -= len;
1802 break;
1805 default:
1806 FIXME("for level %u\n", level);
1808 pPrintersW += pi_sizeof[level];
1809 out += pi_sizeof[level];
1810 id++;
1814 /******************************************************************
1815 * convert_driverinfo_W_to_A [internal]
1818 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1819 DWORD level, DWORD outlen, DWORD numentries)
1821 DWORD id = 0;
1822 LPSTR ptr;
1823 INT len;
1825 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1827 len = di_sizeof[level] * numentries;
1828 ptr = (LPSTR) out + len;
1829 outlen -= len;
1831 /* copy the numbers of all PRINTER_INFO_* first */
1832 memcpy(out, pDriversW, len);
1834 #define COPY_STRING(fld) \
1835 { if (diW->fld){ \
1836 diA->fld = ptr; \
1837 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1838 ptr += len; outlen -= len;\
1840 #define COPY_MULTIZ_STRING(fld) \
1841 { LPWSTR p = diW->fld; if (p){ \
1842 diA->fld = ptr; \
1843 do {\
1844 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1845 ptr += len; outlen -= len; p += len;\
1847 while(len > 1 && outlen > 0); \
1850 while (id < numentries)
1852 switch (level)
1854 case 1:
1856 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1857 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1859 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1861 COPY_STRING(pName);
1862 break;
1864 case 2:
1866 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1867 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1869 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1871 COPY_STRING(pName);
1872 COPY_STRING(pEnvironment);
1873 COPY_STRING(pDriverPath);
1874 COPY_STRING(pDataFile);
1875 COPY_STRING(pConfigFile);
1876 break;
1878 case 3:
1880 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1881 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1883 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1885 COPY_STRING(pName);
1886 COPY_STRING(pEnvironment);
1887 COPY_STRING(pDriverPath);
1888 COPY_STRING(pDataFile);
1889 COPY_STRING(pConfigFile);
1890 COPY_STRING(pHelpFile);
1891 COPY_MULTIZ_STRING(pDependentFiles);
1892 COPY_STRING(pMonitorName);
1893 COPY_STRING(pDefaultDataType);
1894 break;
1896 case 4:
1898 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1899 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1901 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1903 COPY_STRING(pName);
1904 COPY_STRING(pEnvironment);
1905 COPY_STRING(pDriverPath);
1906 COPY_STRING(pDataFile);
1907 COPY_STRING(pConfigFile);
1908 COPY_STRING(pHelpFile);
1909 COPY_MULTIZ_STRING(pDependentFiles);
1910 COPY_STRING(pMonitorName);
1911 COPY_STRING(pDefaultDataType);
1912 COPY_MULTIZ_STRING(pszzPreviousNames);
1913 break;
1915 case 5:
1917 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1918 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1920 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1922 COPY_STRING(pName);
1923 COPY_STRING(pEnvironment);
1924 COPY_STRING(pDriverPath);
1925 COPY_STRING(pDataFile);
1926 COPY_STRING(pConfigFile);
1927 break;
1929 case 6:
1931 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1932 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1934 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1936 COPY_STRING(pName);
1937 COPY_STRING(pEnvironment);
1938 COPY_STRING(pDriverPath);
1939 COPY_STRING(pDataFile);
1940 COPY_STRING(pConfigFile);
1941 COPY_STRING(pHelpFile);
1942 COPY_MULTIZ_STRING(pDependentFiles);
1943 COPY_STRING(pMonitorName);
1944 COPY_STRING(pDefaultDataType);
1945 COPY_MULTIZ_STRING(pszzPreviousNames);
1946 COPY_STRING(pszMfgName);
1947 COPY_STRING(pszOEMUrl);
1948 COPY_STRING(pszHardwareID);
1949 COPY_STRING(pszProvider);
1950 break;
1952 case 8:
1954 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1955 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1957 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1959 COPY_STRING(pName);
1960 COPY_STRING(pEnvironment);
1961 COPY_STRING(pDriverPath);
1962 COPY_STRING(pDataFile);
1963 COPY_STRING(pConfigFile);
1964 COPY_STRING(pHelpFile);
1965 COPY_MULTIZ_STRING(pDependentFiles);
1966 COPY_STRING(pMonitorName);
1967 COPY_STRING(pDefaultDataType);
1968 COPY_MULTIZ_STRING(pszzPreviousNames);
1969 COPY_STRING(pszMfgName);
1970 COPY_STRING(pszOEMUrl);
1971 COPY_STRING(pszHardwareID);
1972 COPY_STRING(pszProvider);
1973 COPY_STRING(pszPrintProcessor);
1974 COPY_STRING(pszVendorSetup);
1975 COPY_MULTIZ_STRING(pszzColorProfiles);
1976 COPY_STRING(pszInfPath);
1977 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1978 break;
1982 default:
1983 FIXME("for level %u\n", level);
1986 pDriversW += di_sizeof[level];
1987 out += di_sizeof[level];
1988 id++;
1991 #undef COPY_STRING
1992 #undef COPY_MULTIZ_STRING
1996 /***********************************************************
1997 * printer_info_AtoW
1999 static void *printer_info_AtoW( const void *data, DWORD level )
2001 void *ret;
2002 UNICODE_STRING usBuffer;
2004 if (!data) return NULL;
2006 if (level < 1 || level > 9) return NULL;
2008 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2009 if (!ret) return NULL;
2011 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2013 switch (level)
2015 case 2:
2017 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2018 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2020 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2021 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2022 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2023 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2024 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2025 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2026 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2027 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2028 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2029 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2030 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2031 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2032 break;
2035 case 8:
2036 case 9:
2038 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2039 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2041 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2042 break;
2045 default:
2046 FIXME( "Unhandled level %d\n", level );
2047 HeapFree( GetProcessHeap(), 0, ret );
2048 return NULL;
2051 return ret;
2054 /***********************************************************
2055 * free_printer_info
2057 static void free_printer_info( void *data, DWORD level )
2059 if (!data) return;
2061 switch (level)
2063 case 2:
2065 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2067 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2068 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2069 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2070 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2071 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2072 HeapFree( GetProcessHeap(), 0, piW->pComment );
2073 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2074 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2075 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2076 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2077 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2078 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2079 break;
2082 case 8:
2083 case 9:
2085 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2087 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2088 break;
2091 default:
2092 FIXME( "Unhandled level %d\n", level );
2095 HeapFree( GetProcessHeap(), 0, data );
2096 return;
2099 /******************************************************************
2100 * DeviceCapabilities [WINSPOOL.@]
2101 * DeviceCapabilitiesA [WINSPOOL.@]
2104 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2105 LPSTR pOutput, LPDEVMODEA lpdm)
2107 INT ret;
2109 if (!GDI_CallDeviceCapabilities16)
2111 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2112 (LPCSTR)104 );
2113 if (!GDI_CallDeviceCapabilities16) return -1;
2115 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2117 /* If DC_PAPERSIZE map POINT16s to POINTs */
2118 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2119 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2120 POINT *pt = (POINT *)pOutput;
2121 INT i;
2122 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2123 for(i = 0; i < ret; i++, pt++)
2125 pt->x = tmp[i].x;
2126 pt->y = tmp[i].y;
2128 HeapFree( GetProcessHeap(), 0, tmp );
2130 return ret;
2134 /*****************************************************************************
2135 * DeviceCapabilitiesW [WINSPOOL.@]
2137 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2140 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2141 WORD fwCapability, LPWSTR pOutput,
2142 const DEVMODEW *pDevMode)
2144 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2145 LPSTR pDeviceA = strdupWtoA(pDevice);
2146 LPSTR pPortA = strdupWtoA(pPort);
2147 INT ret;
2149 if(pOutput && (fwCapability == DC_BINNAMES ||
2150 fwCapability == DC_FILEDEPENDENCIES ||
2151 fwCapability == DC_PAPERNAMES)) {
2152 /* These need A -> W translation */
2153 INT size = 0, i;
2154 LPSTR pOutputA;
2155 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2156 dmA);
2157 if(ret == -1)
2158 return ret;
2159 switch(fwCapability) {
2160 case DC_BINNAMES:
2161 size = 24;
2162 break;
2163 case DC_PAPERNAMES:
2164 case DC_FILEDEPENDENCIES:
2165 size = 64;
2166 break;
2168 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2169 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2170 dmA);
2171 for(i = 0; i < ret; i++)
2172 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2173 pOutput + (i * size), size);
2174 HeapFree(GetProcessHeap(), 0, pOutputA);
2175 } else {
2176 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2177 (LPSTR)pOutput, dmA);
2179 HeapFree(GetProcessHeap(),0,pPortA);
2180 HeapFree(GetProcessHeap(),0,pDeviceA);
2181 HeapFree(GetProcessHeap(),0,dmA);
2182 return ret;
2185 /******************************************************************
2186 * DocumentPropertiesA [WINSPOOL.@]
2188 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2190 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2191 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2192 LPDEVMODEA pDevModeInput,DWORD fMode )
2194 LPSTR lpName = pDeviceName;
2195 static CHAR port[] = "LPT1:";
2196 LONG ret;
2198 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2199 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2202 if(!pDeviceName) {
2203 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2204 if(!lpNameW) {
2205 ERR("no name from hPrinter?\n");
2206 SetLastError(ERROR_INVALID_HANDLE);
2207 return -1;
2209 lpName = strdupWtoA(lpNameW);
2212 if (!GDI_CallExtDeviceMode16)
2214 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2215 (LPCSTR)102 );
2216 if (!GDI_CallExtDeviceMode16) {
2217 ERR("No CallExtDeviceMode16?\n");
2218 return -1;
2221 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2222 pDevModeInput, NULL, fMode);
2224 if(!pDeviceName)
2225 HeapFree(GetProcessHeap(),0,lpName);
2226 return ret;
2230 /*****************************************************************************
2231 * DocumentPropertiesW (WINSPOOL.@)
2233 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2235 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2236 LPWSTR pDeviceName,
2237 LPDEVMODEW pDevModeOutput,
2238 LPDEVMODEW pDevModeInput, DWORD fMode)
2241 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2242 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2243 LPDEVMODEA pDevModeOutputA = NULL;
2244 LONG ret;
2246 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2247 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2248 fMode);
2249 if(pDevModeOutput) {
2250 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2251 if(ret < 0) return ret;
2252 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2254 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2255 pDevModeInputA, fMode);
2256 if(pDevModeOutput) {
2257 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2258 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2260 if(fMode == 0 && ret > 0)
2261 ret += (CCHDEVICENAME + CCHFORMNAME);
2262 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2263 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2264 return ret;
2267 /*****************************************************************************
2268 * IsValidDevmodeA [WINSPOOL.@]
2270 * Validate a DEVMODE structure and fix errors if possible.
2273 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2275 FIXME("(%p,%ld): stub\n", pDevMode, size);
2277 if(!pDevMode)
2278 return FALSE;
2280 return TRUE;
2283 /*****************************************************************************
2284 * IsValidDevmodeW [WINSPOOL.@]
2286 * Validate a DEVMODE structure and fix errors if possible.
2289 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2291 FIXME("(%p,%ld): stub\n", pDevMode, size);
2293 if(!pDevMode)
2294 return FALSE;
2296 return TRUE;
2299 /******************************************************************
2300 * OpenPrinterA [WINSPOOL.@]
2302 * See OpenPrinterW.
2305 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2306 LPPRINTER_DEFAULTSA pDefault)
2308 UNICODE_STRING lpPrinterNameW;
2309 UNICODE_STRING usBuffer;
2310 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2311 PWSTR pwstrPrinterNameW;
2312 BOOL ret;
2314 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2316 if(pDefault) {
2317 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2318 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2319 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2320 pDefaultW = &DefaultW;
2322 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2323 if(pDefault) {
2324 RtlFreeUnicodeString(&usBuffer);
2325 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2327 RtlFreeUnicodeString(&lpPrinterNameW);
2328 return ret;
2331 /******************************************************************
2332 * OpenPrinterW [WINSPOOL.@]
2334 * Open a Printer / Printserver or a Printer-Object
2336 * PARAMS
2337 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2338 * phPrinter [O] The resulting Handle is stored here
2339 * pDefault [I] PTR to Default Printer Settings or NULL
2341 * RETURNS
2342 * Success: TRUE
2343 * Failure: FALSE
2345 * NOTES
2346 * lpPrinterName is one of:
2347 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2348 *| Printer: "PrinterName"
2349 *| Printer-Object: "PrinterName,Job xxx"
2350 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2351 *| XcvPort: "Servername,XcvPort PortName"
2353 * BUGS
2354 *| Printer-Object not supported
2355 *| pDefaults is ignored
2358 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2361 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2363 if(!phPrinter) {
2364 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2365 SetLastError(ERROR_INVALID_PARAMETER);
2366 return FALSE;
2369 /* Get the unique handle of the printer or Printserver */
2370 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2372 WaitForSingleObject( init_mutex, INFINITE );
2373 if (*phPrinter)
2375 HKEY key;
2376 DWORD deleting = 0, size = sizeof( deleting ), type;
2377 DWORD status;
2378 WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key );
2379 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2380 status = get_dword_from_reg( key, StatusW );
2381 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2383 update_driver( *phPrinter );
2384 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2386 RegCloseKey( key );
2388 ReleaseMutex( init_mutex );
2390 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2391 return (*phPrinter != 0);
2394 /******************************************************************
2395 * AddMonitorA [WINSPOOL.@]
2397 * See AddMonitorW.
2400 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2402 LPWSTR nameW = NULL;
2403 INT len;
2404 BOOL res;
2405 LPMONITOR_INFO_2A mi2a;
2406 MONITOR_INFO_2W mi2w;
2408 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2409 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2410 debugstr_a(mi2a ? mi2a->pName : NULL),
2411 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2412 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2414 if (Level != 2) {
2415 SetLastError(ERROR_INVALID_LEVEL);
2416 return FALSE;
2419 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2420 if (mi2a == NULL) {
2421 return FALSE;
2424 if (pName) {
2425 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2426 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2427 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2430 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2431 if (mi2a->pName) {
2432 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2433 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2434 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2436 if (mi2a->pEnvironment) {
2437 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2438 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2439 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2441 if (mi2a->pDLLName) {
2442 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2443 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2444 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2447 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2449 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2450 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2451 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2453 HeapFree(GetProcessHeap(), 0, nameW);
2454 return (res);
2457 /******************************************************************************
2458 * AddMonitorW [WINSPOOL.@]
2460 * Install a Printmonitor
2462 * PARAMS
2463 * pName [I] Servername or NULL (local Computer)
2464 * Level [I] Structure-Level (Must be 2)
2465 * pMonitors [I] PTR to MONITOR_INFO_2
2467 * RETURNS
2468 * Success: TRUE
2469 * Failure: FALSE
2471 * NOTES
2472 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2475 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2477 LPMONITOR_INFO_2W mi2w;
2479 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2480 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2481 debugstr_w(mi2w ? mi2w->pName : NULL),
2482 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2483 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2485 if ((backend == NULL) && !load_backend()) return FALSE;
2487 if (Level != 2) {
2488 SetLastError(ERROR_INVALID_LEVEL);
2489 return FALSE;
2492 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2493 if (mi2w == NULL) {
2494 return FALSE;
2497 return backend->fpAddMonitor(pName, Level, pMonitors);
2500 /******************************************************************
2501 * DeletePrinterDriverA [WINSPOOL.@]
2504 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2506 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2509 /******************************************************************
2510 * DeletePrinterDriverW [WINSPOOL.@]
2513 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2515 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2518 /******************************************************************
2519 * DeleteMonitorA [WINSPOOL.@]
2521 * See DeleteMonitorW.
2524 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2526 LPWSTR nameW = NULL;
2527 LPWSTR EnvironmentW = NULL;
2528 LPWSTR MonitorNameW = NULL;
2529 BOOL res;
2530 INT len;
2532 if (pName) {
2533 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2534 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2535 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2538 if (pEnvironment) {
2539 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2540 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2541 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2543 if (pMonitorName) {
2544 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2545 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2546 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2549 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2551 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2552 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2553 HeapFree(GetProcessHeap(), 0, nameW);
2554 return (res);
2557 /******************************************************************
2558 * DeleteMonitorW [WINSPOOL.@]
2560 * Delete a specific Printmonitor from a Printing-Environment
2562 * PARAMS
2563 * pName [I] Servername or NULL (local Computer)
2564 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2565 * pMonitorName [I] Name of the Monitor, that should be deleted
2567 * RETURNS
2568 * Success: TRUE
2569 * Failure: FALSE
2571 * NOTES
2572 * pEnvironment is ignored in Windows for the local Computer.
2575 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2578 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2579 debugstr_w(pMonitorName));
2581 if ((backend == NULL) && !load_backend()) return FALSE;
2583 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2587 /******************************************************************
2588 * DeletePortA [WINSPOOL.@]
2590 * See DeletePortW.
2593 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2595 LPWSTR nameW = NULL;
2596 LPWSTR portW = NULL;
2597 INT len;
2598 DWORD res;
2600 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2602 /* convert servername to unicode */
2603 if (pName) {
2604 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2605 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2606 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2609 /* convert portname to unicode */
2610 if (pPortName) {
2611 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2612 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2613 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2616 res = DeletePortW(nameW, hWnd, portW);
2617 HeapFree(GetProcessHeap(), 0, nameW);
2618 HeapFree(GetProcessHeap(), 0, portW);
2619 return res;
2622 /******************************************************************
2623 * DeletePortW [WINSPOOL.@]
2625 * Delete a specific Port
2627 * PARAMS
2628 * pName [I] Servername or NULL (local Computer)
2629 * hWnd [I] Handle to parent Window for the Dialog-Box
2630 * pPortName [I] Name of the Port, that should be deleted
2632 * RETURNS
2633 * Success: TRUE
2634 * Failure: FALSE
2637 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2639 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2641 if ((backend == NULL) && !load_backend()) return FALSE;
2643 if (!pPortName) {
2644 SetLastError(RPC_X_NULL_REF_POINTER);
2645 return FALSE;
2648 return backend->fpDeletePort(pName, hWnd, pPortName);
2651 /******************************************************************************
2652 * WritePrinter [WINSPOOL.@]
2654 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2656 opened_printer_t *printer;
2657 BOOL ret = FALSE;
2659 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2661 EnterCriticalSection(&printer_handles_cs);
2662 printer = get_opened_printer(hPrinter);
2663 if(!printer)
2665 SetLastError(ERROR_INVALID_HANDLE);
2666 goto end;
2669 if(!printer->doc)
2671 SetLastError(ERROR_SPL_NO_STARTDOC);
2672 goto end;
2675 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2676 end:
2677 LeaveCriticalSection(&printer_handles_cs);
2678 return ret;
2681 /*****************************************************************************
2682 * AddFormA [WINSPOOL.@]
2684 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2686 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2687 return 1;
2690 /*****************************************************************************
2691 * AddFormW [WINSPOOL.@]
2693 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2695 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2696 return 1;
2699 /*****************************************************************************
2700 * AddJobA [WINSPOOL.@]
2702 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2704 BOOL ret;
2705 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2706 DWORD needed;
2708 if(Level != 1) {
2709 SetLastError(ERROR_INVALID_LEVEL);
2710 return FALSE;
2713 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2715 if(ret) {
2716 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2717 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2718 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2719 if(*pcbNeeded > cbBuf) {
2720 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2721 ret = FALSE;
2722 } else {
2723 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2724 addjobA->JobId = addjobW->JobId;
2725 addjobA->Path = (char *)(addjobA + 1);
2726 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2729 return ret;
2732 /*****************************************************************************
2733 * AddJobW [WINSPOOL.@]
2735 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2737 opened_printer_t *printer;
2738 job_t *job;
2739 BOOL ret = FALSE;
2740 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2741 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2742 WCHAR path[MAX_PATH], filename[MAX_PATH];
2743 DWORD len;
2744 ADDJOB_INFO_1W *addjob;
2746 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2748 EnterCriticalSection(&printer_handles_cs);
2750 printer = get_opened_printer(hPrinter);
2752 if(!printer) {
2753 SetLastError(ERROR_INVALID_HANDLE);
2754 goto end;
2757 if(Level != 1) {
2758 SetLastError(ERROR_INVALID_LEVEL);
2759 goto end;
2762 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2763 if(!job)
2764 goto end;
2766 job->job_id = InterlockedIncrement(&next_job_id);
2768 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2769 if(path[len - 1] != '\\')
2770 path[len++] = '\\';
2771 memcpy(path + len, spool_path, sizeof(spool_path));
2772 sprintfW(filename, fmtW, path, job->job_id);
2774 len = strlenW(filename);
2775 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2776 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2777 job->portname = NULL;
2778 job->document_title = strdupW(default_doc_title);
2779 job->printer_name = strdupW(printer->name);
2780 job->devmode = dup_devmode( printer->devmode );
2781 list_add_tail(&printer->queue->jobs, &job->entry);
2783 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2784 if(*pcbNeeded <= cbBuf) {
2785 addjob = (ADDJOB_INFO_1W*)pData;
2786 addjob->JobId = job->job_id;
2787 addjob->Path = (WCHAR *)(addjob + 1);
2788 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2789 ret = TRUE;
2790 } else
2791 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2793 end:
2794 LeaveCriticalSection(&printer_handles_cs);
2795 return ret;
2798 /*****************************************************************************
2799 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2801 * Return the PATH for the Print-Processors
2803 * See GetPrintProcessorDirectoryW.
2807 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2808 DWORD level, LPBYTE Info,
2809 DWORD cbBuf, LPDWORD pcbNeeded)
2811 LPWSTR serverW = NULL;
2812 LPWSTR envW = NULL;
2813 BOOL ret;
2814 INT len;
2816 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2817 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2820 if (server) {
2821 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2822 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2823 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2826 if (env) {
2827 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2828 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2829 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2832 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2833 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2835 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2836 cbBuf, pcbNeeded);
2838 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2839 cbBuf, NULL, NULL) > 0;
2842 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2843 HeapFree(GetProcessHeap(), 0, envW);
2844 HeapFree(GetProcessHeap(), 0, serverW);
2845 return ret;
2848 /*****************************************************************************
2849 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2851 * Return the PATH for the Print-Processors
2853 * PARAMS
2854 * server [I] Servername (NT only) or NULL (local Computer)
2855 * env [I] Printing-Environment (see below) or NULL (Default)
2856 * level [I] Structure-Level (must be 1)
2857 * Info [O] PTR to Buffer that receives the Result
2858 * cbBuf [I] Size of Buffer at "Info"
2859 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2860 * required for the Buffer at "Info"
2862 * RETURNS
2863 * Success: TRUE and in pcbNeeded the Bytes used in Info
2864 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2865 * if cbBuf is too small
2867 * Native Values returned in Info on Success:
2868 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2869 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2870 *| win9x(Windows 4.0): "%winsysdir%"
2872 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2874 * BUGS
2875 * Only NULL or "" is supported for server
2878 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2879 DWORD level, LPBYTE Info,
2880 DWORD cbBuf, LPDWORD pcbNeeded)
2883 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2884 Info, cbBuf, pcbNeeded);
2886 if ((backend == NULL) && !load_backend()) return FALSE;
2888 if (level != 1) {
2889 /* (Level != 1) is ignored in win9x */
2890 SetLastError(ERROR_INVALID_LEVEL);
2891 return FALSE;
2894 if (pcbNeeded == NULL) {
2895 /* (pcbNeeded == NULL) is ignored in win9x */
2896 SetLastError(RPC_X_NULL_REF_POINTER);
2897 return FALSE;
2900 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2903 /*****************************************************************************
2904 * WINSPOOL_OpenDriverReg [internal]
2906 * opens the registry for the printer drivers depending on the given input
2907 * variable pEnvironment
2909 * RETURNS:
2910 * the opened hkey on success
2911 * NULL on error
2913 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2915 HKEY retval = NULL;
2916 LPWSTR buffer;
2917 const printenv_t * env;
2919 TRACE("(%s)\n", debugstr_w(pEnvironment));
2921 env = validate_envW(pEnvironment);
2922 if (!env) return NULL;
2924 buffer = HeapAlloc( GetProcessHeap(), 0,
2925 (strlenW(DriversW) + strlenW(env->envname) +
2926 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2927 if(buffer) {
2928 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2929 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2930 HeapFree(GetProcessHeap(), 0, buffer);
2932 return retval;
2935 /*****************************************************************************
2936 * set_devices_and_printerports [internal]
2938 * set the [Devices] and [PrinterPorts] entries for a printer.
2941 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2943 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2944 WCHAR *devline;
2945 HKEY hkey;
2947 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2949 /* FIXME: the driver must change to "winspool" */
2950 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2951 if (devline) {
2952 lstrcpyW(devline, driver_nt);
2953 lstrcatW(devline, commaW);
2954 lstrcatW(devline, pi->pPortName);
2956 TRACE("using %s\n", debugstr_w(devline));
2957 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2958 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2959 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2960 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2961 RegCloseKey(hkey);
2964 lstrcatW(devline, timeout_15_45);
2965 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2966 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2967 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2968 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2969 RegCloseKey(hkey);
2971 HeapFree(GetProcessHeap(), 0, devline);
2975 /*****************************************************************************
2976 * AddPrinterW [WINSPOOL.@]
2978 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2980 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2981 LPDEVMODEW dm;
2982 HANDLE retval;
2983 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2984 LONG size;
2986 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2988 if(pName != NULL) {
2989 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2990 SetLastError(ERROR_INVALID_PARAMETER);
2991 return 0;
2993 if(Level != 2) {
2994 ERR("Level = %d, unsupported!\n", Level);
2995 SetLastError(ERROR_INVALID_LEVEL);
2996 return 0;
2998 if(!pPrinter) {
2999 SetLastError(ERROR_INVALID_PARAMETER);
3000 return 0;
3002 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3003 ERROR_SUCCESS) {
3004 ERR("Can't create Printers key\n");
3005 return 0;
3007 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3008 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3009 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3010 RegCloseKey(hkeyPrinter);
3011 RegCloseKey(hkeyPrinters);
3012 return 0;
3014 RegCloseKey(hkeyPrinter);
3016 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3017 if(!hkeyDrivers) {
3018 ERR("Can't create Drivers key\n");
3019 RegCloseKey(hkeyPrinters);
3020 return 0;
3022 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3023 ERROR_SUCCESS) {
3024 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3025 RegCloseKey(hkeyPrinters);
3026 RegCloseKey(hkeyDrivers);
3027 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3028 return 0;
3030 RegCloseKey(hkeyDriver);
3031 RegCloseKey(hkeyDrivers);
3033 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3034 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3035 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3036 RegCloseKey(hkeyPrinters);
3037 return 0;
3040 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3041 ERROR_SUCCESS) {
3042 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3043 SetLastError(ERROR_INVALID_PRINTER_NAME);
3044 RegCloseKey(hkeyPrinters);
3045 return 0;
3048 set_devices_and_printerports(pi);
3050 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3051 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3052 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3053 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3054 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3055 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3056 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3057 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3058 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3059 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3060 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3061 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3062 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3063 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3064 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3065 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3066 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3067 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3069 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3071 if (size < 0)
3073 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3074 size = sizeof(DEVMODEW);
3076 if(pi->pDevMode)
3077 dm = pi->pDevMode;
3078 else
3080 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3081 dm->dmSize = size;
3082 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3084 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3085 HeapFree( GetProcessHeap(), 0, dm );
3086 dm = NULL;
3088 else
3090 /* set devmode to printer name */
3091 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3095 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3096 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3098 RegCloseKey(hkeyPrinter);
3099 RegCloseKey(hkeyPrinters);
3100 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3101 ERR("OpenPrinter failing\n");
3102 return 0;
3104 return retval;
3107 /*****************************************************************************
3108 * AddPrinterA [WINSPOOL.@]
3110 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3112 UNICODE_STRING pNameW;
3113 PWSTR pwstrNameW;
3114 PRINTER_INFO_2W *piW;
3115 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3116 HANDLE ret;
3118 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3119 if(Level != 2) {
3120 ERR("Level = %d, unsupported!\n", Level);
3121 SetLastError(ERROR_INVALID_LEVEL);
3122 return 0;
3124 pwstrNameW = asciitounicode(&pNameW,pName);
3125 piW = printer_info_AtoW( piA, Level );
3127 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3129 free_printer_info( piW, Level );
3130 RtlFreeUnicodeString(&pNameW);
3131 return ret;
3135 /*****************************************************************************
3136 * ClosePrinter [WINSPOOL.@]
3138 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3140 UINT_PTR i = (UINT_PTR)hPrinter;
3141 opened_printer_t *printer = NULL;
3142 BOOL ret = FALSE;
3144 TRACE("(%p)\n", hPrinter);
3146 EnterCriticalSection(&printer_handles_cs);
3148 if ((i > 0) && (i <= nb_printer_handles))
3149 printer = printer_handles[i - 1];
3152 if(printer)
3154 struct list *cursor, *cursor2;
3156 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3158 if (printer->backend_printer) {
3159 backend->fpClosePrinter(printer->backend_printer);
3162 if(printer->doc)
3163 EndDocPrinter(hPrinter);
3165 if(InterlockedDecrement(&printer->queue->ref) == 0)
3167 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3169 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3170 ScheduleJob(hPrinter, job->job_id);
3172 HeapFree(GetProcessHeap(), 0, printer->queue);
3175 free_printer_entry( printer );
3176 printer_handles[i - 1] = NULL;
3177 ret = TRUE;
3179 LeaveCriticalSection(&printer_handles_cs);
3180 return ret;
3183 /*****************************************************************************
3184 * DeleteFormA [WINSPOOL.@]
3186 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3188 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3189 return 1;
3192 /*****************************************************************************
3193 * DeleteFormW [WINSPOOL.@]
3195 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3197 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3198 return 1;
3201 /*****************************************************************************
3202 * DeletePrinter [WINSPOOL.@]
3204 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3206 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3207 HKEY hkeyPrinters, hkey;
3208 WCHAR def[MAX_PATH];
3209 DWORD size = sizeof( def ) / sizeof( def[0] );
3211 if(!lpNameW) {
3212 SetLastError(ERROR_INVALID_HANDLE);
3213 return FALSE;
3215 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3216 RegDeleteTreeW(hkeyPrinters, lpNameW);
3217 RegCloseKey(hkeyPrinters);
3219 WriteProfileStringW(devicesW, lpNameW, NULL);
3220 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3222 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3223 RegDeleteValueW(hkey, lpNameW);
3224 RegCloseKey(hkey);
3227 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3228 RegDeleteValueW(hkey, lpNameW);
3229 RegCloseKey(hkey);
3232 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3234 WriteProfileStringW( windowsW, deviceW, NULL );
3235 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3237 RegDeleteValueW( hkey, deviceW );
3238 RegCloseKey( hkey );
3240 SetDefaultPrinterW( NULL );
3243 return TRUE;
3246 /*****************************************************************************
3247 * SetPrinterA [WINSPOOL.@]
3249 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3251 BYTE *dataW = data;
3252 BOOL ret;
3254 if (level != 0)
3256 dataW = printer_info_AtoW( data, level );
3257 if (!dataW) return FALSE;
3260 ret = SetPrinterW( printer, level, dataW, command );
3262 if (dataW != data) free_printer_info( dataW, level );
3264 return ret;
3267 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3269 set_reg_szW( key, NameW, pi->pPrinterName );
3270 set_reg_szW( key, Share_NameW, pi->pShareName );
3271 set_reg_szW( key, PortW, pi->pPortName );
3272 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3273 set_reg_szW( key, DescriptionW, pi->pComment );
3274 set_reg_szW( key, LocationW, pi->pLocation );
3276 if (pi->pDevMode)
3277 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3279 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3280 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3281 set_reg_szW( key, DatatypeW, pi->pDatatype );
3282 set_reg_szW( key, ParametersW, pi->pParameters );
3284 set_reg_DWORD( key, AttributesW, pi->Attributes );
3285 set_reg_DWORD( key, PriorityW, pi->Priority );
3286 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3287 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3288 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3291 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3293 if (!pi->pDevMode) return FALSE;
3295 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3296 return TRUE;
3299 /******************************************************************************
3300 * SetPrinterW [WINSPOOL.@]
3302 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3304 HKEY key;
3305 BOOL ret = FALSE;
3307 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3309 if (command != 0) FIXME( "Ignoring command %d\n", command );
3311 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3312 return FALSE;
3314 switch (level)
3316 case 2:
3318 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3319 set_printer_2( key, pi2 );
3320 ret = TRUE;
3321 break;
3324 case 9:
3326 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3327 ret = set_printer_9( key, pi );
3328 break;
3331 default:
3332 FIXME( "Unimplemented level %d\n", level );
3333 SetLastError( ERROR_INVALID_LEVEL );
3336 RegCloseKey( key );
3337 return ret;
3340 /*****************************************************************************
3341 * SetJobA [WINSPOOL.@]
3343 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3344 LPBYTE pJob, DWORD Command)
3346 BOOL ret;
3347 LPBYTE JobW;
3348 UNICODE_STRING usBuffer;
3350 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3352 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3353 are all ignored by SetJob, so we don't bother copying them */
3354 switch(Level)
3356 case 0:
3357 JobW = NULL;
3358 break;
3359 case 1:
3361 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3362 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3364 JobW = (LPBYTE)info1W;
3365 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3366 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3367 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3368 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3369 info1W->Status = info1A->Status;
3370 info1W->Priority = info1A->Priority;
3371 info1W->Position = info1A->Position;
3372 info1W->PagesPrinted = info1A->PagesPrinted;
3373 break;
3375 case 2:
3377 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3378 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3380 JobW = (LPBYTE)info2W;
3381 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3382 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3383 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3384 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3385 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3386 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3387 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3388 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3389 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3390 info2W->Status = info2A->Status;
3391 info2W->Priority = info2A->Priority;
3392 info2W->Position = info2A->Position;
3393 info2W->StartTime = info2A->StartTime;
3394 info2W->UntilTime = info2A->UntilTime;
3395 info2W->PagesPrinted = info2A->PagesPrinted;
3396 break;
3398 case 3:
3399 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3400 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3401 break;
3402 default:
3403 SetLastError(ERROR_INVALID_LEVEL);
3404 return FALSE;
3407 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3409 switch(Level)
3411 case 1:
3413 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3414 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3415 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3416 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3417 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3418 break;
3420 case 2:
3422 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3423 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3424 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3425 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3426 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3427 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3428 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3429 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3430 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3431 break;
3434 HeapFree(GetProcessHeap(), 0, JobW);
3436 return ret;
3439 /*****************************************************************************
3440 * SetJobW [WINSPOOL.@]
3442 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3443 LPBYTE pJob, DWORD Command)
3445 BOOL ret = FALSE;
3446 job_t *job;
3448 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3449 FIXME("Ignoring everything other than document title\n");
3451 EnterCriticalSection(&printer_handles_cs);
3452 job = get_job(hPrinter, JobId);
3453 if(!job)
3454 goto end;
3456 switch(Level)
3458 case 0:
3459 break;
3460 case 1:
3462 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3463 HeapFree(GetProcessHeap(), 0, job->document_title);
3464 job->document_title = strdupW(info1->pDocument);
3465 break;
3467 case 2:
3469 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3470 HeapFree(GetProcessHeap(), 0, job->document_title);
3471 job->document_title = strdupW(info2->pDocument);
3472 HeapFree(GetProcessHeap(), 0, job->devmode);
3473 job->devmode = dup_devmode( info2->pDevMode );
3474 break;
3476 case 3:
3477 break;
3478 default:
3479 SetLastError(ERROR_INVALID_LEVEL);
3480 goto end;
3482 ret = TRUE;
3483 end:
3484 LeaveCriticalSection(&printer_handles_cs);
3485 return ret;
3488 /*****************************************************************************
3489 * EndDocPrinter [WINSPOOL.@]
3491 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3493 opened_printer_t *printer;
3494 BOOL ret = FALSE;
3495 TRACE("(%p)\n", hPrinter);
3497 EnterCriticalSection(&printer_handles_cs);
3499 printer = get_opened_printer(hPrinter);
3500 if(!printer)
3502 SetLastError(ERROR_INVALID_HANDLE);
3503 goto end;
3506 if(!printer->doc)
3508 SetLastError(ERROR_SPL_NO_STARTDOC);
3509 goto end;
3512 CloseHandle(printer->doc->hf);
3513 ScheduleJob(hPrinter, printer->doc->job_id);
3514 HeapFree(GetProcessHeap(), 0, printer->doc);
3515 printer->doc = NULL;
3516 ret = TRUE;
3517 end:
3518 LeaveCriticalSection(&printer_handles_cs);
3519 return ret;
3522 /*****************************************************************************
3523 * EndPagePrinter [WINSPOOL.@]
3525 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3527 FIXME("(%p): stub\n", hPrinter);
3528 return TRUE;
3531 /*****************************************************************************
3532 * StartDocPrinterA [WINSPOOL.@]
3534 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3536 UNICODE_STRING usBuffer;
3537 DOC_INFO_2W doc2W;
3538 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3539 DWORD ret;
3541 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3542 or one (DOC_INFO_3) extra DWORDs */
3544 switch(Level) {
3545 case 2:
3546 doc2W.JobId = doc2->JobId;
3547 /* fall through */
3548 case 3:
3549 doc2W.dwMode = doc2->dwMode;
3550 /* fall through */
3551 case 1:
3552 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3553 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3554 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3555 break;
3557 default:
3558 SetLastError(ERROR_INVALID_LEVEL);
3559 return FALSE;
3562 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3564 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3565 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3566 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3568 return ret;
3571 /*****************************************************************************
3572 * StartDocPrinterW [WINSPOOL.@]
3574 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3576 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3577 opened_printer_t *printer;
3578 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3579 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3580 JOB_INFO_1W job_info;
3581 DWORD needed, ret = 0;
3582 HANDLE hf;
3583 WCHAR *filename;
3584 job_t *job;
3586 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3587 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3588 debugstr_w(doc->pDatatype));
3590 if(Level < 1 || Level > 3)
3592 SetLastError(ERROR_INVALID_LEVEL);
3593 return 0;
3596 EnterCriticalSection(&printer_handles_cs);
3597 printer = get_opened_printer(hPrinter);
3598 if(!printer)
3600 SetLastError(ERROR_INVALID_HANDLE);
3601 goto end;
3604 if(printer->doc)
3606 SetLastError(ERROR_INVALID_PRINTER_STATE);
3607 goto end;
3610 /* Even if we're printing to a file we still add a print job, we'll
3611 just ignore the spool file name */
3613 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3615 ERR("AddJob failed gle %u\n", GetLastError());
3616 goto end;
3619 /* use pOutputFile only, when it is a real filename */
3620 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3621 filename = doc->pOutputFile;
3622 else
3623 filename = addjob->Path;
3625 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3626 if(hf == INVALID_HANDLE_VALUE)
3627 goto end;
3629 memset(&job_info, 0, sizeof(job_info));
3630 job_info.pDocument = doc->pDocName;
3631 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3633 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3634 printer->doc->hf = hf;
3635 ret = printer->doc->job_id = addjob->JobId;
3636 job = get_job(hPrinter, ret);
3637 job->portname = strdupW(doc->pOutputFile);
3639 end:
3640 LeaveCriticalSection(&printer_handles_cs);
3642 return ret;
3645 /*****************************************************************************
3646 * StartPagePrinter [WINSPOOL.@]
3648 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3650 FIXME("(%p): stub\n", hPrinter);
3651 return TRUE;
3654 /*****************************************************************************
3655 * GetFormA [WINSPOOL.@]
3657 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3658 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3660 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3661 Level,pForm,cbBuf,pcbNeeded);
3662 return FALSE;
3665 /*****************************************************************************
3666 * GetFormW [WINSPOOL.@]
3668 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3669 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3671 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3672 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3673 return FALSE;
3676 /*****************************************************************************
3677 * SetFormA [WINSPOOL.@]
3679 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3680 LPBYTE pForm)
3682 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3683 return FALSE;
3686 /*****************************************************************************
3687 * SetFormW [WINSPOOL.@]
3689 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3690 LPBYTE pForm)
3692 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3693 return FALSE;
3696 /*****************************************************************************
3697 * ReadPrinter [WINSPOOL.@]
3699 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3700 LPDWORD pNoBytesRead)
3702 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3703 return FALSE;
3706 /*****************************************************************************
3707 * ResetPrinterA [WINSPOOL.@]
3709 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3711 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3712 return FALSE;
3715 /*****************************************************************************
3716 * ResetPrinterW [WINSPOOL.@]
3718 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3720 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3721 return FALSE;
3724 /*****************************************************************************
3725 * get_filename_from_reg [internal]
3727 * Get ValueName from hkey storing result in out
3728 * when the Value in the registry has only a filename, use driverdir as prefix
3729 * outlen is space left in out
3730 * String is stored either as unicode or ascii
3734 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3735 LPBYTE out, DWORD outlen, LPDWORD needed)
3737 WCHAR filename[MAX_PATH];
3738 DWORD size;
3739 DWORD type;
3740 LONG ret;
3741 LPWSTR buffer = filename;
3742 LPWSTR ptr;
3744 *needed = 0;
3745 size = sizeof(filename);
3746 buffer[0] = '\0';
3747 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3748 if (ret == ERROR_MORE_DATA) {
3749 TRACE("need dynamic buffer: %u\n", size);
3750 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3751 if (!buffer) {
3752 /* No Memory is bad */
3753 return FALSE;
3755 buffer[0] = '\0';
3756 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3759 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3760 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3761 return FALSE;
3764 ptr = buffer;
3765 while (ptr) {
3766 /* do we have a full path ? */
3767 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3768 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3770 if (!ret) {
3771 /* we must build the full Path */
3772 *needed += dirlen;
3773 if ((out) && (outlen > dirlen)) {
3774 lstrcpyW((LPWSTR)out, driverdir);
3775 out += dirlen;
3776 outlen -= dirlen;
3778 else
3779 out = NULL;
3782 /* write the filename */
3783 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3784 if ((out) && (outlen >= size)) {
3785 lstrcpyW((LPWSTR)out, ptr);
3786 out += size;
3787 outlen -= size;
3789 else
3790 out = NULL;
3791 *needed += size;
3792 ptr += lstrlenW(ptr)+1;
3793 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3796 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3798 /* write the multisz-termination */
3799 if (type == REG_MULTI_SZ) {
3800 size = sizeof(WCHAR);
3802 *needed += size;
3803 if (out && (outlen >= size)) {
3804 memset (out, 0, size);
3807 return TRUE;
3810 /*****************************************************************************
3811 * WINSPOOL_GetStringFromReg
3813 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3814 * String is stored as unicode.
3816 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3817 DWORD buflen, DWORD *needed)
3819 DWORD sz = buflen, type;
3820 LONG ret;
3822 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3823 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3824 WARN("Got ret = %d\n", ret);
3825 *needed = 0;
3826 return FALSE;
3828 /* add space for terminating '\0' */
3829 sz += sizeof(WCHAR);
3830 *needed = sz;
3832 if (ptr)
3833 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3835 return TRUE;
3838 /*****************************************************************************
3839 * WINSPOOL_GetDefaultDevMode
3841 * Get a default DevMode values for wineps.
3842 * FIXME - use ppd.
3845 static void WINSPOOL_GetDefaultDevMode(
3846 LPBYTE ptr,
3847 DWORD buflen, DWORD *needed)
3849 DEVMODEW dm;
3850 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3852 /* fill default DEVMODE - should be read from ppd... */
3853 ZeroMemory( &dm, sizeof(dm) );
3854 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3855 dm.dmSpecVersion = DM_SPECVERSION;
3856 dm.dmDriverVersion = 1;
3857 dm.dmSize = sizeof(DEVMODEW);
3858 dm.dmDriverExtra = 0;
3859 dm.dmFields =
3860 DM_ORIENTATION | DM_PAPERSIZE |
3861 DM_PAPERLENGTH | DM_PAPERWIDTH |
3862 DM_SCALE |
3863 DM_COPIES |
3864 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3865 DM_YRESOLUTION | DM_TTOPTION;
3867 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3868 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3869 dm.u1.s1.dmPaperLength = 2970;
3870 dm.u1.s1.dmPaperWidth = 2100;
3872 dm.u1.s1.dmScale = 100;
3873 dm.u1.s1.dmCopies = 1;
3874 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3875 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3876 /* dm.dmColor */
3877 /* dm.dmDuplex */
3878 dm.dmYResolution = 300; /* 300dpi */
3879 dm.dmTTOption = DMTT_BITMAP;
3880 /* dm.dmCollate */
3881 /* dm.dmFormName */
3882 /* dm.dmLogPixels */
3883 /* dm.dmBitsPerPel */
3884 /* dm.dmPelsWidth */
3885 /* dm.dmPelsHeight */
3886 /* dm.u2.dmDisplayFlags */
3887 /* dm.dmDisplayFrequency */
3888 /* dm.dmICMMethod */
3889 /* dm.dmICMIntent */
3890 /* dm.dmMediaType */
3891 /* dm.dmDitherType */
3892 /* dm.dmReserved1 */
3893 /* dm.dmReserved2 */
3894 /* dm.dmPanningWidth */
3895 /* dm.dmPanningHeight */
3897 if(buflen >= sizeof(DEVMODEW))
3898 memcpy(ptr, &dm, sizeof(DEVMODEW));
3899 *needed = sizeof(DEVMODEW);
3902 /*****************************************************************************
3903 * WINSPOOL_GetDevModeFromReg
3905 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3906 * DevMode is stored either as unicode or ascii.
3908 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3909 LPBYTE ptr,
3910 DWORD buflen, DWORD *needed)
3912 DWORD sz = buflen, type;
3913 LONG ret;
3915 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3916 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3917 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3918 if (sz < sizeof(DEVMODEA))
3920 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3921 return FALSE;
3923 /* ensures that dmSize is not erratically bogus if registry is invalid */
3924 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3925 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3926 sz += (CCHDEVICENAME + CCHFORMNAME);
3927 if (ptr && (buflen >= sz)) {
3928 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3929 memcpy(ptr, dmW, sz);
3930 HeapFree(GetProcessHeap(),0,dmW);
3932 *needed = sz;
3933 return TRUE;
3936 /*********************************************************************
3937 * WINSPOOL_GetPrinter_1
3939 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3941 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3942 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3944 DWORD size, left = cbBuf;
3945 BOOL space = (cbBuf > 0);
3946 LPBYTE ptr = buf;
3948 *pcbNeeded = 0;
3950 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3951 if(space && size <= left) {
3952 pi1->pName = (LPWSTR)ptr;
3953 ptr += size;
3954 left -= size;
3955 } else
3956 space = FALSE;
3957 *pcbNeeded += size;
3960 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3961 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3962 if(space && size <= left) {
3963 pi1->pDescription = (LPWSTR)ptr;
3964 ptr += size;
3965 left -= size;
3966 } else
3967 space = FALSE;
3968 *pcbNeeded += size;
3971 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3972 if(space && size <= left) {
3973 pi1->pComment = (LPWSTR)ptr;
3974 ptr += size;
3975 left -= size;
3976 } else
3977 space = FALSE;
3978 *pcbNeeded += size;
3981 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3983 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3984 memset(pi1, 0, sizeof(*pi1));
3986 return space;
3988 /*********************************************************************
3989 * WINSPOOL_GetPrinter_2
3991 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3993 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3994 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3996 DWORD size, left = cbBuf;
3997 BOOL space = (cbBuf > 0);
3998 LPBYTE ptr = buf;
4000 *pcbNeeded = 0;
4002 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4003 if(space && size <= left) {
4004 pi2->pPrinterName = (LPWSTR)ptr;
4005 ptr += size;
4006 left -= size;
4007 } else
4008 space = FALSE;
4009 *pcbNeeded += size;
4011 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4012 if(space && size <= left) {
4013 pi2->pShareName = (LPWSTR)ptr;
4014 ptr += size;
4015 left -= size;
4016 } else
4017 space = FALSE;
4018 *pcbNeeded += size;
4020 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4021 if(space && size <= left) {
4022 pi2->pPortName = (LPWSTR)ptr;
4023 ptr += size;
4024 left -= size;
4025 } else
4026 space = FALSE;
4027 *pcbNeeded += size;
4029 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4030 if(space && size <= left) {
4031 pi2->pDriverName = (LPWSTR)ptr;
4032 ptr += size;
4033 left -= size;
4034 } else
4035 space = FALSE;
4036 *pcbNeeded += size;
4038 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4039 if(space && size <= left) {
4040 pi2->pComment = (LPWSTR)ptr;
4041 ptr += size;
4042 left -= size;
4043 } else
4044 space = FALSE;
4045 *pcbNeeded += size;
4047 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4048 if(space && size <= left) {
4049 pi2->pLocation = (LPWSTR)ptr;
4050 ptr += size;
4051 left -= size;
4052 } else
4053 space = FALSE;
4054 *pcbNeeded += size;
4056 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4057 if(space && size <= left) {
4058 pi2->pDevMode = (LPDEVMODEW)ptr;
4059 ptr += size;
4060 left -= size;
4061 } else
4062 space = FALSE;
4063 *pcbNeeded += size;
4065 else
4067 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4068 if(space && size <= left) {
4069 pi2->pDevMode = (LPDEVMODEW)ptr;
4070 ptr += size;
4071 left -= size;
4072 } else
4073 space = FALSE;
4074 *pcbNeeded += size;
4076 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4077 if(space && size <= left) {
4078 pi2->pSepFile = (LPWSTR)ptr;
4079 ptr += size;
4080 left -= size;
4081 } else
4082 space = FALSE;
4083 *pcbNeeded += size;
4085 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4086 if(space && size <= left) {
4087 pi2->pPrintProcessor = (LPWSTR)ptr;
4088 ptr += size;
4089 left -= size;
4090 } else
4091 space = FALSE;
4092 *pcbNeeded += size;
4094 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4095 if(space && size <= left) {
4096 pi2->pDatatype = (LPWSTR)ptr;
4097 ptr += size;
4098 left -= size;
4099 } else
4100 space = FALSE;
4101 *pcbNeeded += size;
4103 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4104 if(space && size <= left) {
4105 pi2->pParameters = (LPWSTR)ptr;
4106 ptr += size;
4107 left -= size;
4108 } else
4109 space = FALSE;
4110 *pcbNeeded += size;
4112 if(pi2) {
4113 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4114 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4115 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4116 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4117 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4120 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4121 memset(pi2, 0, sizeof(*pi2));
4123 return space;
4126 /*********************************************************************
4127 * WINSPOOL_GetPrinter_4
4129 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4131 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4132 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4134 DWORD size, left = cbBuf;
4135 BOOL space = (cbBuf > 0);
4136 LPBYTE ptr = buf;
4138 *pcbNeeded = 0;
4140 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4141 if(space && size <= left) {
4142 pi4->pPrinterName = (LPWSTR)ptr;
4143 ptr += size;
4144 left -= size;
4145 } else
4146 space = FALSE;
4147 *pcbNeeded += size;
4149 if(pi4) {
4150 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4153 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4154 memset(pi4, 0, sizeof(*pi4));
4156 return space;
4159 /*********************************************************************
4160 * WINSPOOL_GetPrinter_5
4162 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4164 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4165 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4167 DWORD size, left = cbBuf;
4168 BOOL space = (cbBuf > 0);
4169 LPBYTE ptr = buf;
4171 *pcbNeeded = 0;
4173 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4174 if(space && size <= left) {
4175 pi5->pPrinterName = (LPWSTR)ptr;
4176 ptr += size;
4177 left -= size;
4178 } else
4179 space = FALSE;
4180 *pcbNeeded += size;
4182 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4183 if(space && size <= left) {
4184 pi5->pPortName = (LPWSTR)ptr;
4185 ptr += size;
4186 left -= size;
4187 } else
4188 space = FALSE;
4189 *pcbNeeded += size;
4191 if(pi5) {
4192 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4193 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4194 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4197 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4198 memset(pi5, 0, sizeof(*pi5));
4200 return space;
4203 /*********************************************************************
4204 * WINSPOOL_GetPrinter_7
4206 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4208 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4209 DWORD cbBuf, LPDWORD pcbNeeded)
4211 DWORD size, left = cbBuf;
4212 BOOL space = (cbBuf > 0);
4213 LPBYTE ptr = buf;
4215 *pcbNeeded = 0;
4217 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4219 ptr = NULL;
4220 size = sizeof(pi7->pszObjectGUID);
4222 if (space && size <= left) {
4223 pi7->pszObjectGUID = (LPWSTR)ptr;
4224 ptr += size;
4225 left -= size;
4226 } else
4227 space = FALSE;
4228 *pcbNeeded += size;
4229 if (pi7) {
4230 /* We do not have a Directory Service */
4231 pi7->dwAction = DSPRINT_UNPUBLISH;
4234 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4235 memset(pi7, 0, sizeof(*pi7));
4237 return space;
4240 /*********************************************************************
4241 * WINSPOOL_GetPrinter_9
4243 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4245 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4246 DWORD cbBuf, LPDWORD pcbNeeded)
4248 DWORD size;
4249 BOOL space = (cbBuf > 0);
4251 *pcbNeeded = 0;
4253 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4254 if(space && size <= cbBuf) {
4255 pi9->pDevMode = (LPDEVMODEW)buf;
4256 } else
4257 space = FALSE;
4258 *pcbNeeded += size;
4260 else
4262 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4263 if(space && size <= cbBuf) {
4264 pi9->pDevMode = (LPDEVMODEW)buf;
4265 } else
4266 space = FALSE;
4267 *pcbNeeded += size;
4270 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4271 memset(pi9, 0, sizeof(*pi9));
4273 return space;
4276 /*****************************************************************************
4277 * GetPrinterW [WINSPOOL.@]
4279 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4280 DWORD cbBuf, LPDWORD pcbNeeded)
4282 DWORD size, needed = 0, err;
4283 LPBYTE ptr = NULL;
4284 HKEY hkeyPrinter;
4285 BOOL ret;
4287 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4289 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4290 if (err)
4292 SetLastError( err );
4293 return FALSE;
4296 switch(Level) {
4297 case 2:
4299 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4301 size = sizeof(PRINTER_INFO_2W);
4302 if(size <= cbBuf) {
4303 ptr = pPrinter + size;
4304 cbBuf -= size;
4305 memset(pPrinter, 0, size);
4306 } else {
4307 pi2 = NULL;
4308 cbBuf = 0;
4310 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4311 needed += size;
4312 break;
4315 case 4:
4317 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4319 size = sizeof(PRINTER_INFO_4W);
4320 if(size <= cbBuf) {
4321 ptr = pPrinter + size;
4322 cbBuf -= size;
4323 memset(pPrinter, 0, size);
4324 } else {
4325 pi4 = NULL;
4326 cbBuf = 0;
4328 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4329 needed += size;
4330 break;
4334 case 5:
4336 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4338 size = sizeof(PRINTER_INFO_5W);
4339 if(size <= cbBuf) {
4340 ptr = pPrinter + size;
4341 cbBuf -= size;
4342 memset(pPrinter, 0, size);
4343 } else {
4344 pi5 = NULL;
4345 cbBuf = 0;
4348 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4349 needed += size;
4350 break;
4354 case 6:
4356 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4358 size = sizeof(PRINTER_INFO_6);
4359 if (size <= cbBuf) {
4360 /* FIXME: We do not update the status yet */
4361 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4362 ret = TRUE;
4363 } else {
4364 ret = FALSE;
4367 needed += size;
4368 break;
4371 case 7:
4373 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4375 size = sizeof(PRINTER_INFO_7W);
4376 if (size <= cbBuf) {
4377 ptr = pPrinter + size;
4378 cbBuf -= size;
4379 memset(pPrinter, 0, size);
4380 } else {
4381 pi7 = NULL;
4382 cbBuf = 0;
4385 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4386 needed += size;
4387 break;
4391 case 8:
4392 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4393 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4394 /* fall through */
4395 case 9:
4397 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4399 size = sizeof(PRINTER_INFO_9W);
4400 if(size <= cbBuf) {
4401 ptr = pPrinter + size;
4402 cbBuf -= size;
4403 memset(pPrinter, 0, size);
4404 } else {
4405 pi9 = NULL;
4406 cbBuf = 0;
4409 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4410 needed += size;
4411 break;
4415 default:
4416 FIXME("Unimplemented level %d\n", Level);
4417 SetLastError(ERROR_INVALID_LEVEL);
4418 RegCloseKey(hkeyPrinter);
4419 return FALSE;
4422 RegCloseKey(hkeyPrinter);
4424 TRACE("returning %d needed = %d\n", ret, needed);
4425 if(pcbNeeded) *pcbNeeded = needed;
4426 if(!ret)
4427 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4428 return ret;
4431 /*****************************************************************************
4432 * GetPrinterA [WINSPOOL.@]
4434 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4435 DWORD cbBuf, LPDWORD pcbNeeded)
4437 BOOL ret;
4438 LPBYTE buf = NULL;
4440 if (cbBuf)
4441 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4443 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4444 if (ret)
4445 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4446 HeapFree(GetProcessHeap(), 0, buf);
4448 return ret;
4451 /*****************************************************************************
4452 * WINSPOOL_EnumPrintersW
4454 * Implementation of EnumPrintersW
4456 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4457 DWORD dwLevel, LPBYTE lpbPrinters,
4458 DWORD cbBuf, LPDWORD lpdwNeeded,
4459 LPDWORD lpdwReturned)
4462 HKEY hkeyPrinters, hkeyPrinter;
4463 WCHAR PrinterName[255];
4464 DWORD needed = 0, number = 0;
4465 DWORD used, i, left;
4466 PBYTE pi, buf;
4468 if(lpbPrinters)
4469 memset(lpbPrinters, 0, cbBuf);
4470 if(lpdwReturned)
4471 *lpdwReturned = 0;
4472 if(lpdwNeeded)
4473 *lpdwNeeded = 0;
4475 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4476 if(dwType == PRINTER_ENUM_DEFAULT)
4477 return TRUE;
4479 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4480 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4481 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4482 if (!dwType) {
4483 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4484 return TRUE;
4489 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4490 FIXME("dwType = %08x\n", dwType);
4491 SetLastError(ERROR_INVALID_FLAGS);
4492 return FALSE;
4495 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4496 ERROR_SUCCESS) {
4497 ERR("Can't create Printers key\n");
4498 return FALSE;
4501 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4502 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4503 RegCloseKey(hkeyPrinters);
4504 ERR("Can't query Printers key\n");
4505 return FALSE;
4507 TRACE("Found %d printers\n", number);
4509 switch(dwLevel) {
4510 case 1:
4511 used = number * sizeof(PRINTER_INFO_1W);
4512 break;
4513 case 2:
4514 used = number * sizeof(PRINTER_INFO_2W);
4515 break;
4516 case 4:
4517 used = number * sizeof(PRINTER_INFO_4W);
4518 break;
4519 case 5:
4520 used = number * sizeof(PRINTER_INFO_5W);
4521 break;
4523 default:
4524 SetLastError(ERROR_INVALID_LEVEL);
4525 RegCloseKey(hkeyPrinters);
4526 return FALSE;
4528 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4530 for(i = 0; i < number; i++) {
4531 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4532 ERROR_SUCCESS) {
4533 ERR("Can't enum key number %d\n", i);
4534 RegCloseKey(hkeyPrinters);
4535 return FALSE;
4537 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4538 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4539 ERROR_SUCCESS) {
4540 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4541 RegCloseKey(hkeyPrinters);
4542 return FALSE;
4545 if(cbBuf > used) {
4546 buf = lpbPrinters + used;
4547 left = cbBuf - used;
4548 } else {
4549 buf = NULL;
4550 left = 0;
4553 switch(dwLevel) {
4554 case 1:
4555 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4556 left, &needed);
4557 used += needed;
4558 if(pi) pi += sizeof(PRINTER_INFO_1W);
4559 break;
4560 case 2:
4561 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4562 left, &needed);
4563 used += needed;
4564 if(pi) pi += sizeof(PRINTER_INFO_2W);
4565 break;
4566 case 4:
4567 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4568 left, &needed);
4569 used += needed;
4570 if(pi) pi += sizeof(PRINTER_INFO_4W);
4571 break;
4572 case 5:
4573 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4574 left, &needed);
4575 used += needed;
4576 if(pi) pi += sizeof(PRINTER_INFO_5W);
4577 break;
4578 default:
4579 ERR("Shouldn't be here!\n");
4580 RegCloseKey(hkeyPrinter);
4581 RegCloseKey(hkeyPrinters);
4582 return FALSE;
4584 RegCloseKey(hkeyPrinter);
4586 RegCloseKey(hkeyPrinters);
4588 if(lpdwNeeded)
4589 *lpdwNeeded = used;
4591 if(used > cbBuf) {
4592 if(lpbPrinters)
4593 memset(lpbPrinters, 0, cbBuf);
4594 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4595 return FALSE;
4597 if(lpdwReturned)
4598 *lpdwReturned = number;
4599 SetLastError(ERROR_SUCCESS);
4600 return TRUE;
4604 /******************************************************************
4605 * EnumPrintersW [WINSPOOL.@]
4607 * Enumerates the available printers, print servers and print
4608 * providers, depending on the specified flags, name and level.
4610 * RETURNS:
4612 * If level is set to 1:
4613 * Returns an array of PRINTER_INFO_1 data structures in the
4614 * lpbPrinters buffer.
4616 * If level is set to 2:
4617 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4618 * Returns an array of PRINTER_INFO_2 data structures in the
4619 * lpbPrinters buffer. Note that according to MSDN also an
4620 * OpenPrinter should be performed on every remote printer.
4622 * If level is set to 4 (officially WinNT only):
4623 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4624 * Fast: Only the registry is queried to retrieve printer names,
4625 * no connection to the driver is made.
4626 * Returns an array of PRINTER_INFO_4 data structures in the
4627 * lpbPrinters buffer.
4629 * If level is set to 5 (officially WinNT4/Win9x only):
4630 * Fast: Only the registry is queried to retrieve printer names,
4631 * no connection to the driver is made.
4632 * Returns an array of PRINTER_INFO_5 data structures in the
4633 * lpbPrinters buffer.
4635 * If level set to 3 or 6+:
4636 * returns zero (failure!)
4638 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4639 * for information.
4641 * BUGS:
4642 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4643 * - Only levels 2, 4 and 5 are implemented at the moment.
4644 * - 16-bit printer drivers are not enumerated.
4645 * - Returned amount of bytes used/needed does not match the real Windoze
4646 * implementation (as in this implementation, all strings are part
4647 * of the buffer, whereas Win32 keeps them somewhere else)
4648 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4650 * NOTE:
4651 * - In a regular Wine installation, no registry settings for printers
4652 * exist, which makes this function return an empty list.
4654 BOOL WINAPI EnumPrintersW(
4655 DWORD dwType, /* [in] Types of print objects to enumerate */
4656 LPWSTR lpszName, /* [in] name of objects to enumerate */
4657 DWORD dwLevel, /* [in] type of printer info structure */
4658 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4659 DWORD cbBuf, /* [in] max size of buffer in bytes */
4660 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4661 LPDWORD lpdwReturned /* [out] number of entries returned */
4664 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4665 lpdwNeeded, lpdwReturned);
4668 /******************************************************************
4669 * EnumPrintersA [WINSPOOL.@]
4671 * See EnumPrintersW
4674 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4675 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4677 BOOL ret;
4678 UNICODE_STRING pNameU;
4679 LPWSTR pNameW;
4680 LPBYTE pPrintersW;
4682 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4683 pPrinters, cbBuf, pcbNeeded, pcReturned);
4685 pNameW = asciitounicode(&pNameU, pName);
4687 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4688 MS Office need this */
4689 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4691 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4693 RtlFreeUnicodeString(&pNameU);
4694 if (ret) {
4695 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4697 HeapFree(GetProcessHeap(), 0, pPrintersW);
4698 return ret;
4701 /*****************************************************************************
4702 * WINSPOOL_GetDriverInfoFromReg [internal]
4704 * Enters the information from the registry into the DRIVER_INFO struct
4706 * RETURNS
4707 * zero if the printer driver does not exist in the registry
4708 * (only if Level > 1) otherwise nonzero
4710 static BOOL WINSPOOL_GetDriverInfoFromReg(
4711 HKEY hkeyDrivers,
4712 LPWSTR DriverName,
4713 const printenv_t * env,
4714 DWORD Level,
4715 LPBYTE ptr, /* DRIVER_INFO */
4716 LPBYTE pDriverStrings, /* strings buffer */
4717 DWORD cbBuf, /* size of string buffer */
4718 LPDWORD pcbNeeded) /* space needed for str. */
4720 DWORD size, tmp;
4721 HKEY hkeyDriver;
4722 WCHAR driverdir[MAX_PATH];
4723 DWORD dirlen;
4724 LPBYTE strPtr = pDriverStrings;
4725 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4727 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4728 debugstr_w(DriverName), env,
4729 Level, di, pDriverStrings, cbBuf);
4731 if (di) ZeroMemory(di, di_sizeof[Level]);
4733 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4734 if (*pcbNeeded <= cbBuf)
4735 strcpyW((LPWSTR)strPtr, DriverName);
4737 /* pName for level 1 has a different offset! */
4738 if (Level == 1) {
4739 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4740 return TRUE;
4743 /* .cVersion and .pName for level > 1 */
4744 if (di) {
4745 di->cVersion = env->driverversion;
4746 di->pName = (LPWSTR) strPtr;
4747 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4750 /* Reserve Space for the largest subdir and a Backslash*/
4751 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4752 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4753 /* Should never Fail */
4754 return FALSE;
4756 lstrcatW(driverdir, env->versionsubdir);
4757 lstrcatW(driverdir, backslashW);
4759 /* dirlen must not include the terminating zero */
4760 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4762 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4763 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4764 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4765 return FALSE;
4768 /* pEnvironment */
4769 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4771 *pcbNeeded += size;
4772 if (*pcbNeeded <= cbBuf) {
4773 lstrcpyW((LPWSTR)strPtr, env->envname);
4774 if (di) di->pEnvironment = (LPWSTR)strPtr;
4775 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4778 /* .pDriverPath is the Graphics rendering engine.
4779 The full Path is required to avoid a crash in some apps */
4780 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4781 *pcbNeeded += size;
4782 if (*pcbNeeded <= cbBuf)
4783 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4785 if (di) di->pDriverPath = (LPWSTR)strPtr;
4786 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4789 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4790 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4791 *pcbNeeded += size;
4792 if (*pcbNeeded <= cbBuf)
4793 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4795 if (di) di->pDataFile = (LPWSTR)strPtr;
4796 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4799 /* .pConfigFile is the Driver user Interface */
4800 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4801 *pcbNeeded += size;
4802 if (*pcbNeeded <= cbBuf)
4803 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4805 if (di) di->pConfigFile = (LPWSTR)strPtr;
4806 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4809 if (Level == 2 ) {
4810 RegCloseKey(hkeyDriver);
4811 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4812 return TRUE;
4815 if (Level == 5 ) {
4816 RegCloseKey(hkeyDriver);
4817 FIXME("level 5: incomplete\n");
4818 return TRUE;
4821 /* .pHelpFile */
4822 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4823 *pcbNeeded += size;
4824 if (*pcbNeeded <= cbBuf)
4825 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4827 if (di) di->pHelpFile = (LPWSTR)strPtr;
4828 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4831 /* .pDependentFiles */
4832 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4833 *pcbNeeded += size;
4834 if (*pcbNeeded <= cbBuf)
4835 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4837 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4838 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4840 else if (GetVersion() & 0x80000000) {
4841 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4842 size = 2 * sizeof(WCHAR);
4843 *pcbNeeded += size;
4844 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4846 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4847 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4850 /* .pMonitorName is the optional Language Monitor */
4851 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4852 *pcbNeeded += size;
4853 if (*pcbNeeded <= cbBuf)
4854 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4856 if (di) di->pMonitorName = (LPWSTR)strPtr;
4857 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4860 /* .pDefaultDataType */
4861 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4862 *pcbNeeded += size;
4863 if(*pcbNeeded <= cbBuf)
4864 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4866 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4867 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4870 if (Level == 3 ) {
4871 RegCloseKey(hkeyDriver);
4872 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4873 return TRUE;
4876 /* .pszzPreviousNames */
4877 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4878 *pcbNeeded += size;
4879 if(*pcbNeeded <= cbBuf)
4880 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4882 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4883 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4886 if (Level == 4 ) {
4887 RegCloseKey(hkeyDriver);
4888 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4889 return TRUE;
4892 /* support is missing, but not important enough for a FIXME */
4893 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4895 /* .pszMfgName */
4896 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4897 *pcbNeeded += size;
4898 if(*pcbNeeded <= cbBuf)
4899 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4901 if (di) di->pszMfgName = (LPWSTR)strPtr;
4902 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4905 /* .pszOEMUrl */
4906 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4907 *pcbNeeded += size;
4908 if(*pcbNeeded <= cbBuf)
4909 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4911 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4912 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4915 /* .pszHardwareID */
4916 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4917 *pcbNeeded += size;
4918 if(*pcbNeeded <= cbBuf)
4919 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4921 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4922 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4925 /* .pszProvider */
4926 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4927 *pcbNeeded += size;
4928 if(*pcbNeeded <= cbBuf)
4929 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4931 if (di) di->pszProvider = (LPWSTR)strPtr;
4932 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4935 if (Level == 6 ) {
4936 RegCloseKey(hkeyDriver);
4937 return TRUE;
4940 /* support is missing, but not important enough for a FIXME */
4941 TRACE("level 8: incomplete\n");
4943 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4944 RegCloseKey(hkeyDriver);
4945 return TRUE;
4948 /*****************************************************************************
4949 * GetPrinterDriverW [WINSPOOL.@]
4951 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4952 DWORD Level, LPBYTE pDriverInfo,
4953 DWORD cbBuf, LPDWORD pcbNeeded)
4955 LPCWSTR name;
4956 WCHAR DriverName[100];
4957 DWORD ret, type, size, needed = 0;
4958 LPBYTE ptr = NULL;
4959 HKEY hkeyPrinter, hkeyDrivers;
4960 const printenv_t * env;
4962 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4963 Level,pDriverInfo,cbBuf, pcbNeeded);
4965 if (cbBuf > 0)
4966 ZeroMemory(pDriverInfo, cbBuf);
4968 if (!(name = get_opened_printer_name(hPrinter))) {
4969 SetLastError(ERROR_INVALID_HANDLE);
4970 return FALSE;
4973 if (Level < 1 || Level == 7 || Level > 8) {
4974 SetLastError(ERROR_INVALID_LEVEL);
4975 return FALSE;
4978 env = validate_envW(pEnvironment);
4979 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4981 ret = open_printer_reg_key( name, &hkeyPrinter );
4982 if (ret)
4984 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
4985 SetLastError( ret );
4986 return FALSE;
4989 size = sizeof(DriverName);
4990 DriverName[0] = 0;
4991 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4992 (LPBYTE)DriverName, &size);
4993 RegCloseKey(hkeyPrinter);
4994 if(ret != ERROR_SUCCESS) {
4995 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4996 return FALSE;
4999 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5000 if(!hkeyDrivers) {
5001 ERR("Can't create Drivers key\n");
5002 return FALSE;
5005 size = di_sizeof[Level];
5006 if ((size <= cbBuf) && pDriverInfo)
5007 ptr = pDriverInfo + size;
5009 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5010 env, Level, pDriverInfo, ptr,
5011 (cbBuf < size) ? 0 : cbBuf - size,
5012 &needed)) {
5013 RegCloseKey(hkeyDrivers);
5014 return FALSE;
5017 RegCloseKey(hkeyDrivers);
5019 if(pcbNeeded) *pcbNeeded = size + needed;
5020 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5021 if(cbBuf >= size + needed) return TRUE;
5022 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5023 return FALSE;
5026 /*****************************************************************************
5027 * GetPrinterDriverA [WINSPOOL.@]
5029 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5030 DWORD Level, LPBYTE pDriverInfo,
5031 DWORD cbBuf, LPDWORD pcbNeeded)
5033 BOOL ret;
5034 UNICODE_STRING pEnvW;
5035 PWSTR pwstrEnvW;
5036 LPBYTE buf = NULL;
5038 if (cbBuf)
5040 ZeroMemory(pDriverInfo, cbBuf);
5041 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5044 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5045 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5046 cbBuf, pcbNeeded);
5047 if (ret)
5048 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5050 HeapFree(GetProcessHeap(), 0, buf);
5052 RtlFreeUnicodeString(&pEnvW);
5053 return ret;
5056 /*****************************************************************************
5057 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5059 * Return the PATH for the Printer-Drivers (UNICODE)
5061 * PARAMS
5062 * pName [I] Servername (NT only) or NULL (local Computer)
5063 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5064 * Level [I] Structure-Level (must be 1)
5065 * pDriverDirectory [O] PTR to Buffer that receives the Result
5066 * cbBuf [I] Size of Buffer at pDriverDirectory
5067 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5068 * required for pDriverDirectory
5070 * RETURNS
5071 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5072 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5073 * if cbBuf is too small
5075 * Native Values returned in pDriverDirectory on Success:
5076 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5077 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5078 *| win9x(Windows 4.0): "%winsysdir%"
5080 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5082 * FIXME
5083 *- Only NULL or "" is supported for pName
5086 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5087 DWORD Level, LPBYTE pDriverDirectory,
5088 DWORD cbBuf, LPDWORD pcbNeeded)
5090 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5091 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5093 if ((backend == NULL) && !load_backend()) return FALSE;
5095 if (Level != 1) {
5096 /* (Level != 1) is ignored in win9x */
5097 SetLastError(ERROR_INVALID_LEVEL);
5098 return FALSE;
5100 if (pcbNeeded == NULL) {
5101 /* (pcbNeeded == NULL) is ignored in win9x */
5102 SetLastError(RPC_X_NULL_REF_POINTER);
5103 return FALSE;
5106 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5107 pDriverDirectory, cbBuf, pcbNeeded);
5112 /*****************************************************************************
5113 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5115 * Return the PATH for the Printer-Drivers (ANSI)
5117 * See GetPrinterDriverDirectoryW.
5119 * NOTES
5120 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5123 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5124 DWORD Level, LPBYTE pDriverDirectory,
5125 DWORD cbBuf, LPDWORD pcbNeeded)
5127 UNICODE_STRING nameW, environmentW;
5128 BOOL ret;
5129 DWORD pcbNeededW;
5130 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5131 WCHAR *driverDirectoryW = NULL;
5133 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5134 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5136 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5138 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5139 else nameW.Buffer = NULL;
5140 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5141 else environmentW.Buffer = NULL;
5143 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5144 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5145 if (ret) {
5146 DWORD needed;
5147 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5148 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5149 if(pcbNeeded)
5150 *pcbNeeded = needed;
5151 ret = (needed <= cbBuf) ? TRUE : FALSE;
5152 } else
5153 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5155 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5157 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5158 RtlFreeUnicodeString(&environmentW);
5159 RtlFreeUnicodeString(&nameW);
5161 return ret;
5164 /*****************************************************************************
5165 * AddPrinterDriverA [WINSPOOL.@]
5167 * See AddPrinterDriverW.
5170 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5172 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5173 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5176 /******************************************************************************
5177 * AddPrinterDriverW (WINSPOOL.@)
5179 * Install a Printer Driver
5181 * PARAMS
5182 * pName [I] Servername or NULL (local Computer)
5183 * level [I] Level for the supplied DRIVER_INFO_*W struct
5184 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5186 * RESULTS
5187 * Success: TRUE
5188 * Failure: FALSE
5191 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5193 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5194 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5197 /*****************************************************************************
5198 * AddPrintProcessorA [WINSPOOL.@]
5200 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5201 LPSTR pPrintProcessorName)
5203 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5204 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5205 return FALSE;
5208 /*****************************************************************************
5209 * AddPrintProcessorW [WINSPOOL.@]
5211 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5212 LPWSTR pPrintProcessorName)
5214 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5215 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5216 return TRUE;
5219 /*****************************************************************************
5220 * AddPrintProvidorA [WINSPOOL.@]
5222 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5224 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5225 return FALSE;
5228 /*****************************************************************************
5229 * AddPrintProvidorW [WINSPOOL.@]
5231 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5233 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5234 return FALSE;
5237 /*****************************************************************************
5238 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5240 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5241 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5243 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5244 pDevModeOutput, pDevModeInput);
5245 return 0;
5248 /*****************************************************************************
5249 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5251 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5252 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5254 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5255 pDevModeOutput, pDevModeInput);
5256 return 0;
5259 /*****************************************************************************
5260 * PrinterProperties [WINSPOOL.@]
5262 * Displays a dialog to set the properties of the printer.
5264 * RETURNS
5265 * nonzero on success or zero on failure
5267 * BUGS
5268 * implemented as stub only
5270 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5271 HANDLE hPrinter /* [in] handle to printer object */
5273 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5274 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5275 return FALSE;
5278 /*****************************************************************************
5279 * EnumJobsA [WINSPOOL.@]
5282 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5283 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5284 LPDWORD pcReturned)
5286 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5287 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5289 if(pcbNeeded) *pcbNeeded = 0;
5290 if(pcReturned) *pcReturned = 0;
5291 return FALSE;
5295 /*****************************************************************************
5296 * EnumJobsW [WINSPOOL.@]
5299 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5300 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5301 LPDWORD pcReturned)
5303 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5304 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5306 if(pcbNeeded) *pcbNeeded = 0;
5307 if(pcReturned) *pcReturned = 0;
5308 return FALSE;
5311 /*****************************************************************************
5312 * WINSPOOL_EnumPrinterDrivers [internal]
5314 * Delivers information about all printer drivers installed on the
5315 * localhost or a given server
5317 * RETURNS
5318 * nonzero on success or zero on failure. If the buffer for the returned
5319 * information is too small the function will return an error
5321 * BUGS
5322 * - only implemented for localhost, foreign hosts will return an error
5324 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5325 DWORD Level, LPBYTE pDriverInfo,
5326 DWORD driver_index,
5327 DWORD cbBuf, LPDWORD pcbNeeded,
5328 LPDWORD pcFound, DWORD data_offset)
5330 { HKEY hkeyDrivers;
5331 DWORD i, size = 0;
5332 const printenv_t * env;
5334 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5335 debugstr_w(pName), debugstr_w(pEnvironment),
5336 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5338 env = validate_envW(pEnvironment);
5339 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5341 *pcFound = 0;
5343 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5344 if(!hkeyDrivers) {
5345 ERR("Can't open Drivers key\n");
5346 return FALSE;
5349 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5350 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5351 RegCloseKey(hkeyDrivers);
5352 ERR("Can't query Drivers key\n");
5353 return FALSE;
5355 TRACE("Found %d Drivers\n", *pcFound);
5357 /* get size of single struct
5358 * unicode and ascii structure have the same size
5360 size = di_sizeof[Level];
5362 if (data_offset == 0)
5363 data_offset = size * (*pcFound);
5364 *pcbNeeded = data_offset;
5366 for( i = 0; i < *pcFound; i++) {
5367 WCHAR DriverNameW[255];
5368 PBYTE table_ptr = NULL;
5369 PBYTE data_ptr = NULL;
5370 DWORD needed = 0;
5372 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5373 != ERROR_SUCCESS) {
5374 ERR("Can't enum key number %d\n", i);
5375 RegCloseKey(hkeyDrivers);
5376 return FALSE;
5379 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5380 table_ptr = pDriverInfo + (driver_index + i) * size;
5381 if (pDriverInfo && *pcbNeeded <= cbBuf)
5382 data_ptr = pDriverInfo + *pcbNeeded;
5384 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5385 env, Level, table_ptr, data_ptr,
5386 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5387 &needed)) {
5388 RegCloseKey(hkeyDrivers);
5389 return FALSE;
5392 *pcbNeeded += needed;
5395 RegCloseKey(hkeyDrivers);
5397 if(cbBuf < *pcbNeeded){
5398 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5399 return FALSE;
5402 return TRUE;
5405 /*****************************************************************************
5406 * EnumPrinterDriversW [WINSPOOL.@]
5408 * see function EnumPrinterDrivers for RETURNS, BUGS
5410 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5411 LPBYTE pDriverInfo, DWORD cbBuf,
5412 LPDWORD pcbNeeded, LPDWORD pcReturned)
5414 static const WCHAR allW[] = {'a','l','l',0};
5415 BOOL ret;
5416 DWORD found;
5418 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5420 SetLastError(RPC_X_NULL_REF_POINTER);
5421 return FALSE;
5424 /* check for local drivers */
5425 if((pName) && (pName[0])) {
5426 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5427 SetLastError(ERROR_ACCESS_DENIED);
5428 return FALSE;
5431 /* check input parameter */
5432 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5433 SetLastError(ERROR_INVALID_LEVEL);
5434 return FALSE;
5437 if(pDriverInfo && cbBuf > 0)
5438 memset( pDriverInfo, 0, cbBuf);
5440 /* Exception: pull all printers */
5441 if (pEnvironment && !strcmpW(pEnvironment, allW))
5443 DWORD i, needed, bufsize = cbBuf;
5444 DWORD total_needed = 0;
5445 DWORD total_found = 0;
5446 DWORD data_offset;
5448 /* Precompute the overall total; we need this to know
5449 where pointers end and data begins (i.e. data_offset) */
5450 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5452 needed = found = 0;
5453 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5454 NULL, 0, 0, &needed, &found, 0);
5455 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5456 total_needed += needed;
5457 total_found += found;
5460 data_offset = di_sizeof[Level] * total_found;
5462 *pcReturned = 0;
5463 *pcbNeeded = 0;
5464 total_found = 0;
5465 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5467 needed = found = 0;
5468 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5469 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5470 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5471 else if (ret)
5472 *pcReturned += found;
5473 *pcbNeeded = needed;
5474 data_offset = needed;
5475 total_found += found;
5477 return ret;
5480 /* Normal behavior */
5481 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5482 0, cbBuf, pcbNeeded, &found, 0);
5483 if (ret)
5484 *pcReturned = found;
5486 return ret;
5489 /*****************************************************************************
5490 * EnumPrinterDriversA [WINSPOOL.@]
5492 * see function EnumPrinterDrivers for RETURNS, BUGS
5494 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5495 LPBYTE pDriverInfo, DWORD cbBuf,
5496 LPDWORD pcbNeeded, LPDWORD pcReturned)
5498 BOOL ret;
5499 UNICODE_STRING pNameW, pEnvironmentW;
5500 PWSTR pwstrNameW, pwstrEnvironmentW;
5501 LPBYTE buf = NULL;
5503 if (cbBuf)
5504 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5506 pwstrNameW = asciitounicode(&pNameW, pName);
5507 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5509 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5510 buf, cbBuf, pcbNeeded, pcReturned);
5511 if (ret)
5512 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5514 HeapFree(GetProcessHeap(), 0, buf);
5516 RtlFreeUnicodeString(&pNameW);
5517 RtlFreeUnicodeString(&pEnvironmentW);
5519 return ret;
5522 /******************************************************************************
5523 * EnumPortsA (WINSPOOL.@)
5525 * See EnumPortsW.
5528 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5529 LPDWORD pcbNeeded, LPDWORD pcReturned)
5531 BOOL res;
5532 LPBYTE bufferW = NULL;
5533 LPWSTR nameW = NULL;
5534 DWORD needed = 0;
5535 DWORD numentries = 0;
5536 INT len;
5538 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5539 cbBuf, pcbNeeded, pcReturned);
5541 /* convert servername to unicode */
5542 if (pName) {
5543 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5544 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5545 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5547 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5548 needed = cbBuf * sizeof(WCHAR);
5549 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5550 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5552 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5553 if (pcbNeeded) needed = *pcbNeeded;
5554 /* HeapReAlloc return NULL, when bufferW was NULL */
5555 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5556 HeapAlloc(GetProcessHeap(), 0, needed);
5558 /* Try again with the large Buffer */
5559 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5561 needed = pcbNeeded ? *pcbNeeded : 0;
5562 numentries = pcReturned ? *pcReturned : 0;
5565 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5566 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5568 if (res) {
5569 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5570 DWORD entrysize = 0;
5571 DWORD index;
5572 LPSTR ptr;
5573 LPPORT_INFO_2W pi2w;
5574 LPPORT_INFO_2A pi2a;
5576 needed = 0;
5577 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5579 /* First pass: calculate the size for all Entries */
5580 pi2w = (LPPORT_INFO_2W) bufferW;
5581 pi2a = (LPPORT_INFO_2A) pPorts;
5582 index = 0;
5583 while (index < numentries) {
5584 index++;
5585 needed += entrysize; /* PORT_INFO_?A */
5586 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5588 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5589 NULL, 0, NULL, NULL);
5590 if (Level > 1) {
5591 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5592 NULL, 0, NULL, NULL);
5593 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5594 NULL, 0, NULL, NULL);
5596 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5597 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5598 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5601 /* check for errors and quit on failure */
5602 if (cbBuf < needed) {
5603 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5604 res = FALSE;
5605 goto cleanup;
5607 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5608 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5609 cbBuf -= len ; /* free Bytes in the user-Buffer */
5610 pi2w = (LPPORT_INFO_2W) bufferW;
5611 pi2a = (LPPORT_INFO_2A) pPorts;
5612 index = 0;
5613 /* Second Pass: Fill the User Buffer (if we have one) */
5614 while ((index < numentries) && pPorts) {
5615 index++;
5616 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5617 pi2a->pPortName = ptr;
5618 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5619 ptr, cbBuf , NULL, NULL);
5620 ptr += len;
5621 cbBuf -= len;
5622 if (Level > 1) {
5623 pi2a->pMonitorName = ptr;
5624 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5625 ptr, cbBuf, NULL, NULL);
5626 ptr += len;
5627 cbBuf -= len;
5629 pi2a->pDescription = ptr;
5630 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5631 ptr, cbBuf, NULL, NULL);
5632 ptr += len;
5633 cbBuf -= len;
5635 pi2a->fPortType = pi2w->fPortType;
5636 pi2a->Reserved = 0; /* documented: "must be zero" */
5639 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5640 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5641 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5645 cleanup:
5646 if (pcbNeeded) *pcbNeeded = needed;
5647 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5649 HeapFree(GetProcessHeap(), 0, nameW);
5650 HeapFree(GetProcessHeap(), 0, bufferW);
5652 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5653 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5655 return (res);
5659 /******************************************************************************
5660 * EnumPortsW (WINSPOOL.@)
5662 * Enumerate available Ports
5664 * PARAMS
5665 * pName [I] Servername or NULL (local Computer)
5666 * Level [I] Structure-Level (1 or 2)
5667 * pPorts [O] PTR to Buffer that receives the Result
5668 * cbBuf [I] Size of Buffer at pPorts
5669 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5670 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5672 * RETURNS
5673 * Success: TRUE
5674 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5677 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5680 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5681 cbBuf, pcbNeeded, pcReturned);
5683 if ((backend == NULL) && !load_backend()) return FALSE;
5685 /* Level is not checked in win9x */
5686 if (!Level || (Level > 2)) {
5687 WARN("level (%d) is ignored in win9x\n", Level);
5688 SetLastError(ERROR_INVALID_LEVEL);
5689 return FALSE;
5691 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5692 SetLastError(RPC_X_NULL_REF_POINTER);
5693 return FALSE;
5696 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5699 /******************************************************************************
5700 * GetDefaultPrinterW (WINSPOOL.@)
5702 * FIXME
5703 * This function must read the value from data 'device' of key
5704 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5706 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5708 BOOL retval = TRUE;
5709 DWORD insize, len;
5710 WCHAR *buffer, *ptr;
5712 if (!namesize)
5714 SetLastError(ERROR_INVALID_PARAMETER);
5715 return FALSE;
5718 /* make the buffer big enough for the stuff from the profile/registry,
5719 * the content must fit into the local buffer to compute the correct
5720 * size even if the extern buffer is too small or not given.
5721 * (20 for ,driver,port) */
5722 insize = *namesize;
5723 len = max(100, (insize + 20));
5724 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5726 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5728 SetLastError (ERROR_FILE_NOT_FOUND);
5729 retval = FALSE;
5730 goto end;
5732 TRACE("%s\n", debugstr_w(buffer));
5734 if ((ptr = strchrW(buffer, ',')) == NULL)
5736 SetLastError(ERROR_INVALID_NAME);
5737 retval = FALSE;
5738 goto end;
5741 *ptr = 0;
5742 *namesize = strlenW(buffer) + 1;
5743 if(!name || (*namesize > insize))
5745 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5746 retval = FALSE;
5747 goto end;
5749 strcpyW(name, buffer);
5751 end:
5752 HeapFree( GetProcessHeap(), 0, buffer);
5753 return retval;
5757 /******************************************************************************
5758 * GetDefaultPrinterA (WINSPOOL.@)
5760 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5762 BOOL retval = TRUE;
5763 DWORD insize = 0;
5764 WCHAR *bufferW = NULL;
5766 if (!namesize)
5768 SetLastError(ERROR_INVALID_PARAMETER);
5769 return FALSE;
5772 if(name && *namesize) {
5773 insize = *namesize;
5774 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5777 if(!GetDefaultPrinterW( bufferW, namesize)) {
5778 retval = FALSE;
5779 goto end;
5782 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5783 NULL, NULL);
5784 if (!*namesize)
5786 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5787 retval = FALSE;
5789 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5791 end:
5792 HeapFree( GetProcessHeap(), 0, bufferW);
5793 return retval;
5797 /******************************************************************************
5798 * SetDefaultPrinterW (WINSPOOL.204)
5800 * Set the Name of the Default Printer
5802 * PARAMS
5803 * pszPrinter [I] Name of the Printer or NULL
5805 * RETURNS
5806 * Success: True
5807 * Failure: FALSE
5809 * NOTES
5810 * When the Parameter is NULL or points to an Empty String and
5811 * a Default Printer was already present, then this Function changes nothing.
5812 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5813 * the First enumerated local Printer is used.
5816 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5818 WCHAR default_printer[MAX_PATH];
5819 LPWSTR buffer = NULL;
5820 HKEY hreg;
5821 DWORD size;
5822 DWORD namelen;
5823 LONG lres;
5825 TRACE("(%s)\n", debugstr_w(pszPrinter));
5826 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5828 default_printer[0] = '\0';
5829 size = sizeof(default_printer)/sizeof(WCHAR);
5831 /* if we have a default Printer, do nothing. */
5832 if (GetDefaultPrinterW(default_printer, &size))
5833 return TRUE;
5835 pszPrinter = NULL;
5836 /* we have no default Printer: search local Printers and use the first */
5837 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5839 default_printer[0] = '\0';
5840 size = sizeof(default_printer)/sizeof(WCHAR);
5841 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5843 pszPrinter = default_printer;
5844 TRACE("using %s\n", debugstr_w(pszPrinter));
5846 RegCloseKey(hreg);
5849 if (pszPrinter == NULL) {
5850 TRACE("no local printer found\n");
5851 SetLastError(ERROR_FILE_NOT_FOUND);
5852 return FALSE;
5856 /* "pszPrinter" is never empty or NULL here. */
5857 namelen = lstrlenW(pszPrinter);
5858 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5859 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5860 if (!buffer ||
5861 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5862 HeapFree(GetProcessHeap(), 0, buffer);
5863 SetLastError(ERROR_FILE_NOT_FOUND);
5864 return FALSE;
5867 /* read the devices entry for the printer (driver,port) to build the string for the
5868 default device entry (printer,driver,port) */
5869 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5870 buffer[namelen] = ',';
5871 namelen++; /* move index to the start of the driver */
5873 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5874 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5875 if (!lres) {
5876 TRACE("set device to %s\n", debugstr_w(buffer));
5878 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5879 TRACE("failed to set the device entry: %d\n", GetLastError());
5880 lres = ERROR_INVALID_PRINTER_NAME;
5883 /* remove the next section, when INIFileMapping is implemented */
5885 HKEY hdev;
5886 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5887 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5888 RegCloseKey(hdev);
5892 else
5894 if (lres != ERROR_FILE_NOT_FOUND)
5895 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5897 SetLastError(ERROR_INVALID_PRINTER_NAME);
5900 RegCloseKey(hreg);
5901 HeapFree(GetProcessHeap(), 0, buffer);
5902 return (lres == ERROR_SUCCESS);
5905 /******************************************************************************
5906 * SetDefaultPrinterA (WINSPOOL.202)
5908 * See SetDefaultPrinterW.
5911 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5913 LPWSTR bufferW = NULL;
5914 BOOL res;
5916 TRACE("(%s)\n", debugstr_a(pszPrinter));
5917 if(pszPrinter) {
5918 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5919 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5920 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5922 res = SetDefaultPrinterW(bufferW);
5923 HeapFree(GetProcessHeap(), 0, bufferW);
5924 return res;
5927 /******************************************************************************
5928 * SetPrinterDataExA (WINSPOOL.@)
5930 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5931 LPCSTR pValueName, DWORD Type,
5932 LPBYTE pData, DWORD cbData)
5934 HKEY hkeyPrinter, hkeySubkey;
5935 DWORD ret;
5937 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5938 debugstr_a(pValueName), Type, pData, cbData);
5940 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5941 != ERROR_SUCCESS)
5942 return ret;
5944 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5945 != ERROR_SUCCESS) {
5946 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5947 RegCloseKey(hkeyPrinter);
5948 return ret;
5950 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5951 RegCloseKey(hkeySubkey);
5952 RegCloseKey(hkeyPrinter);
5953 return ret;
5956 /******************************************************************************
5957 * SetPrinterDataExW (WINSPOOL.@)
5959 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5960 LPCWSTR pValueName, DWORD Type,
5961 LPBYTE pData, DWORD cbData)
5963 HKEY hkeyPrinter, hkeySubkey;
5964 DWORD ret;
5966 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5967 debugstr_w(pValueName), Type, pData, cbData);
5969 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5970 != ERROR_SUCCESS)
5971 return ret;
5973 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5974 != ERROR_SUCCESS) {
5975 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5976 RegCloseKey(hkeyPrinter);
5977 return ret;
5979 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5980 RegCloseKey(hkeySubkey);
5981 RegCloseKey(hkeyPrinter);
5982 return ret;
5985 /******************************************************************************
5986 * SetPrinterDataA (WINSPOOL.@)
5988 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5989 LPBYTE pData, DWORD cbData)
5991 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5992 pData, cbData);
5995 /******************************************************************************
5996 * SetPrinterDataW (WINSPOOL.@)
5998 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5999 LPBYTE pData, DWORD cbData)
6001 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6002 pData, cbData);
6005 /******************************************************************************
6006 * GetPrinterDataExA (WINSPOOL.@)
6008 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6009 LPCSTR pValueName, LPDWORD pType,
6010 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6012 opened_printer_t *printer;
6013 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6014 DWORD ret;
6016 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6017 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6019 printer = get_opened_printer(hPrinter);
6020 if(!printer) return ERROR_INVALID_HANDLE;
6022 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6023 if (ret) return ret;
6025 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6027 if (printer->name) {
6029 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6030 if (ret) {
6031 RegCloseKey(hkeyPrinters);
6032 return ret;
6034 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6035 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6036 RegCloseKey(hkeyPrinter);
6037 RegCloseKey(hkeyPrinters);
6038 return ret;
6041 *pcbNeeded = nSize;
6042 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6043 0, pType, pData, pcbNeeded);
6045 if (!ret && !pData) ret = ERROR_MORE_DATA;
6047 RegCloseKey(hkeySubkey);
6048 RegCloseKey(hkeyPrinter);
6049 RegCloseKey(hkeyPrinters);
6051 TRACE("--> %d\n", ret);
6052 return ret;
6055 /******************************************************************************
6056 * GetPrinterDataExW (WINSPOOL.@)
6058 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6059 LPCWSTR pValueName, LPDWORD pType,
6060 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6062 opened_printer_t *printer;
6063 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6064 DWORD ret;
6066 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6067 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6069 printer = get_opened_printer(hPrinter);
6070 if(!printer) return ERROR_INVALID_HANDLE;
6072 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6073 if (ret) return ret;
6075 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6077 if (printer->name) {
6079 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6080 if (ret) {
6081 RegCloseKey(hkeyPrinters);
6082 return ret;
6084 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6085 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6086 RegCloseKey(hkeyPrinter);
6087 RegCloseKey(hkeyPrinters);
6088 return ret;
6091 *pcbNeeded = nSize;
6092 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6093 0, pType, pData, pcbNeeded);
6095 if (!ret && !pData) ret = ERROR_MORE_DATA;
6097 RegCloseKey(hkeySubkey);
6098 RegCloseKey(hkeyPrinter);
6099 RegCloseKey(hkeyPrinters);
6101 TRACE("--> %d\n", ret);
6102 return ret;
6105 /******************************************************************************
6106 * GetPrinterDataA (WINSPOOL.@)
6108 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6109 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6111 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6112 pData, nSize, pcbNeeded);
6115 /******************************************************************************
6116 * GetPrinterDataW (WINSPOOL.@)
6118 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6119 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6121 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6122 pData, nSize, pcbNeeded);
6125 /*******************************************************************************
6126 * EnumPrinterDataExW [WINSPOOL.@]
6128 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6129 LPBYTE pEnumValues, DWORD cbEnumValues,
6130 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6132 HKEY hkPrinter, hkSubKey;
6133 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6134 cbValueNameLen, cbMaxValueLen, cbValueLen,
6135 cbBufSize, dwType;
6136 LPWSTR lpValueName;
6137 HANDLE hHeap;
6138 PBYTE lpValue;
6139 PPRINTER_ENUM_VALUESW ppev;
6141 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6143 if (pKeyName == NULL || *pKeyName == 0)
6144 return ERROR_INVALID_PARAMETER;
6146 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6147 if (ret != ERROR_SUCCESS)
6149 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6150 hPrinter, ret);
6151 return ret;
6154 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6155 if (ret != ERROR_SUCCESS)
6157 r = RegCloseKey (hkPrinter);
6158 if (r != ERROR_SUCCESS)
6159 WARN ("RegCloseKey returned %i\n", r);
6160 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6161 debugstr_w (pKeyName), ret);
6162 return ret;
6165 ret = RegCloseKey (hkPrinter);
6166 if (ret != ERROR_SUCCESS)
6168 ERR ("RegCloseKey returned %i\n", ret);
6169 r = RegCloseKey (hkSubKey);
6170 if (r != ERROR_SUCCESS)
6171 WARN ("RegCloseKey returned %i\n", r);
6172 return ret;
6175 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6176 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6177 if (ret != ERROR_SUCCESS)
6179 r = RegCloseKey (hkSubKey);
6180 if (r != ERROR_SUCCESS)
6181 WARN ("RegCloseKey returned %i\n", r);
6182 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6183 return ret;
6186 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6187 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6189 if (cValues == 0) /* empty key */
6191 r = RegCloseKey (hkSubKey);
6192 if (r != ERROR_SUCCESS)
6193 WARN ("RegCloseKey returned %i\n", r);
6194 *pcbEnumValues = *pnEnumValues = 0;
6195 return ERROR_SUCCESS;
6198 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6200 hHeap = GetProcessHeap ();
6201 if (hHeap == NULL)
6203 ERR ("GetProcessHeap failed\n");
6204 r = RegCloseKey (hkSubKey);
6205 if (r != ERROR_SUCCESS)
6206 WARN ("RegCloseKey returned %i\n", r);
6207 return ERROR_OUTOFMEMORY;
6210 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6211 if (lpValueName == NULL)
6213 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6214 r = RegCloseKey (hkSubKey);
6215 if (r != ERROR_SUCCESS)
6216 WARN ("RegCloseKey returned %i\n", r);
6217 return ERROR_OUTOFMEMORY;
6220 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6221 if (lpValue == NULL)
6223 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6224 if (HeapFree (hHeap, 0, lpValueName) == 0)
6225 WARN ("HeapFree failed with code %i\n", GetLastError ());
6226 r = RegCloseKey (hkSubKey);
6227 if (r != ERROR_SUCCESS)
6228 WARN ("RegCloseKey returned %i\n", r);
6229 return ERROR_OUTOFMEMORY;
6232 TRACE ("pass 1: calculating buffer required for all names and values\n");
6234 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6236 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6238 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6240 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6241 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6242 NULL, NULL, lpValue, &cbValueLen);
6243 if (ret != ERROR_SUCCESS)
6245 if (HeapFree (hHeap, 0, lpValue) == 0)
6246 WARN ("HeapFree failed with code %i\n", GetLastError ());
6247 if (HeapFree (hHeap, 0, lpValueName) == 0)
6248 WARN ("HeapFree failed with code %i\n", GetLastError ());
6249 r = RegCloseKey (hkSubKey);
6250 if (r != ERROR_SUCCESS)
6251 WARN ("RegCloseKey returned %i\n", r);
6252 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6253 return ret;
6256 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6257 debugstr_w (lpValueName), dwIndex,
6258 cbValueNameLen + 1, cbValueLen);
6260 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6261 cbBufSize += cbValueLen;
6264 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6266 *pcbEnumValues = cbBufSize;
6267 *pnEnumValues = cValues;
6269 if (cbEnumValues < cbBufSize) /* buffer too small */
6271 if (HeapFree (hHeap, 0, lpValue) == 0)
6272 WARN ("HeapFree failed with code %i\n", GetLastError ());
6273 if (HeapFree (hHeap, 0, lpValueName) == 0)
6274 WARN ("HeapFree failed with code %i\n", GetLastError ());
6275 r = RegCloseKey (hkSubKey);
6276 if (r != ERROR_SUCCESS)
6277 WARN ("RegCloseKey returned %i\n", r);
6278 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6279 return ERROR_MORE_DATA;
6282 TRACE ("pass 2: copying all names and values to buffer\n");
6284 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6285 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6287 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6289 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6290 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6291 NULL, &dwType, lpValue, &cbValueLen);
6292 if (ret != ERROR_SUCCESS)
6294 if (HeapFree (hHeap, 0, lpValue) == 0)
6295 WARN ("HeapFree failed with code %i\n", GetLastError ());
6296 if (HeapFree (hHeap, 0, lpValueName) == 0)
6297 WARN ("HeapFree failed with code %i\n", GetLastError ());
6298 r = RegCloseKey (hkSubKey);
6299 if (r != ERROR_SUCCESS)
6300 WARN ("RegCloseKey returned %i\n", r);
6301 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6302 return ret;
6305 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6306 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6307 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6308 pEnumValues += cbValueNameLen;
6310 /* return # of *bytes* (including trailing \0), not # of chars */
6311 ppev[dwIndex].cbValueName = cbValueNameLen;
6313 ppev[dwIndex].dwType = dwType;
6315 memcpy (pEnumValues, lpValue, cbValueLen);
6316 ppev[dwIndex].pData = pEnumValues;
6317 pEnumValues += cbValueLen;
6319 ppev[dwIndex].cbData = cbValueLen;
6321 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6322 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6325 if (HeapFree (hHeap, 0, lpValue) == 0)
6327 ret = GetLastError ();
6328 ERR ("HeapFree failed with code %i\n", ret);
6329 if (HeapFree (hHeap, 0, lpValueName) == 0)
6330 WARN ("HeapFree failed with code %i\n", GetLastError ());
6331 r = RegCloseKey (hkSubKey);
6332 if (r != ERROR_SUCCESS)
6333 WARN ("RegCloseKey returned %i\n", r);
6334 return ret;
6337 if (HeapFree (hHeap, 0, lpValueName) == 0)
6339 ret = GetLastError ();
6340 ERR ("HeapFree failed with code %i\n", ret);
6341 r = RegCloseKey (hkSubKey);
6342 if (r != ERROR_SUCCESS)
6343 WARN ("RegCloseKey returned %i\n", r);
6344 return ret;
6347 ret = RegCloseKey (hkSubKey);
6348 if (ret != ERROR_SUCCESS)
6350 ERR ("RegCloseKey returned %i\n", ret);
6351 return ret;
6354 return ERROR_SUCCESS;
6357 /*******************************************************************************
6358 * EnumPrinterDataExA [WINSPOOL.@]
6360 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6361 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6362 * what Windows 2000 SP1 does.
6365 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6366 LPBYTE pEnumValues, DWORD cbEnumValues,
6367 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6369 INT len;
6370 LPWSTR pKeyNameW;
6371 DWORD ret, dwIndex, dwBufSize;
6372 HANDLE hHeap;
6373 LPSTR pBuffer;
6375 TRACE ("%p %s\n", hPrinter, pKeyName);
6377 if (pKeyName == NULL || *pKeyName == 0)
6378 return ERROR_INVALID_PARAMETER;
6380 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6381 if (len == 0)
6383 ret = GetLastError ();
6384 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6385 return ret;
6388 hHeap = GetProcessHeap ();
6389 if (hHeap == NULL)
6391 ERR ("GetProcessHeap failed\n");
6392 return ERROR_OUTOFMEMORY;
6395 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6396 if (pKeyNameW == NULL)
6398 ERR ("Failed to allocate %i bytes from process heap\n",
6399 (LONG)(len * sizeof (WCHAR)));
6400 return ERROR_OUTOFMEMORY;
6403 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6405 ret = GetLastError ();
6406 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6407 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6408 WARN ("HeapFree failed with code %i\n", GetLastError ());
6409 return ret;
6412 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6413 pcbEnumValues, pnEnumValues);
6414 if (ret != ERROR_SUCCESS)
6416 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6417 WARN ("HeapFree failed with code %i\n", GetLastError ());
6418 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6419 return ret;
6422 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6424 ret = GetLastError ();
6425 ERR ("HeapFree failed with code %i\n", ret);
6426 return ret;
6429 if (*pnEnumValues == 0) /* empty key */
6430 return ERROR_SUCCESS;
6432 dwBufSize = 0;
6433 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6435 PPRINTER_ENUM_VALUESW ppev =
6436 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6438 if (dwBufSize < ppev->cbValueName)
6439 dwBufSize = ppev->cbValueName;
6441 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6442 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6443 dwBufSize = ppev->cbData;
6446 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6448 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6449 if (pBuffer == NULL)
6451 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6452 return ERROR_OUTOFMEMORY;
6455 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6457 PPRINTER_ENUM_VALUESW ppev =
6458 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6460 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6461 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6462 NULL);
6463 if (len == 0)
6465 ret = GetLastError ();
6466 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6467 if (HeapFree (hHeap, 0, pBuffer) == 0)
6468 WARN ("HeapFree failed with code %i\n", GetLastError ());
6469 return ret;
6472 memcpy (ppev->pValueName, pBuffer, len);
6474 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6476 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6477 ppev->dwType != REG_MULTI_SZ)
6478 continue;
6480 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6481 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6482 if (len == 0)
6484 ret = GetLastError ();
6485 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6486 if (HeapFree (hHeap, 0, pBuffer) == 0)
6487 WARN ("HeapFree failed with code %i\n", GetLastError ());
6488 return ret;
6491 memcpy (ppev->pData, pBuffer, len);
6493 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6494 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6497 if (HeapFree (hHeap, 0, pBuffer) == 0)
6499 ret = GetLastError ();
6500 ERR ("HeapFree failed with code %i\n", ret);
6501 return ret;
6504 return ERROR_SUCCESS;
6507 /******************************************************************************
6508 * AbortPrinter (WINSPOOL.@)
6510 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6512 FIXME("(%p), stub!\n", hPrinter);
6513 return TRUE;
6516 /******************************************************************************
6517 * AddPortA (WINSPOOL.@)
6519 * See AddPortW.
6522 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6524 LPWSTR nameW = NULL;
6525 LPWSTR monitorW = NULL;
6526 DWORD len;
6527 BOOL res;
6529 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6531 if (pName) {
6532 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6533 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6534 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6537 if (pMonitorName) {
6538 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6539 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6540 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6542 res = AddPortW(nameW, hWnd, monitorW);
6543 HeapFree(GetProcessHeap(), 0, nameW);
6544 HeapFree(GetProcessHeap(), 0, monitorW);
6545 return res;
6548 /******************************************************************************
6549 * AddPortW (WINSPOOL.@)
6551 * Add a Port for a specific Monitor
6553 * PARAMS
6554 * pName [I] Servername or NULL (local Computer)
6555 * hWnd [I] Handle to parent Window for the Dialog-Box
6556 * pMonitorName [I] Name of the Monitor that manage the Port
6558 * RETURNS
6559 * Success: TRUE
6560 * Failure: FALSE
6563 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6565 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6567 if ((backend == NULL) && !load_backend()) return FALSE;
6569 if (!pMonitorName) {
6570 SetLastError(RPC_X_NULL_REF_POINTER);
6571 return FALSE;
6574 return backend->fpAddPort(pName, hWnd, pMonitorName);
6577 /******************************************************************************
6578 * AddPortExA (WINSPOOL.@)
6580 * See AddPortExW.
6583 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6585 PORT_INFO_2W pi2W;
6586 PORT_INFO_2A * pi2A;
6587 LPWSTR nameW = NULL;
6588 LPWSTR monitorW = NULL;
6589 DWORD len;
6590 BOOL res;
6592 pi2A = (PORT_INFO_2A *) pBuffer;
6594 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6595 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6597 if ((level < 1) || (level > 2)) {
6598 SetLastError(ERROR_INVALID_LEVEL);
6599 return FALSE;
6602 if (!pi2A) {
6603 SetLastError(ERROR_INVALID_PARAMETER);
6604 return FALSE;
6607 if (pName) {
6608 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6609 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6610 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6613 if (pMonitorName) {
6614 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6615 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6616 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6619 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6621 if (pi2A->pPortName) {
6622 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6623 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6624 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6627 if (level > 1) {
6628 if (pi2A->pMonitorName) {
6629 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6630 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6631 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6634 if (pi2A->pDescription) {
6635 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6636 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6637 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6639 pi2W.fPortType = pi2A->fPortType;
6640 pi2W.Reserved = pi2A->Reserved;
6643 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6645 HeapFree(GetProcessHeap(), 0, nameW);
6646 HeapFree(GetProcessHeap(), 0, monitorW);
6647 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6648 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6649 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6650 return res;
6654 /******************************************************************************
6655 * AddPortExW (WINSPOOL.@)
6657 * Add a Port for a specific Monitor, without presenting a user interface
6659 * PARAMS
6660 * pName [I] Servername or NULL (local Computer)
6661 * level [I] Structure-Level (1 or 2) for pBuffer
6662 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6663 * pMonitorName [I] Name of the Monitor that manage the Port
6665 * RETURNS
6666 * Success: TRUE
6667 * Failure: FALSE
6670 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6672 PORT_INFO_2W * pi2;
6674 pi2 = (PORT_INFO_2W *) pBuffer;
6676 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6677 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6678 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6679 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6681 if ((backend == NULL) && !load_backend()) return FALSE;
6683 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6684 SetLastError(ERROR_INVALID_PARAMETER);
6685 return FALSE;
6688 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6691 /******************************************************************************
6692 * AddPrinterConnectionA (WINSPOOL.@)
6694 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6696 FIXME("%s\n", debugstr_a(pName));
6697 return FALSE;
6700 /******************************************************************************
6701 * AddPrinterConnectionW (WINSPOOL.@)
6703 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6705 FIXME("%s\n", debugstr_w(pName));
6706 return FALSE;
6709 /******************************************************************************
6710 * AddPrinterDriverExW (WINSPOOL.@)
6712 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6714 * PARAMS
6715 * pName [I] Servername or NULL (local Computer)
6716 * level [I] Level for the supplied DRIVER_INFO_*W struct
6717 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6718 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6720 * RESULTS
6721 * Success: TRUE
6722 * Failure: FALSE
6725 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6727 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6729 if ((backend == NULL) && !load_backend()) return FALSE;
6731 if (level < 2 || level == 5 || level == 7 || level > 8) {
6732 SetLastError(ERROR_INVALID_LEVEL);
6733 return FALSE;
6736 if (!pDriverInfo) {
6737 SetLastError(ERROR_INVALID_PARAMETER);
6738 return FALSE;
6741 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6744 /******************************************************************************
6745 * AddPrinterDriverExA (WINSPOOL.@)
6747 * See AddPrinterDriverExW.
6750 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6752 DRIVER_INFO_8A *diA;
6753 DRIVER_INFO_8W diW;
6754 LPWSTR nameW = NULL;
6755 DWORD lenA;
6756 DWORD len;
6757 DWORD res = FALSE;
6759 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6761 diA = (DRIVER_INFO_8A *) pDriverInfo;
6762 ZeroMemory(&diW, sizeof(diW));
6764 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6765 SetLastError(ERROR_INVALID_LEVEL);
6766 return FALSE;
6769 if (diA == NULL) {
6770 SetLastError(ERROR_INVALID_PARAMETER);
6771 return FALSE;
6774 /* convert servername to unicode */
6775 if (pName) {
6776 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6777 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6778 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6781 /* common fields */
6782 diW.cVersion = diA->cVersion;
6784 if (diA->pName) {
6785 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6786 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6787 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6790 if (diA->pEnvironment) {
6791 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6792 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6793 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6796 if (diA->pDriverPath) {
6797 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6798 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6799 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6802 if (diA->pDataFile) {
6803 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6804 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6805 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6808 if (diA->pConfigFile) {
6809 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6810 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6811 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6814 if ((Level > 2) && diA->pDependentFiles) {
6815 lenA = multi_sz_lenA(diA->pDependentFiles);
6816 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6817 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6818 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6821 if ((Level > 2) && diA->pMonitorName) {
6822 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6823 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6824 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6827 if ((Level > 3) && diA->pDefaultDataType) {
6828 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6829 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6830 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6833 if ((Level > 3) && diA->pszzPreviousNames) {
6834 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6835 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6836 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6837 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6840 if ((Level > 5) && diA->pszMfgName) {
6841 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6842 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6843 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6846 if ((Level > 5) && diA->pszOEMUrl) {
6847 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6848 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6849 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6852 if ((Level > 5) && diA->pszHardwareID) {
6853 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6854 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6855 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6858 if ((Level > 5) && diA->pszProvider) {
6859 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6860 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6861 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6864 if (Level > 7) {
6865 FIXME("level %u is incomplete\n", Level);
6868 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6869 TRACE("got %u with %u\n", res, GetLastError());
6870 HeapFree(GetProcessHeap(), 0, nameW);
6871 HeapFree(GetProcessHeap(), 0, diW.pName);
6872 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6873 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6874 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6875 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6876 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6877 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6878 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6879 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6880 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6881 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6882 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6883 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6885 TRACE("=> %u with %u\n", res, GetLastError());
6886 return res;
6889 /******************************************************************************
6890 * ConfigurePortA (WINSPOOL.@)
6892 * See ConfigurePortW.
6895 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6897 LPWSTR nameW = NULL;
6898 LPWSTR portW = NULL;
6899 INT len;
6900 DWORD res;
6902 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6904 /* convert servername to unicode */
6905 if (pName) {
6906 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6907 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6908 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6911 /* convert portname to unicode */
6912 if (pPortName) {
6913 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6914 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6915 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6918 res = ConfigurePortW(nameW, hWnd, portW);
6919 HeapFree(GetProcessHeap(), 0, nameW);
6920 HeapFree(GetProcessHeap(), 0, portW);
6921 return res;
6924 /******************************************************************************
6925 * ConfigurePortW (WINSPOOL.@)
6927 * Display the Configuration-Dialog for a specific Port
6929 * PARAMS
6930 * pName [I] Servername or NULL (local Computer)
6931 * hWnd [I] Handle to parent Window for the Dialog-Box
6932 * pPortName [I] Name of the Port, that should be configured
6934 * RETURNS
6935 * Success: TRUE
6936 * Failure: FALSE
6939 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6942 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6944 if ((backend == NULL) && !load_backend()) return FALSE;
6946 if (!pPortName) {
6947 SetLastError(RPC_X_NULL_REF_POINTER);
6948 return FALSE;
6951 return backend->fpConfigurePort(pName, hWnd, pPortName);
6954 /******************************************************************************
6955 * ConnectToPrinterDlg (WINSPOOL.@)
6957 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6959 FIXME("%p %x\n", hWnd, Flags);
6960 return NULL;
6963 /******************************************************************************
6964 * DeletePrinterConnectionA (WINSPOOL.@)
6966 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6968 FIXME("%s\n", debugstr_a(pName));
6969 return TRUE;
6972 /******************************************************************************
6973 * DeletePrinterConnectionW (WINSPOOL.@)
6975 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6977 FIXME("%s\n", debugstr_w(pName));
6978 return TRUE;
6981 /******************************************************************************
6982 * DeletePrinterDriverExW (WINSPOOL.@)
6984 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6985 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6987 HKEY hkey_drivers;
6988 BOOL ret = FALSE;
6990 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6991 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6993 if(pName && pName[0])
6995 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6996 SetLastError(ERROR_INVALID_PARAMETER);
6997 return FALSE;
7000 if(dwDeleteFlag)
7002 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7003 SetLastError(ERROR_INVALID_PARAMETER);
7004 return FALSE;
7007 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7009 if(!hkey_drivers)
7011 ERR("Can't open drivers key\n");
7012 return FALSE;
7015 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7016 ret = TRUE;
7018 RegCloseKey(hkey_drivers);
7020 return ret;
7023 /******************************************************************************
7024 * DeletePrinterDriverExA (WINSPOOL.@)
7026 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7027 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7029 UNICODE_STRING NameW, EnvW, DriverW;
7030 BOOL ret;
7032 asciitounicode(&NameW, pName);
7033 asciitounicode(&EnvW, pEnvironment);
7034 asciitounicode(&DriverW, pDriverName);
7036 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7038 RtlFreeUnicodeString(&DriverW);
7039 RtlFreeUnicodeString(&EnvW);
7040 RtlFreeUnicodeString(&NameW);
7042 return ret;
7045 /******************************************************************************
7046 * DeletePrinterDataExW (WINSPOOL.@)
7048 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7049 LPCWSTR pValueName)
7051 FIXME("%p %s %s\n", hPrinter,
7052 debugstr_w(pKeyName), debugstr_w(pValueName));
7053 return ERROR_INVALID_PARAMETER;
7056 /******************************************************************************
7057 * DeletePrinterDataExA (WINSPOOL.@)
7059 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7060 LPCSTR pValueName)
7062 FIXME("%p %s %s\n", hPrinter,
7063 debugstr_a(pKeyName), debugstr_a(pValueName));
7064 return ERROR_INVALID_PARAMETER;
7067 /******************************************************************************
7068 * DeletePrintProcessorA (WINSPOOL.@)
7070 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7072 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7073 debugstr_a(pPrintProcessorName));
7074 return TRUE;
7077 /******************************************************************************
7078 * DeletePrintProcessorW (WINSPOOL.@)
7080 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7082 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7083 debugstr_w(pPrintProcessorName));
7084 return TRUE;
7087 /******************************************************************************
7088 * DeletePrintProvidorA (WINSPOOL.@)
7090 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7092 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7093 debugstr_a(pPrintProviderName));
7094 return TRUE;
7097 /******************************************************************************
7098 * DeletePrintProvidorW (WINSPOOL.@)
7100 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7102 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7103 debugstr_w(pPrintProviderName));
7104 return TRUE;
7107 /******************************************************************************
7108 * EnumFormsA (WINSPOOL.@)
7110 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7111 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7113 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7114 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7115 return FALSE;
7118 /******************************************************************************
7119 * EnumFormsW (WINSPOOL.@)
7121 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7122 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7124 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7125 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7126 return FALSE;
7129 /*****************************************************************************
7130 * EnumMonitorsA [WINSPOOL.@]
7132 * See EnumMonitorsW.
7135 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7136 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7138 BOOL res;
7139 LPBYTE bufferW = NULL;
7140 LPWSTR nameW = NULL;
7141 DWORD needed = 0;
7142 DWORD numentries = 0;
7143 INT len;
7145 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7146 cbBuf, pcbNeeded, pcReturned);
7148 /* convert servername to unicode */
7149 if (pName) {
7150 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7151 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7152 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7154 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7155 needed = cbBuf * sizeof(WCHAR);
7156 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7157 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7159 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7160 if (pcbNeeded) needed = *pcbNeeded;
7161 /* HeapReAlloc return NULL, when bufferW was NULL */
7162 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7163 HeapAlloc(GetProcessHeap(), 0, needed);
7165 /* Try again with the large Buffer */
7166 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7168 numentries = pcReturned ? *pcReturned : 0;
7169 needed = 0;
7171 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7172 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7174 if (res) {
7175 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7176 DWORD entrysize = 0;
7177 DWORD index;
7178 LPSTR ptr;
7179 LPMONITOR_INFO_2W mi2w;
7180 LPMONITOR_INFO_2A mi2a;
7182 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7183 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7185 /* First pass: calculate the size for all Entries */
7186 mi2w = (LPMONITOR_INFO_2W) bufferW;
7187 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7188 index = 0;
7189 while (index < numentries) {
7190 index++;
7191 needed += entrysize; /* MONITOR_INFO_?A */
7192 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7194 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7195 NULL, 0, NULL, NULL);
7196 if (Level > 1) {
7197 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7198 NULL, 0, NULL, NULL);
7199 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7200 NULL, 0, NULL, NULL);
7202 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7203 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7204 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7207 /* check for errors and quit on failure */
7208 if (cbBuf < needed) {
7209 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7210 res = FALSE;
7211 goto emA_cleanup;
7213 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7214 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7215 cbBuf -= len ; /* free Bytes in the user-Buffer */
7216 mi2w = (LPMONITOR_INFO_2W) bufferW;
7217 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7218 index = 0;
7219 /* Second Pass: Fill the User Buffer (if we have one) */
7220 while ((index < numentries) && pMonitors) {
7221 index++;
7222 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7223 mi2a->pName = ptr;
7224 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7225 ptr, cbBuf , NULL, NULL);
7226 ptr += len;
7227 cbBuf -= len;
7228 if (Level > 1) {
7229 mi2a->pEnvironment = ptr;
7230 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7231 ptr, cbBuf, NULL, NULL);
7232 ptr += len;
7233 cbBuf -= len;
7235 mi2a->pDLLName = ptr;
7236 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7237 ptr, cbBuf, NULL, NULL);
7238 ptr += len;
7239 cbBuf -= len;
7241 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7242 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7243 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7246 emA_cleanup:
7247 if (pcbNeeded) *pcbNeeded = needed;
7248 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7250 HeapFree(GetProcessHeap(), 0, nameW);
7251 HeapFree(GetProcessHeap(), 0, bufferW);
7253 TRACE("returning %d with %d (%d byte for %d entries)\n",
7254 (res), GetLastError(), needed, numentries);
7256 return (res);
7260 /*****************************************************************************
7261 * EnumMonitorsW [WINSPOOL.@]
7263 * Enumerate available Port-Monitors
7265 * PARAMS
7266 * pName [I] Servername or NULL (local Computer)
7267 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7268 * pMonitors [O] PTR to Buffer that receives the Result
7269 * cbBuf [I] Size of Buffer at pMonitors
7270 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7271 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7273 * RETURNS
7274 * Success: TRUE
7275 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7278 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7279 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7282 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7283 cbBuf, pcbNeeded, pcReturned);
7285 if ((backend == NULL) && !load_backend()) return FALSE;
7287 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7288 SetLastError(RPC_X_NULL_REF_POINTER);
7289 return FALSE;
7292 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7295 /******************************************************************************
7296 * SpoolerInit (WINSPOOL.@)
7298 * Initialize the Spooler
7300 * RETURNS
7301 * Success: TRUE
7302 * Failure: FALSE
7304 * NOTES
7305 * The function fails on windows, when the spooler service is not running
7308 BOOL WINAPI SpoolerInit(void)
7311 if ((backend == NULL) && !load_backend()) return FALSE;
7312 return TRUE;
7315 /******************************************************************************
7316 * XcvDataW (WINSPOOL.@)
7318 * Execute commands in the Printmonitor DLL
7320 * PARAMS
7321 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7322 * pszDataName [i] Name of the command to execute
7323 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7324 * cbInputData [i] Size in Bytes of Buffer at pInputData
7325 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7326 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7327 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7328 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7330 * RETURNS
7331 * Success: TRUE
7332 * Failure: FALSE
7334 * NOTES
7335 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7336 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7338 * Minimal List of commands, that a Printmonitor DLL should support:
7340 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7341 *| "AddPort" : Add a Port
7342 *| "DeletePort": Delete a Port
7344 * Many Printmonitors support additional commands. Examples for localspl.dll:
7345 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7346 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7349 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7350 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7351 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7353 opened_printer_t *printer;
7355 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7356 pInputData, cbInputData, pOutputData,
7357 cbOutputData, pcbOutputNeeded, pdwStatus);
7359 if ((backend == NULL) && !load_backend()) return FALSE;
7361 printer = get_opened_printer(hXcv);
7362 if (!printer || (!printer->backend_printer)) {
7363 SetLastError(ERROR_INVALID_HANDLE);
7364 return FALSE;
7367 if (!pcbOutputNeeded) {
7368 SetLastError(ERROR_INVALID_PARAMETER);
7369 return FALSE;
7372 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7373 SetLastError(RPC_X_NULL_REF_POINTER);
7374 return FALSE;
7377 *pcbOutputNeeded = 0;
7379 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7380 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7384 /*****************************************************************************
7385 * EnumPrinterDataA [WINSPOOL.@]
7388 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7389 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7390 DWORD cbData, LPDWORD pcbData )
7392 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7393 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7394 return ERROR_NO_MORE_ITEMS;
7397 /*****************************************************************************
7398 * EnumPrinterDataW [WINSPOOL.@]
7401 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7402 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7403 DWORD cbData, LPDWORD pcbData )
7405 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7406 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7407 return ERROR_NO_MORE_ITEMS;
7410 /*****************************************************************************
7411 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7414 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7415 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7416 LPDWORD pcbNeeded, LPDWORD pcReturned)
7418 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7419 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7420 pcbNeeded, pcReturned);
7421 return FALSE;
7424 /*****************************************************************************
7425 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7428 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7429 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7430 LPDWORD pcbNeeded, LPDWORD pcReturned)
7432 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7433 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7434 pcbNeeded, pcReturned);
7435 return FALSE;
7438 /*****************************************************************************
7439 * EnumPrintProcessorsA [WINSPOOL.@]
7441 * See EnumPrintProcessorsW.
7444 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7445 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7447 BOOL res;
7448 LPBYTE bufferW = NULL;
7449 LPWSTR nameW = NULL;
7450 LPWSTR envW = NULL;
7451 DWORD needed = 0;
7452 DWORD numentries = 0;
7453 INT len;
7455 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7456 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7458 /* convert names to unicode */
7459 if (pName) {
7460 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7461 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7462 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7464 if (pEnvironment) {
7465 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7466 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7467 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7470 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7471 needed = cbBuf * sizeof(WCHAR);
7472 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7473 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7475 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7476 if (pcbNeeded) needed = *pcbNeeded;
7477 /* HeapReAlloc return NULL, when bufferW was NULL */
7478 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7479 HeapAlloc(GetProcessHeap(), 0, needed);
7481 /* Try again with the large Buffer */
7482 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7484 numentries = pcReturned ? *pcReturned : 0;
7485 needed = 0;
7487 if (res) {
7488 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7489 DWORD index;
7490 LPSTR ptr;
7491 PPRINTPROCESSOR_INFO_1W ppiw;
7492 PPRINTPROCESSOR_INFO_1A ppia;
7494 /* First pass: calculate the size for all Entries */
7495 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7496 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7497 index = 0;
7498 while (index < numentries) {
7499 index++;
7500 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7501 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7503 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7504 NULL, 0, NULL, NULL);
7506 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7507 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7510 /* check for errors and quit on failure */
7511 if (cbBuf < needed) {
7512 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7513 res = FALSE;
7514 goto epp_cleanup;
7517 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7518 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7519 cbBuf -= len ; /* free Bytes in the user-Buffer */
7520 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7521 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7522 index = 0;
7523 /* Second Pass: Fill the User Buffer (if we have one) */
7524 while ((index < numentries) && pPPInfo) {
7525 index++;
7526 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7527 ppia->pName = ptr;
7528 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7529 ptr, cbBuf , NULL, NULL);
7530 ptr += len;
7531 cbBuf -= len;
7533 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7534 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7538 epp_cleanup:
7539 if (pcbNeeded) *pcbNeeded = needed;
7540 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7542 HeapFree(GetProcessHeap(), 0, nameW);
7543 HeapFree(GetProcessHeap(), 0, envW);
7544 HeapFree(GetProcessHeap(), 0, bufferW);
7546 TRACE("returning %d with %d (%d byte for %d entries)\n",
7547 (res), GetLastError(), needed, numentries);
7549 return (res);
7552 /*****************************************************************************
7553 * EnumPrintProcessorsW [WINSPOOL.@]
7555 * Enumerate available Print Processors
7557 * PARAMS
7558 * pName [I] Servername or NULL (local Computer)
7559 * pEnvironment [I] Printing-Environment or NULL (Default)
7560 * Level [I] Structure-Level (Only 1 is allowed)
7561 * pPPInfo [O] PTR to Buffer that receives the Result
7562 * cbBuf [I] Size of Buffer at pPPInfo
7563 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7564 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7566 * RETURNS
7567 * Success: TRUE
7568 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7571 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7572 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7575 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7576 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7578 if ((backend == NULL) && !load_backend()) return FALSE;
7580 if (!pcbNeeded || !pcReturned) {
7581 SetLastError(RPC_X_NULL_REF_POINTER);
7582 return FALSE;
7585 if (!pPPInfo && (cbBuf > 0)) {
7586 SetLastError(ERROR_INVALID_USER_BUFFER);
7587 return FALSE;
7590 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7591 cbBuf, pcbNeeded, pcReturned);
7594 /*****************************************************************************
7595 * ExtDeviceMode [WINSPOOL.@]
7598 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7599 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7600 DWORD fMode)
7602 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7603 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7604 debugstr_a(pProfile), fMode);
7605 return -1;
7608 /*****************************************************************************
7609 * FindClosePrinterChangeNotification [WINSPOOL.@]
7612 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7614 FIXME("Stub: %p\n", hChange);
7615 return TRUE;
7618 /*****************************************************************************
7619 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7622 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7623 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7625 FIXME("Stub: %p %x %x %p\n",
7626 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7627 return INVALID_HANDLE_VALUE;
7630 /*****************************************************************************
7631 * FindNextPrinterChangeNotification [WINSPOOL.@]
7634 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7635 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7637 FIXME("Stub: %p %p %p %p\n",
7638 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7639 return FALSE;
7642 /*****************************************************************************
7643 * FreePrinterNotifyInfo [WINSPOOL.@]
7646 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7648 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7649 return TRUE;
7652 /*****************************************************************************
7653 * string_to_buf
7655 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7656 * ansi depending on the unicode parameter.
7658 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7660 if(!str)
7662 *size = 0;
7663 return TRUE;
7666 if(unicode)
7668 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7669 if(*size <= cb)
7671 memcpy(ptr, str, *size);
7672 return TRUE;
7674 return FALSE;
7676 else
7678 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7679 if(*size <= cb)
7681 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7682 return TRUE;
7684 return FALSE;
7688 /*****************************************************************************
7689 * get_job_info_1
7691 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7692 LPDWORD pcbNeeded, BOOL unicode)
7694 DWORD size, left = cbBuf;
7695 BOOL space = (cbBuf > 0);
7696 LPBYTE ptr = buf;
7698 *pcbNeeded = 0;
7700 if(space)
7702 ji1->JobId = job->job_id;
7705 string_to_buf(job->document_title, ptr, left, &size, unicode);
7706 if(space && size <= left)
7708 ji1->pDocument = (LPWSTR)ptr;
7709 ptr += size;
7710 left -= size;
7712 else
7713 space = FALSE;
7714 *pcbNeeded += size;
7716 if (job->printer_name)
7718 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7719 if(space && size <= left)
7721 ji1->pPrinterName = (LPWSTR)ptr;
7722 ptr += size;
7723 left -= size;
7725 else
7726 space = FALSE;
7727 *pcbNeeded += size;
7730 return space;
7733 /*****************************************************************************
7734 * get_job_info_2
7736 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7737 LPDWORD pcbNeeded, BOOL unicode)
7739 DWORD size, left = cbBuf;
7740 DWORD shift;
7741 BOOL space = (cbBuf > 0);
7742 LPBYTE ptr = buf;
7743 LPDEVMODEA dmA = NULL;
7744 LPDEVMODEW devmode;
7746 *pcbNeeded = 0;
7748 if(space)
7750 ji2->JobId = job->job_id;
7753 string_to_buf(job->document_title, ptr, left, &size, unicode);
7754 if(space && size <= left)
7756 ji2->pDocument = (LPWSTR)ptr;
7757 ptr += size;
7758 left -= size;
7760 else
7761 space = FALSE;
7762 *pcbNeeded += size;
7764 if (job->printer_name)
7766 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7767 if(space && size <= left)
7769 ji2->pPrinterName = (LPWSTR)ptr;
7770 ptr += size;
7771 left -= size;
7773 else
7774 space = FALSE;
7775 *pcbNeeded += size;
7778 if (job->devmode)
7780 if (!unicode)
7782 dmA = DEVMODEdupWtoA(job->devmode);
7783 devmode = (LPDEVMODEW) dmA;
7784 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7786 else
7788 devmode = job->devmode;
7789 size = devmode->dmSize + devmode->dmDriverExtra;
7792 if (!devmode)
7793 FIXME("Can't convert DEVMODE W to A\n");
7794 else
7796 /* align DEVMODE to a DWORD boundary */
7797 shift = (4 - (*pcbNeeded & 3)) & 3;
7798 size += shift;
7800 if (size <= left)
7802 ptr += shift;
7803 memcpy(ptr, devmode, size-shift);
7804 ji2->pDevMode = (LPDEVMODEW)ptr;
7805 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7806 ptr += size-shift;
7807 left -= size;
7809 else
7810 space = FALSE;
7811 *pcbNeeded +=size;
7815 return space;
7818 /*****************************************************************************
7819 * get_job_info
7821 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7822 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7824 BOOL ret = FALSE;
7825 DWORD needed = 0, size;
7826 job_t *job;
7827 LPBYTE ptr = pJob;
7829 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7831 EnterCriticalSection(&printer_handles_cs);
7832 job = get_job(hPrinter, JobId);
7833 if(!job)
7834 goto end;
7836 switch(Level)
7838 case 1:
7839 size = sizeof(JOB_INFO_1W);
7840 if(cbBuf >= size)
7842 cbBuf -= size;
7843 ptr += size;
7844 memset(pJob, 0, size);
7846 else
7847 cbBuf = 0;
7848 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7849 needed += size;
7850 break;
7852 case 2:
7853 size = sizeof(JOB_INFO_2W);
7854 if(cbBuf >= size)
7856 cbBuf -= size;
7857 ptr += size;
7858 memset(pJob, 0, size);
7860 else
7861 cbBuf = 0;
7862 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7863 needed += size;
7864 break;
7866 case 3:
7867 size = sizeof(JOB_INFO_3);
7868 if(cbBuf >= size)
7870 cbBuf -= size;
7871 memset(pJob, 0, size);
7872 ret = TRUE;
7874 else
7875 cbBuf = 0;
7876 needed = size;
7877 break;
7879 default:
7880 SetLastError(ERROR_INVALID_LEVEL);
7881 goto end;
7883 if(pcbNeeded)
7884 *pcbNeeded = needed;
7885 end:
7886 LeaveCriticalSection(&printer_handles_cs);
7887 return ret;
7890 /*****************************************************************************
7891 * GetJobA [WINSPOOL.@]
7894 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7895 DWORD cbBuf, LPDWORD pcbNeeded)
7897 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7900 /*****************************************************************************
7901 * GetJobW [WINSPOOL.@]
7904 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7905 DWORD cbBuf, LPDWORD pcbNeeded)
7907 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7910 /*****************************************************************************
7911 * schedule_pipe
7913 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7915 #ifdef HAVE_FORK
7916 char *unixname, *cmdA;
7917 DWORD len;
7918 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7919 BOOL ret = FALSE;
7920 char buf[1024];
7921 pid_t pid, wret;
7922 int status;
7924 if(!(unixname = wine_get_unix_file_name(filename)))
7925 return FALSE;
7927 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7928 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7929 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7931 TRACE("printing with: %s\n", cmdA);
7933 if((file_fd = open(unixname, O_RDONLY)) == -1)
7934 goto end;
7936 if (pipe(fds))
7938 ERR("pipe() failed!\n");
7939 goto end;
7942 if ((pid = fork()) == 0)
7944 close(0);
7945 dup2(fds[0], 0);
7946 close(fds[1]);
7948 /* reset signals that we previously set to SIG_IGN */
7949 signal(SIGPIPE, SIG_DFL);
7951 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7952 _exit(1);
7954 else if (pid == -1)
7956 ERR("fork() failed!\n");
7957 goto end;
7960 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7961 write(fds[1], buf, no_read);
7963 close(fds[1]);
7964 fds[1] = -1;
7966 /* reap child */
7967 do {
7968 wret = waitpid(pid, &status, 0);
7969 } while (wret < 0 && errno == EINTR);
7970 if (wret < 0)
7972 ERR("waitpid() failed!\n");
7973 goto end;
7975 if (!WIFEXITED(status) || WEXITSTATUS(status))
7977 ERR("child process failed! %d\n", status);
7978 goto end;
7981 ret = TRUE;
7983 end:
7984 if(file_fd != -1) close(file_fd);
7985 if(fds[0] != -1) close(fds[0]);
7986 if(fds[1] != -1) close(fds[1]);
7988 HeapFree(GetProcessHeap(), 0, cmdA);
7989 HeapFree(GetProcessHeap(), 0, unixname);
7990 return ret;
7991 #else
7992 return FALSE;
7993 #endif
7996 /*****************************************************************************
7997 * schedule_lpr
7999 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8001 WCHAR *cmd;
8002 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8003 BOOL r;
8005 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8006 sprintfW(cmd, fmtW, printer_name);
8008 r = schedule_pipe(cmd, filename);
8010 HeapFree(GetProcessHeap(), 0, cmd);
8011 return r;
8014 #ifdef SONAME_LIBCUPS
8015 /*****************************************************************************
8016 * get_cups_jobs_ticket_options
8018 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8019 * The CUPS scheduler only looks for these in Print-File requests, and since
8020 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8021 * parsed.
8023 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8025 FILE *fp = fopen( file, "r" );
8026 char buf[257]; /* DSC max of 256 + '\0' */
8027 const char *ps_adobe = "%!PS-Adobe-";
8028 const char *cups_job = "%cupsJobTicket:";
8030 if (!fp) return num_options;
8031 if (!fgets( buf, sizeof(buf), fp )) goto end;
8032 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8033 while (fgets( buf, sizeof(buf), fp ))
8035 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8036 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8039 end:
8040 fclose( fp );
8041 return num_options;
8043 #endif
8045 /*****************************************************************************
8046 * schedule_cups
8048 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8050 #ifdef SONAME_LIBCUPS
8051 if(pcupsPrintFile)
8053 char *unixname, *queue, *unix_doc_title;
8054 DWORD len;
8055 BOOL ret;
8056 int num_options = 0, i;
8057 cups_option_t *options = NULL;
8059 if(!(unixname = wine_get_unix_file_name(filename)))
8060 return FALSE;
8062 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8063 queue = HeapAlloc(GetProcessHeap(), 0, len);
8064 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8066 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8067 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8068 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8070 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8072 TRACE( "printing via cups with options:\n" );
8073 for (i = 0; i < num_options; i++)
8074 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8076 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8078 pcupsFreeOptions( num_options, options );
8080 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8081 HeapFree(GetProcessHeap(), 0, queue);
8082 HeapFree(GetProcessHeap(), 0, unixname);
8083 return ret;
8085 else
8086 #endif
8088 return schedule_lpr(printer_name, filename);
8092 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8094 LPWSTR filename;
8096 switch(msg)
8098 case WM_INITDIALOG:
8099 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8100 return TRUE;
8102 case WM_COMMAND:
8103 if(HIWORD(wparam) == BN_CLICKED)
8105 if(LOWORD(wparam) == IDOK)
8107 HANDLE hf;
8108 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8109 LPWSTR *output;
8111 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8112 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8114 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8116 WCHAR caption[200], message[200];
8117 int mb_ret;
8119 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8120 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8121 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8122 if(mb_ret == IDCANCEL)
8124 HeapFree(GetProcessHeap(), 0, filename);
8125 return TRUE;
8128 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8129 if(hf == INVALID_HANDLE_VALUE)
8131 WCHAR caption[200], message[200];
8133 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8134 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8135 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8136 HeapFree(GetProcessHeap(), 0, filename);
8137 return TRUE;
8139 CloseHandle(hf);
8140 DeleteFileW(filename);
8141 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8142 *output = filename;
8143 EndDialog(hwnd, IDOK);
8144 return TRUE;
8146 if(LOWORD(wparam) == IDCANCEL)
8148 EndDialog(hwnd, IDCANCEL);
8149 return TRUE;
8152 return FALSE;
8154 return FALSE;
8157 /*****************************************************************************
8158 * get_filename
8160 static BOOL get_filename(LPWSTR *filename)
8162 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8163 file_dlg_proc, (LPARAM)filename) == IDOK;
8166 /*****************************************************************************
8167 * schedule_file
8169 static BOOL schedule_file(LPCWSTR filename)
8171 LPWSTR output = NULL;
8173 if(get_filename(&output))
8175 BOOL r;
8176 TRACE("copy to %s\n", debugstr_w(output));
8177 r = CopyFileW(filename, output, FALSE);
8178 HeapFree(GetProcessHeap(), 0, output);
8179 return r;
8181 return FALSE;
8184 /*****************************************************************************
8185 * schedule_unixfile
8187 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8189 int in_fd, out_fd, no_read;
8190 char buf[1024];
8191 BOOL ret = FALSE;
8192 char *unixname, *outputA;
8193 DWORD len;
8195 if(!(unixname = wine_get_unix_file_name(filename)))
8196 return FALSE;
8198 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8199 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8200 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8202 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8203 in_fd = open(unixname, O_RDONLY);
8204 if(out_fd == -1 || in_fd == -1)
8205 goto end;
8207 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8208 write(out_fd, buf, no_read);
8210 ret = TRUE;
8211 end:
8212 if(in_fd != -1) close(in_fd);
8213 if(out_fd != -1) close(out_fd);
8214 HeapFree(GetProcessHeap(), 0, outputA);
8215 HeapFree(GetProcessHeap(), 0, unixname);
8216 return ret;
8219 /*****************************************************************************
8220 * ScheduleJob [WINSPOOL.@]
8223 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8225 opened_printer_t *printer;
8226 BOOL ret = FALSE;
8227 struct list *cursor, *cursor2;
8229 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8230 EnterCriticalSection(&printer_handles_cs);
8231 printer = get_opened_printer(hPrinter);
8232 if(!printer)
8233 goto end;
8235 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8237 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8238 HANDLE hf;
8240 if(job->job_id != dwJobID) continue;
8242 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8243 if(hf != INVALID_HANDLE_VALUE)
8245 PRINTER_INFO_5W *pi5 = NULL;
8246 LPWSTR portname = job->portname;
8247 DWORD needed;
8248 HKEY hkey;
8249 WCHAR output[1024];
8250 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8251 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8253 if (!portname)
8255 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8256 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8257 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8258 portname = pi5->pPortName;
8260 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8261 debugstr_w(portname));
8263 output[0] = 0;
8265 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8266 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8268 DWORD type, count = sizeof(output);
8269 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8270 RegCloseKey(hkey);
8272 if(output[0] == '|')
8274 ret = schedule_pipe(output + 1, job->filename);
8276 else if(output[0])
8278 ret = schedule_unixfile(output, job->filename);
8280 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8282 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8284 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8286 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8288 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8290 ret = schedule_file(job->filename);
8292 else
8294 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8296 HeapFree(GetProcessHeap(), 0, pi5);
8297 CloseHandle(hf);
8298 DeleteFileW(job->filename);
8300 list_remove(cursor);
8301 HeapFree(GetProcessHeap(), 0, job->document_title);
8302 HeapFree(GetProcessHeap(), 0, job->printer_name);
8303 HeapFree(GetProcessHeap(), 0, job->portname);
8304 HeapFree(GetProcessHeap(), 0, job->filename);
8305 HeapFree(GetProcessHeap(), 0, job->devmode);
8306 HeapFree(GetProcessHeap(), 0, job);
8307 break;
8309 end:
8310 LeaveCriticalSection(&printer_handles_cs);
8311 return ret;
8314 /*****************************************************************************
8315 * StartDocDlgA [WINSPOOL.@]
8317 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8319 UNICODE_STRING usBuffer;
8320 DOCINFOW docW;
8321 LPWSTR retW;
8322 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8323 LPSTR ret = NULL;
8325 docW.cbSize = sizeof(docW);
8326 if (doc->lpszDocName)
8328 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8329 if (!(docW.lpszDocName = docnameW)) return NULL;
8331 if (doc->lpszOutput)
8333 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8334 if (!(docW.lpszOutput = outputW)) return NULL;
8336 if (doc->lpszDatatype)
8338 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8339 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8341 docW.fwType = doc->fwType;
8343 retW = StartDocDlgW(hPrinter, &docW);
8345 if(retW)
8347 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8348 ret = HeapAlloc(GetProcessHeap(), 0, len);
8349 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8350 HeapFree(GetProcessHeap(), 0, retW);
8353 HeapFree(GetProcessHeap(), 0, datatypeW);
8354 HeapFree(GetProcessHeap(), 0, outputW);
8355 HeapFree(GetProcessHeap(), 0, docnameW);
8357 return ret;
8360 /*****************************************************************************
8361 * StartDocDlgW [WINSPOOL.@]
8363 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8364 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8365 * port is "FILE:". Also returns the full path if passed a relative path.
8367 * The caller should free the returned string from the process heap.
8369 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8371 LPWSTR ret = NULL;
8372 DWORD len, attr;
8374 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8376 PRINTER_INFO_5W *pi5;
8377 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8378 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8379 return NULL;
8380 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8381 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8382 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8384 HeapFree(GetProcessHeap(), 0, pi5);
8385 return NULL;
8387 HeapFree(GetProcessHeap(), 0, pi5);
8390 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8392 LPWSTR name;
8394 if (get_filename(&name))
8396 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8398 HeapFree(GetProcessHeap(), 0, name);
8399 return NULL;
8401 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8402 GetFullPathNameW(name, len, ret, NULL);
8403 HeapFree(GetProcessHeap(), 0, name);
8405 return ret;
8408 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8409 return NULL;
8411 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8412 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8414 attr = GetFileAttributesW(ret);
8415 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8417 HeapFree(GetProcessHeap(), 0, ret);
8418 ret = NULL;
8420 return ret;