winspool: Update the devmode when we update the driver.
[wine/multimedia.git] / dlls / winspool.drv / info.c
bloba8d245fa40e3be55cd7bf918800422cad16be934
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 );
978 /* call into the driver to update the devmode */
979 DocumentPropertiesW( 0, printer, NULL, NULL, NULL, 0 );
981 return ret;
984 static BOOL PRINTCAP_ParseEntry( const char *pent, BOOL isfirst )
986 PRINTER_INFO_2A pinfo2a;
987 const char *r;
988 size_t name_len;
989 char *e,*s,*name,*prettyname,*devname;
990 BOOL ret = FALSE, set_default = FALSE;
991 char *port = NULL, *env_default;
992 HKEY hkeyPrinter, hkeyPrinters = NULL;
993 WCHAR devnameW[MAX_PATH], *ppd_dir = NULL, *ppd;
994 HANDLE added_printer;
996 while (isspace(*pent)) pent++;
997 r = strchr(pent,':');
998 if (r)
999 name_len = r - pent;
1000 else
1001 name_len = strlen(pent);
1002 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
1003 memcpy(name, pent, name_len);
1004 name[name_len] = '\0';
1005 if (r)
1006 pent = r;
1007 else
1008 pent = "";
1010 TRACE("name=%s entry=%s\n",name, pent);
1012 if(ispunct(*name)) { /* a tc entry, not a real printer */
1013 TRACE("skipping tc entry\n");
1014 goto end;
1017 if(strstr(pent,":server")) { /* server only version so skip */
1018 TRACE("skipping server entry\n");
1019 goto end;
1022 /* Determine whether this is a postscript printer. */
1024 ret = TRUE;
1025 env_default = getenv("PRINTER");
1026 prettyname = name;
1027 /* Get longest name, usually the one at the right for later display. */
1028 while((s=strchr(prettyname,'|'))) {
1029 *s = '\0';
1030 e = s;
1031 while(isspace(*--e)) *e = '\0';
1032 TRACE("\t%s\n", debugstr_a(prettyname));
1033 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1034 for(prettyname = s+1; isspace(*prettyname); prettyname++)
1037 e = prettyname + strlen(prettyname);
1038 while(isspace(*--e)) *e = '\0';
1039 TRACE("\t%s\n", debugstr_a(prettyname));
1040 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
1042 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1043 * if it is too long, we use it as comment below. */
1044 devname = prettyname;
1045 if (strlen(devname)>=CCHDEVICENAME-1)
1046 devname = name;
1047 if (strlen(devname)>=CCHDEVICENAME-1) {
1048 ret = FALSE;
1049 goto end;
1052 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
1053 sprintf(port,"LPR:%s",name);
1055 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1056 ERROR_SUCCESS) {
1057 ERR("Can't create Printers key\n");
1058 ret = FALSE;
1059 goto end;
1062 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
1064 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
1065 DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
1066 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1067 and continue */
1068 TRACE("Printer already exists\n");
1069 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
1070 /* flag that the PPD file should be checked for an update */
1071 set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
1072 RegCloseKey(hkeyPrinter);
1073 } else {
1074 static CHAR data_type[] = "RAW",
1075 print_proc[] = "WinPrint",
1076 comment[] = "WINEPS Printer using LPR",
1077 params[] = "<parameters?>",
1078 share_name[] = "<share name?>",
1079 sep_file[] = "<sep file?>";
1080 BOOL added_driver = FALSE;
1082 if (!ppd_dir) ppd_dir = get_ppd_dir();
1083 ppd = get_ppd_filename( ppd_dir, devnameW );
1084 if (get_fallback_ppd( devname, ppd ))
1086 added_driver = add_printer_driver( devnameW, ppd );
1087 unlink_ppd( ppd );
1089 HeapFree( GetProcessHeap(), 0, ppd );
1090 if (!added_driver) goto end;
1092 memset(&pinfo2a,0,sizeof(pinfo2a));
1093 pinfo2a.pPrinterName = devname;
1094 pinfo2a.pDatatype = data_type;
1095 pinfo2a.pPrintProcessor = print_proc;
1096 pinfo2a.pDriverName = devname;
1097 pinfo2a.pComment = comment;
1098 pinfo2a.pLocation = prettyname;
1099 pinfo2a.pPortName = port;
1100 pinfo2a.pParameters = params;
1101 pinfo2a.pShareName = share_name;
1102 pinfo2a.pSepFile = sep_file;
1104 added_printer = AddPrinterA( NULL, 2, (LPBYTE)&pinfo2a );
1105 if (added_printer) ClosePrinter( added_printer );
1106 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
1107 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name), GetLastError() );
1110 if (isfirst || set_default)
1111 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
1113 end:
1114 if (hkeyPrinters) RegCloseKey( hkeyPrinters );
1115 if (ppd_dir)
1117 RemoveDirectoryW( ppd_dir );
1118 HeapFree( GetProcessHeap(), 0, ppd_dir );
1120 HeapFree(GetProcessHeap(), 0, port);
1121 HeapFree(GetProcessHeap(), 0, name);
1122 return ret;
1125 static BOOL
1126 PRINTCAP_LoadPrinters(void) {
1127 BOOL hadprinter = FALSE;
1128 char buf[200];
1129 FILE *f;
1130 char *pent = NULL;
1131 BOOL had_bash = FALSE;
1133 f = fopen("/etc/printcap","r");
1134 if (!f)
1135 return FALSE;
1137 while(fgets(buf,sizeof(buf),f)) {
1138 char *start, *end;
1140 end=strchr(buf,'\n');
1141 if (end) *end='\0';
1143 start = buf;
1144 while(isspace(*start)) start++;
1145 if(*start == '#' || *start == '\0')
1146 continue;
1148 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
1149 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1150 HeapFree(GetProcessHeap(),0,pent);
1151 pent = NULL;
1154 if (end && *--end == '\\') {
1155 *end = '\0';
1156 had_bash = TRUE;
1157 } else
1158 had_bash = FALSE;
1160 if (pent) {
1161 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
1162 strcat(pent,start);
1163 } else {
1164 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
1165 strcpy(pent,start);
1169 if(pent) {
1170 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
1171 HeapFree(GetProcessHeap(),0,pent);
1173 fclose(f);
1174 return hadprinter;
1177 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
1179 if (value)
1180 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
1181 (lstrlenW(value) + 1) * sizeof(WCHAR));
1182 else
1183 return ERROR_FILE_NOT_FOUND;
1186 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
1188 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
1189 DWORD ret = ERROR_FILE_NOT_FOUND;
1191 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1192 and we support these drivers. NT writes DEVMODEW so somehow
1193 we'll need to distinguish between these when we support NT
1194 drivers */
1196 if (dmA)
1198 ret = RegSetValueExW( key, name, 0, REG_BINARY,
1199 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
1200 HeapFree( GetProcessHeap(), 0, dmA );
1203 return ret;
1206 /******************************************************************
1207 * get_servername_from_name (internal)
1209 * for an external server, a copy of the serverpart from the full name is returned
1212 static LPWSTR get_servername_from_name(LPCWSTR name)
1214 LPWSTR server;
1215 LPWSTR ptr;
1216 WCHAR buffer[MAX_PATH];
1217 DWORD len;
1219 if (name == NULL) return NULL;
1220 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1222 server = strdupW(&name[2]); /* skip over both backslash */
1223 if (server == NULL) return NULL;
1225 /* strip '\' and the printername */
1226 ptr = strchrW(server, '\\');
1227 if (ptr) ptr[0] = '\0';
1229 TRACE("found %s\n", debugstr_w(server));
1231 len = sizeof(buffer)/sizeof(buffer[0]);
1232 if (GetComputerNameW(buffer, &len)) {
1233 if (lstrcmpW(buffer, server) == 0) {
1234 /* The requested Servername is our computername */
1235 HeapFree(GetProcessHeap(), 0, server);
1236 return NULL;
1239 return server;
1242 /******************************************************************
1243 * get_basename_from_name (internal)
1245 * skip over the serverpart from the full name
1248 static LPCWSTR get_basename_from_name(LPCWSTR name)
1250 if (name == NULL) return NULL;
1251 if ((name[0] == '\\') && (name[1] == '\\')) {
1252 /* skip over the servername and search for the following '\' */
1253 name = strchrW(&name[2], '\\');
1254 if ((name) && (name[1])) {
1255 /* found a separator ('\') followed by a name:
1256 skip over the separator and return the rest */
1257 name++;
1259 else
1261 /* no basename present (we found only a servername) */
1262 return NULL;
1265 return name;
1268 static void free_printer_entry( opened_printer_t *printer )
1270 /* the queue is shared, so don't free that here */
1271 HeapFree( GetProcessHeap(), 0, printer->printername );
1272 HeapFree( GetProcessHeap(), 0, printer->name );
1273 HeapFree( GetProcessHeap(), 0, printer->devmode );
1274 HeapFree( GetProcessHeap(), 0, printer );
1277 /******************************************************************
1278 * get_opened_printer_entry
1279 * Get the first place empty in the opened printer table
1281 * ToDo:
1282 * - pDefault is ignored
1284 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1286 UINT_PTR handle = nb_printer_handles, i;
1287 jobqueue_t *queue = NULL;
1288 opened_printer_t *printer = NULL;
1289 LPWSTR servername;
1290 LPCWSTR printername;
1292 if ((backend == NULL) && !load_backend()) return NULL;
1294 servername = get_servername_from_name(name);
1295 if (servername) {
1296 FIXME("server %s not supported\n", debugstr_w(servername));
1297 HeapFree(GetProcessHeap(), 0, servername);
1298 SetLastError(ERROR_INVALID_PRINTER_NAME);
1299 return NULL;
1302 printername = get_basename_from_name(name);
1303 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1305 /* an empty printername is invalid */
1306 if (printername && (!printername[0])) {
1307 SetLastError(ERROR_INVALID_PARAMETER);
1308 return NULL;
1311 EnterCriticalSection(&printer_handles_cs);
1313 for (i = 0; i < nb_printer_handles; i++)
1315 if (!printer_handles[i])
1317 if(handle == nb_printer_handles)
1318 handle = i;
1320 else
1322 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1323 queue = printer_handles[i]->queue;
1327 if (handle >= nb_printer_handles)
1329 opened_printer_t **new_array;
1330 if (printer_handles)
1331 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1332 (nb_printer_handles + 16) * sizeof(*new_array) );
1333 else
1334 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1335 (nb_printer_handles + 16) * sizeof(*new_array) );
1337 if (!new_array)
1339 handle = 0;
1340 goto end;
1342 printer_handles = new_array;
1343 nb_printer_handles += 16;
1346 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1348 handle = 0;
1349 goto end;
1352 /* get a printer handle from the backend */
1353 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1354 handle = 0;
1355 goto end;
1358 /* clone the base name. This is NULL for the printserver */
1359 printer->printername = strdupW(printername);
1361 /* clone the full name */
1362 printer->name = strdupW(name);
1363 if (name && (!printer->name)) {
1364 handle = 0;
1365 goto end;
1368 if (pDefault && pDefault->pDevMode)
1369 printer->devmode = dup_devmode( pDefault->pDevMode );
1371 if(queue)
1372 printer->queue = queue;
1373 else
1375 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1376 if (!printer->queue) {
1377 handle = 0;
1378 goto end;
1380 list_init(&printer->queue->jobs);
1381 printer->queue->ref = 0;
1383 InterlockedIncrement(&printer->queue->ref);
1385 printer_handles[handle] = printer;
1386 handle++;
1387 end:
1388 LeaveCriticalSection(&printer_handles_cs);
1389 if (!handle && printer) {
1390 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1391 free_printer_entry( printer );
1394 return (HANDLE)handle;
1397 static void old_printer_check( BOOL delete_phase )
1399 PRINTER_INFO_5W* pi;
1400 DWORD needed, type, num, delete, i, size;
1401 const DWORD one = 1;
1402 HKEY key;
1403 HANDLE hprn;
1405 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num );
1406 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
1408 pi = HeapAlloc( GetProcessHeap(), 0, needed );
1409 EnumPrintersW( PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num );
1410 for (i = 0; i < num; i++)
1412 if (strncmpW( pi[i].pPortName, CUPS_Port, strlenW(CUPS_Port) ) &&
1413 strncmpW( pi[i].pPortName, LPR_Port, strlenW(LPR_Port) ))
1414 continue;
1416 if (open_printer_reg_key( pi[i].pPrinterName, &key )) continue;
1418 if (!delete_phase)
1420 RegSetValueExW( key, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&one, sizeof(one) );
1421 RegCloseKey( key );
1423 else
1425 delete = 0;
1426 size = sizeof( delete );
1427 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&delete, &size );
1428 RegCloseKey( key );
1429 if (delete)
1431 TRACE( "Deleting old printer %s\n", debugstr_w(pi[i].pPrinterName) );
1432 if (OpenPrinterW( pi[i].pPrinterName, &hprn, NULL ))
1434 DeletePrinter( hprn );
1435 ClosePrinter( hprn );
1437 DeletePrinterDriverExW( NULL, NULL, pi[i].pPrinterName, 0, 0 );
1441 HeapFree(GetProcessHeap(), 0, pi);
1444 static const WCHAR winspool_mutex_name[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1445 'M','U','T','E','X','_','_','\0'};
1446 static HANDLE init_mutex;
1448 void WINSPOOL_LoadSystemPrinters(void)
1450 HKEY hkey, hkeyPrinters;
1451 DWORD needed, num, i;
1452 WCHAR PrinterName[256];
1453 BOOL done = FALSE;
1455 /* FIXME: The init code should be moved to spoolsv.exe */
1456 init_mutex = CreateMutexW( NULL, TRUE, winspool_mutex_name );
1457 if (!init_mutex)
1459 ERR( "Failed to create mutex\n" );
1460 return;
1462 if (GetLastError() == ERROR_ALREADY_EXISTS)
1464 WaitForSingleObject( init_mutex, INFINITE );
1465 ReleaseMutex( init_mutex );
1466 TRACE( "Init already done\n" );
1467 return;
1470 /* This ensures that all printer entries have a valid Name value. If causes
1471 problems later if they don't. If one is found to be missed we create one
1472 and set it equal to the name of the key */
1473 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1474 if(RegQueryInfoKeyW(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1475 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1476 for(i = 0; i < num; i++) {
1477 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1478 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1479 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1480 set_reg_szW(hkey, NameW, PrinterName);
1482 RegCloseKey(hkey);
1487 RegCloseKey(hkeyPrinters);
1490 old_printer_check( FALSE );
1492 #ifdef SONAME_LIBCUPS
1493 done = CUPS_LoadPrinters();
1494 #endif
1496 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1497 PRINTCAP_LoadPrinters();
1499 old_printer_check( TRUE );
1501 ReleaseMutex( init_mutex );
1502 return;
1505 /******************************************************************
1506 * get_job
1508 * Get the pointer to the specified job.
1509 * Should hold the printer_handles_cs before calling.
1511 static job_t *get_job(HANDLE hprn, DWORD JobId)
1513 opened_printer_t *printer = get_opened_printer(hprn);
1514 job_t *job;
1516 if(!printer) return NULL;
1517 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1519 if(job->job_id == JobId)
1520 return job;
1522 return NULL;
1525 /***********************************************************
1526 * DEVMODEcpyAtoW
1528 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1530 BOOL Formname;
1531 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1532 DWORD size;
1534 Formname = (dmA->dmSize > off_formname);
1535 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1536 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1537 dmW->dmDeviceName, CCHDEVICENAME);
1538 if(!Formname) {
1539 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1540 dmA->dmSize - CCHDEVICENAME);
1541 } else {
1542 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1543 off_formname - CCHDEVICENAME);
1544 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1545 dmW->dmFormName, CCHFORMNAME);
1546 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1547 (off_formname + CCHFORMNAME));
1549 dmW->dmSize = size;
1550 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1551 dmA->dmDriverExtra);
1552 return dmW;
1555 /******************************************************************
1556 * convert_printerinfo_W_to_A [internal]
1559 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1560 DWORD level, DWORD outlen, DWORD numentries)
1562 DWORD id = 0;
1563 LPSTR ptr;
1564 INT len;
1566 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1568 len = pi_sizeof[level] * numentries;
1569 ptr = (LPSTR) out + len;
1570 outlen -= len;
1572 /* copy the numbers of all PRINTER_INFO_* first */
1573 memcpy(out, pPrintersW, len);
1575 while (id < numentries) {
1576 switch (level) {
1577 case 1:
1579 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1580 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1582 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1583 if (piW->pDescription) {
1584 piA->pDescription = ptr;
1585 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1586 ptr, outlen, NULL, NULL);
1587 ptr += len;
1588 outlen -= len;
1590 if (piW->pName) {
1591 piA->pName = ptr;
1592 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1593 ptr, outlen, NULL, NULL);
1594 ptr += len;
1595 outlen -= len;
1597 if (piW->pComment) {
1598 piA->pComment = ptr;
1599 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1600 ptr, outlen, NULL, NULL);
1601 ptr += len;
1602 outlen -= len;
1604 break;
1607 case 2:
1609 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1610 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1611 LPDEVMODEA dmA;
1613 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1614 if (piW->pServerName) {
1615 piA->pServerName = ptr;
1616 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1617 ptr, outlen, NULL, NULL);
1618 ptr += len;
1619 outlen -= len;
1621 if (piW->pPrinterName) {
1622 piA->pPrinterName = ptr;
1623 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1624 ptr, outlen, NULL, NULL);
1625 ptr += len;
1626 outlen -= len;
1628 if (piW->pShareName) {
1629 piA->pShareName = ptr;
1630 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1631 ptr, outlen, NULL, NULL);
1632 ptr += len;
1633 outlen -= len;
1635 if (piW->pPortName) {
1636 piA->pPortName = ptr;
1637 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1638 ptr, outlen, NULL, NULL);
1639 ptr += len;
1640 outlen -= len;
1642 if (piW->pDriverName) {
1643 piA->pDriverName = ptr;
1644 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1645 ptr, outlen, NULL, NULL);
1646 ptr += len;
1647 outlen -= len;
1649 if (piW->pComment) {
1650 piA->pComment = ptr;
1651 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1652 ptr, outlen, NULL, NULL);
1653 ptr += len;
1654 outlen -= len;
1656 if (piW->pLocation) {
1657 piA->pLocation = ptr;
1658 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1659 ptr, outlen, NULL, NULL);
1660 ptr += len;
1661 outlen -= len;
1664 dmA = DEVMODEdupWtoA(piW->pDevMode);
1665 if (dmA) {
1666 /* align DEVMODEA to a DWORD boundary */
1667 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1668 ptr += len;
1669 outlen -= len;
1671 piA->pDevMode = (LPDEVMODEA) ptr;
1672 len = dmA->dmSize + dmA->dmDriverExtra;
1673 memcpy(ptr, dmA, len);
1674 HeapFree(GetProcessHeap(), 0, dmA);
1676 ptr += len;
1677 outlen -= len;
1680 if (piW->pSepFile) {
1681 piA->pSepFile = ptr;
1682 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1683 ptr, outlen, NULL, NULL);
1684 ptr += len;
1685 outlen -= len;
1687 if (piW->pPrintProcessor) {
1688 piA->pPrintProcessor = ptr;
1689 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1690 ptr, outlen, NULL, NULL);
1691 ptr += len;
1692 outlen -= len;
1694 if (piW->pDatatype) {
1695 piA->pDatatype = ptr;
1696 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1697 ptr, outlen, NULL, NULL);
1698 ptr += len;
1699 outlen -= len;
1701 if (piW->pParameters) {
1702 piA->pParameters = ptr;
1703 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1704 ptr, outlen, NULL, NULL);
1705 ptr += len;
1706 outlen -= len;
1708 if (piW->pSecurityDescriptor) {
1709 piA->pSecurityDescriptor = NULL;
1710 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1712 break;
1715 case 4:
1717 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1718 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1720 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1722 if (piW->pPrinterName) {
1723 piA->pPrinterName = ptr;
1724 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1725 ptr, outlen, NULL, NULL);
1726 ptr += len;
1727 outlen -= len;
1729 if (piW->pServerName) {
1730 piA->pServerName = ptr;
1731 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1732 ptr, outlen, NULL, NULL);
1733 ptr += len;
1734 outlen -= len;
1736 break;
1739 case 5:
1741 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1742 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1744 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1746 if (piW->pPrinterName) {
1747 piA->pPrinterName = ptr;
1748 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1749 ptr, outlen, NULL, NULL);
1750 ptr += len;
1751 outlen -= len;
1753 if (piW->pPortName) {
1754 piA->pPortName = ptr;
1755 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1756 ptr, outlen, NULL, NULL);
1757 ptr += len;
1758 outlen -= len;
1760 break;
1763 case 6: /* 6A and 6W are the same structure */
1764 break;
1766 case 7:
1768 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1769 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1771 TRACE("(%u) #%u\n", level, id);
1772 if (piW->pszObjectGUID) {
1773 piA->pszObjectGUID = ptr;
1774 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1775 ptr, outlen, NULL, NULL);
1776 ptr += len;
1777 outlen -= len;
1779 break;
1782 case 8:
1783 case 9:
1785 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1786 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1787 LPDEVMODEA dmA;
1789 TRACE("(%u) #%u\n", level, id);
1790 dmA = DEVMODEdupWtoA(piW->pDevMode);
1791 if (dmA) {
1792 /* align DEVMODEA to a DWORD boundary */
1793 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1794 ptr += len;
1795 outlen -= len;
1797 piA->pDevMode = (LPDEVMODEA) ptr;
1798 len = dmA->dmSize + dmA->dmDriverExtra;
1799 memcpy(ptr, dmA, len);
1800 HeapFree(GetProcessHeap(), 0, dmA);
1802 ptr += len;
1803 outlen -= len;
1806 break;
1809 default:
1810 FIXME("for level %u\n", level);
1812 pPrintersW += pi_sizeof[level];
1813 out += pi_sizeof[level];
1814 id++;
1818 /******************************************************************
1819 * convert_driverinfo_W_to_A [internal]
1822 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1823 DWORD level, DWORD outlen, DWORD numentries)
1825 DWORD id = 0;
1826 LPSTR ptr;
1827 INT len;
1829 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1831 len = di_sizeof[level] * numentries;
1832 ptr = (LPSTR) out + len;
1833 outlen -= len;
1835 /* copy the numbers of all PRINTER_INFO_* first */
1836 memcpy(out, pDriversW, len);
1838 #define COPY_STRING(fld) \
1839 { if (diW->fld){ \
1840 diA->fld = ptr; \
1841 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1842 ptr += len; outlen -= len;\
1844 #define COPY_MULTIZ_STRING(fld) \
1845 { LPWSTR p = diW->fld; if (p){ \
1846 diA->fld = ptr; \
1847 do {\
1848 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1849 ptr += len; outlen -= len; p += len;\
1851 while(len > 1 && outlen > 0); \
1854 while (id < numentries)
1856 switch (level)
1858 case 1:
1860 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1861 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1863 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1865 COPY_STRING(pName);
1866 break;
1868 case 2:
1870 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1871 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1873 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1875 COPY_STRING(pName);
1876 COPY_STRING(pEnvironment);
1877 COPY_STRING(pDriverPath);
1878 COPY_STRING(pDataFile);
1879 COPY_STRING(pConfigFile);
1880 break;
1882 case 3:
1884 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1885 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1887 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1889 COPY_STRING(pName);
1890 COPY_STRING(pEnvironment);
1891 COPY_STRING(pDriverPath);
1892 COPY_STRING(pDataFile);
1893 COPY_STRING(pConfigFile);
1894 COPY_STRING(pHelpFile);
1895 COPY_MULTIZ_STRING(pDependentFiles);
1896 COPY_STRING(pMonitorName);
1897 COPY_STRING(pDefaultDataType);
1898 break;
1900 case 4:
1902 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1903 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1905 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1907 COPY_STRING(pName);
1908 COPY_STRING(pEnvironment);
1909 COPY_STRING(pDriverPath);
1910 COPY_STRING(pDataFile);
1911 COPY_STRING(pConfigFile);
1912 COPY_STRING(pHelpFile);
1913 COPY_MULTIZ_STRING(pDependentFiles);
1914 COPY_STRING(pMonitorName);
1915 COPY_STRING(pDefaultDataType);
1916 COPY_MULTIZ_STRING(pszzPreviousNames);
1917 break;
1919 case 5:
1921 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1922 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1924 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1926 COPY_STRING(pName);
1927 COPY_STRING(pEnvironment);
1928 COPY_STRING(pDriverPath);
1929 COPY_STRING(pDataFile);
1930 COPY_STRING(pConfigFile);
1931 break;
1933 case 6:
1935 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1936 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1938 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1940 COPY_STRING(pName);
1941 COPY_STRING(pEnvironment);
1942 COPY_STRING(pDriverPath);
1943 COPY_STRING(pDataFile);
1944 COPY_STRING(pConfigFile);
1945 COPY_STRING(pHelpFile);
1946 COPY_MULTIZ_STRING(pDependentFiles);
1947 COPY_STRING(pMonitorName);
1948 COPY_STRING(pDefaultDataType);
1949 COPY_MULTIZ_STRING(pszzPreviousNames);
1950 COPY_STRING(pszMfgName);
1951 COPY_STRING(pszOEMUrl);
1952 COPY_STRING(pszHardwareID);
1953 COPY_STRING(pszProvider);
1954 break;
1956 case 8:
1958 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1959 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1961 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1963 COPY_STRING(pName);
1964 COPY_STRING(pEnvironment);
1965 COPY_STRING(pDriverPath);
1966 COPY_STRING(pDataFile);
1967 COPY_STRING(pConfigFile);
1968 COPY_STRING(pHelpFile);
1969 COPY_MULTIZ_STRING(pDependentFiles);
1970 COPY_STRING(pMonitorName);
1971 COPY_STRING(pDefaultDataType);
1972 COPY_MULTIZ_STRING(pszzPreviousNames);
1973 COPY_STRING(pszMfgName);
1974 COPY_STRING(pszOEMUrl);
1975 COPY_STRING(pszHardwareID);
1976 COPY_STRING(pszProvider);
1977 COPY_STRING(pszPrintProcessor);
1978 COPY_STRING(pszVendorSetup);
1979 COPY_MULTIZ_STRING(pszzColorProfiles);
1980 COPY_STRING(pszInfPath);
1981 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1982 break;
1986 default:
1987 FIXME("for level %u\n", level);
1990 pDriversW += di_sizeof[level];
1991 out += di_sizeof[level];
1992 id++;
1995 #undef COPY_STRING
1996 #undef COPY_MULTIZ_STRING
2000 /***********************************************************
2001 * printer_info_AtoW
2003 static void *printer_info_AtoW( const void *data, DWORD level )
2005 void *ret;
2006 UNICODE_STRING usBuffer;
2008 if (!data) return NULL;
2010 if (level < 1 || level > 9) return NULL;
2012 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
2013 if (!ret) return NULL;
2015 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
2017 switch (level)
2019 case 2:
2021 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
2022 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
2024 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
2025 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
2026 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
2027 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
2028 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
2029 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
2030 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
2031 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2032 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
2033 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
2034 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
2035 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
2036 break;
2039 case 8:
2040 case 9:
2042 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
2043 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
2045 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
2046 break;
2049 default:
2050 FIXME( "Unhandled level %d\n", level );
2051 HeapFree( GetProcessHeap(), 0, ret );
2052 return NULL;
2055 return ret;
2058 /***********************************************************
2059 * free_printer_info
2061 static void free_printer_info( void *data, DWORD level )
2063 if (!data) return;
2065 switch (level)
2067 case 2:
2069 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
2071 HeapFree( GetProcessHeap(), 0, piW->pServerName );
2072 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
2073 HeapFree( GetProcessHeap(), 0, piW->pShareName );
2074 HeapFree( GetProcessHeap(), 0, piW->pPortName );
2075 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
2076 HeapFree( GetProcessHeap(), 0, piW->pComment );
2077 HeapFree( GetProcessHeap(), 0, piW->pLocation );
2078 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2079 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
2080 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
2081 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
2082 HeapFree( GetProcessHeap(), 0, piW->pParameters );
2083 break;
2086 case 8:
2087 case 9:
2089 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
2091 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
2092 break;
2095 default:
2096 FIXME( "Unhandled level %d\n", level );
2099 HeapFree( GetProcessHeap(), 0, data );
2100 return;
2103 /******************************************************************
2104 * DeviceCapabilities [WINSPOOL.@]
2105 * DeviceCapabilitiesA [WINSPOOL.@]
2108 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2109 LPSTR pOutput, LPDEVMODEA lpdm)
2111 INT ret;
2113 if (!GDI_CallDeviceCapabilities16)
2115 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2116 (LPCSTR)104 );
2117 if (!GDI_CallDeviceCapabilities16) return -1;
2119 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2121 /* If DC_PAPERSIZE map POINT16s to POINTs */
2122 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2123 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2124 POINT *pt = (POINT *)pOutput;
2125 INT i;
2126 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2127 for(i = 0; i < ret; i++, pt++)
2129 pt->x = tmp[i].x;
2130 pt->y = tmp[i].y;
2132 HeapFree( GetProcessHeap(), 0, tmp );
2134 return ret;
2138 /*****************************************************************************
2139 * DeviceCapabilitiesW [WINSPOOL.@]
2141 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2144 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2145 WORD fwCapability, LPWSTR pOutput,
2146 const DEVMODEW *pDevMode)
2148 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2149 LPSTR pDeviceA = strdupWtoA(pDevice);
2150 LPSTR pPortA = strdupWtoA(pPort);
2151 INT ret;
2153 if(pOutput && (fwCapability == DC_BINNAMES ||
2154 fwCapability == DC_FILEDEPENDENCIES ||
2155 fwCapability == DC_PAPERNAMES)) {
2156 /* These need A -> W translation */
2157 INT size = 0, i;
2158 LPSTR pOutputA;
2159 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2160 dmA);
2161 if(ret == -1)
2162 return ret;
2163 switch(fwCapability) {
2164 case DC_BINNAMES:
2165 size = 24;
2166 break;
2167 case DC_PAPERNAMES:
2168 case DC_FILEDEPENDENCIES:
2169 size = 64;
2170 break;
2172 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2173 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2174 dmA);
2175 for(i = 0; i < ret; i++)
2176 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2177 pOutput + (i * size), size);
2178 HeapFree(GetProcessHeap(), 0, pOutputA);
2179 } else {
2180 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2181 (LPSTR)pOutput, dmA);
2183 HeapFree(GetProcessHeap(),0,pPortA);
2184 HeapFree(GetProcessHeap(),0,pDeviceA);
2185 HeapFree(GetProcessHeap(),0,dmA);
2186 return ret;
2189 /******************************************************************
2190 * DocumentPropertiesA [WINSPOOL.@]
2192 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2194 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2195 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2196 LPDEVMODEA pDevModeInput,DWORD fMode )
2198 LPSTR lpName = pDeviceName;
2199 static CHAR port[] = "LPT1:";
2200 LONG ret;
2202 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2203 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2206 if(!pDeviceName) {
2207 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2208 if(!lpNameW) {
2209 ERR("no name from hPrinter?\n");
2210 SetLastError(ERROR_INVALID_HANDLE);
2211 return -1;
2213 lpName = strdupWtoA(lpNameW);
2216 if (!GDI_CallExtDeviceMode16)
2218 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2219 (LPCSTR)102 );
2220 if (!GDI_CallExtDeviceMode16) {
2221 ERR("No CallExtDeviceMode16?\n");
2222 return -1;
2225 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2226 pDevModeInput, NULL, fMode);
2228 if(!pDeviceName)
2229 HeapFree(GetProcessHeap(),0,lpName);
2230 return ret;
2234 /*****************************************************************************
2235 * DocumentPropertiesW (WINSPOOL.@)
2237 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2239 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2240 LPWSTR pDeviceName,
2241 LPDEVMODEW pDevModeOutput,
2242 LPDEVMODEW pDevModeInput, DWORD fMode)
2245 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2246 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2247 LPDEVMODEA pDevModeOutputA = NULL;
2248 LONG ret;
2250 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2251 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2252 fMode);
2253 if(pDevModeOutput) {
2254 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2255 if(ret < 0) return ret;
2256 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2258 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2259 pDevModeInputA, fMode);
2260 if(pDevModeOutput) {
2261 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2262 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2264 if(fMode == 0 && ret > 0)
2265 ret += (CCHDEVICENAME + CCHFORMNAME);
2266 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2267 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2268 return ret;
2271 /*****************************************************************************
2272 * IsValidDevmodeA [WINSPOOL.@]
2274 * Validate a DEVMODE structure and fix errors if possible.
2277 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
2279 FIXME("(%p,%ld): stub\n", pDevMode, size);
2281 if(!pDevMode)
2282 return FALSE;
2284 return TRUE;
2287 /*****************************************************************************
2288 * IsValidDevmodeW [WINSPOOL.@]
2290 * Validate a DEVMODE structure and fix errors if possible.
2293 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
2295 FIXME("(%p,%ld): stub\n", pDevMode, size);
2297 if(!pDevMode)
2298 return FALSE;
2300 return TRUE;
2303 /******************************************************************
2304 * OpenPrinterA [WINSPOOL.@]
2306 * See OpenPrinterW.
2309 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2310 LPPRINTER_DEFAULTSA pDefault)
2312 UNICODE_STRING lpPrinterNameW;
2313 UNICODE_STRING usBuffer;
2314 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2315 PWSTR pwstrPrinterNameW;
2316 BOOL ret;
2318 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2320 if(pDefault) {
2321 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2322 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2323 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2324 pDefaultW = &DefaultW;
2326 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2327 if(pDefault) {
2328 RtlFreeUnicodeString(&usBuffer);
2329 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2331 RtlFreeUnicodeString(&lpPrinterNameW);
2332 return ret;
2335 /******************************************************************
2336 * OpenPrinterW [WINSPOOL.@]
2338 * Open a Printer / Printserver or a Printer-Object
2340 * PARAMS
2341 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2342 * phPrinter [O] The resulting Handle is stored here
2343 * pDefault [I] PTR to Default Printer Settings or NULL
2345 * RETURNS
2346 * Success: TRUE
2347 * Failure: FALSE
2349 * NOTES
2350 * lpPrinterName is one of:
2351 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2352 *| Printer: "PrinterName"
2353 *| Printer-Object: "PrinterName,Job xxx"
2354 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2355 *| XcvPort: "Servername,XcvPort PortName"
2357 * BUGS
2358 *| Printer-Object not supported
2359 *| pDefaults is ignored
2362 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2365 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2367 if(!phPrinter) {
2368 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2369 SetLastError(ERROR_INVALID_PARAMETER);
2370 return FALSE;
2373 /* Get the unique handle of the printer or Printserver */
2374 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2376 if (*phPrinter)
2378 HKEY key;
2379 DWORD deleting = 0, size = sizeof( deleting ), type;
2380 DWORD status;
2381 WINSPOOL_GetOpenedPrinterRegKey( *phPrinter, &key );
2382 RegQueryValueExW( key, May_Delete_Value, NULL, &type, (LPBYTE)&deleting, &size );
2383 WaitForSingleObject( init_mutex, INFINITE );
2384 status = get_dword_from_reg( key, StatusW );
2385 set_reg_DWORD( key, StatusW, status & ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
2386 ReleaseMutex( init_mutex );
2387 if (!deleting && (status & PRINTER_STATUS_DRIVER_UPDATE_NEEDED))
2388 update_driver( *phPrinter );
2389 RegCloseKey( key );
2392 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2393 return (*phPrinter != 0);
2396 /******************************************************************
2397 * AddMonitorA [WINSPOOL.@]
2399 * See AddMonitorW.
2402 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2404 LPWSTR nameW = NULL;
2405 INT len;
2406 BOOL res;
2407 LPMONITOR_INFO_2A mi2a;
2408 MONITOR_INFO_2W mi2w;
2410 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2411 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2412 debugstr_a(mi2a ? mi2a->pName : NULL),
2413 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2414 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2416 if (Level != 2) {
2417 SetLastError(ERROR_INVALID_LEVEL);
2418 return FALSE;
2421 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2422 if (mi2a == NULL) {
2423 return FALSE;
2426 if (pName) {
2427 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2428 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2429 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2432 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2433 if (mi2a->pName) {
2434 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2435 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2436 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2438 if (mi2a->pEnvironment) {
2439 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2440 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2441 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2443 if (mi2a->pDLLName) {
2444 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2445 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2446 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2449 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2451 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2452 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2453 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2455 HeapFree(GetProcessHeap(), 0, nameW);
2456 return (res);
2459 /******************************************************************************
2460 * AddMonitorW [WINSPOOL.@]
2462 * Install a Printmonitor
2464 * PARAMS
2465 * pName [I] Servername or NULL (local Computer)
2466 * Level [I] Structure-Level (Must be 2)
2467 * pMonitors [I] PTR to MONITOR_INFO_2
2469 * RETURNS
2470 * Success: TRUE
2471 * Failure: FALSE
2473 * NOTES
2474 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2477 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2479 LPMONITOR_INFO_2W mi2w;
2481 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2482 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2483 debugstr_w(mi2w ? mi2w->pName : NULL),
2484 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2485 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2487 if ((backend == NULL) && !load_backend()) return FALSE;
2489 if (Level != 2) {
2490 SetLastError(ERROR_INVALID_LEVEL);
2491 return FALSE;
2494 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2495 if (mi2w == NULL) {
2496 return FALSE;
2499 return backend->fpAddMonitor(pName, Level, pMonitors);
2502 /******************************************************************
2503 * DeletePrinterDriverA [WINSPOOL.@]
2506 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2508 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2511 /******************************************************************
2512 * DeletePrinterDriverW [WINSPOOL.@]
2515 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2517 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2520 /******************************************************************
2521 * DeleteMonitorA [WINSPOOL.@]
2523 * See DeleteMonitorW.
2526 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2528 LPWSTR nameW = NULL;
2529 LPWSTR EnvironmentW = NULL;
2530 LPWSTR MonitorNameW = NULL;
2531 BOOL res;
2532 INT len;
2534 if (pName) {
2535 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2536 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2537 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2540 if (pEnvironment) {
2541 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2542 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2543 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2545 if (pMonitorName) {
2546 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2547 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2548 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2551 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2553 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2554 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2555 HeapFree(GetProcessHeap(), 0, nameW);
2556 return (res);
2559 /******************************************************************
2560 * DeleteMonitorW [WINSPOOL.@]
2562 * Delete a specific Printmonitor from a Printing-Environment
2564 * PARAMS
2565 * pName [I] Servername or NULL (local Computer)
2566 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2567 * pMonitorName [I] Name of the Monitor, that should be deleted
2569 * RETURNS
2570 * Success: TRUE
2571 * Failure: FALSE
2573 * NOTES
2574 * pEnvironment is ignored in Windows for the local Computer.
2577 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2580 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2581 debugstr_w(pMonitorName));
2583 if ((backend == NULL) && !load_backend()) return FALSE;
2585 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2589 /******************************************************************
2590 * DeletePortA [WINSPOOL.@]
2592 * See DeletePortW.
2595 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2597 LPWSTR nameW = NULL;
2598 LPWSTR portW = NULL;
2599 INT len;
2600 DWORD res;
2602 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2604 /* convert servername to unicode */
2605 if (pName) {
2606 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2607 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2608 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2611 /* convert portname to unicode */
2612 if (pPortName) {
2613 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2614 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2615 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2618 res = DeletePortW(nameW, hWnd, portW);
2619 HeapFree(GetProcessHeap(), 0, nameW);
2620 HeapFree(GetProcessHeap(), 0, portW);
2621 return res;
2624 /******************************************************************
2625 * DeletePortW [WINSPOOL.@]
2627 * Delete a specific Port
2629 * PARAMS
2630 * pName [I] Servername or NULL (local Computer)
2631 * hWnd [I] Handle to parent Window for the Dialog-Box
2632 * pPortName [I] Name of the Port, that should be deleted
2634 * RETURNS
2635 * Success: TRUE
2636 * Failure: FALSE
2639 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2641 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2643 if ((backend == NULL) && !load_backend()) return FALSE;
2645 if (!pPortName) {
2646 SetLastError(RPC_X_NULL_REF_POINTER);
2647 return FALSE;
2650 return backend->fpDeletePort(pName, hWnd, pPortName);
2653 /******************************************************************************
2654 * WritePrinter [WINSPOOL.@]
2656 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2658 opened_printer_t *printer;
2659 BOOL ret = FALSE;
2661 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2663 EnterCriticalSection(&printer_handles_cs);
2664 printer = get_opened_printer(hPrinter);
2665 if(!printer)
2667 SetLastError(ERROR_INVALID_HANDLE);
2668 goto end;
2671 if(!printer->doc)
2673 SetLastError(ERROR_SPL_NO_STARTDOC);
2674 goto end;
2677 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2678 end:
2679 LeaveCriticalSection(&printer_handles_cs);
2680 return ret;
2683 /*****************************************************************************
2684 * AddFormA [WINSPOOL.@]
2686 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2688 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2689 return 1;
2692 /*****************************************************************************
2693 * AddFormW [WINSPOOL.@]
2695 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2697 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2698 return 1;
2701 /*****************************************************************************
2702 * AddJobA [WINSPOOL.@]
2704 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2706 BOOL ret;
2707 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2708 DWORD needed;
2710 if(Level != 1) {
2711 SetLastError(ERROR_INVALID_LEVEL);
2712 return FALSE;
2715 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2717 if(ret) {
2718 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2719 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2720 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2721 if(*pcbNeeded > cbBuf) {
2722 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2723 ret = FALSE;
2724 } else {
2725 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2726 addjobA->JobId = addjobW->JobId;
2727 addjobA->Path = (char *)(addjobA + 1);
2728 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2731 return ret;
2734 /*****************************************************************************
2735 * AddJobW [WINSPOOL.@]
2737 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2739 opened_printer_t *printer;
2740 job_t *job;
2741 BOOL ret = FALSE;
2742 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2743 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2744 WCHAR path[MAX_PATH], filename[MAX_PATH];
2745 DWORD len;
2746 ADDJOB_INFO_1W *addjob;
2748 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2750 EnterCriticalSection(&printer_handles_cs);
2752 printer = get_opened_printer(hPrinter);
2754 if(!printer) {
2755 SetLastError(ERROR_INVALID_HANDLE);
2756 goto end;
2759 if(Level != 1) {
2760 SetLastError(ERROR_INVALID_LEVEL);
2761 goto end;
2764 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2765 if(!job)
2766 goto end;
2768 job->job_id = InterlockedIncrement(&next_job_id);
2770 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2771 if(path[len - 1] != '\\')
2772 path[len++] = '\\';
2773 memcpy(path + len, spool_path, sizeof(spool_path));
2774 sprintfW(filename, fmtW, path, job->job_id);
2776 len = strlenW(filename);
2777 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2778 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2779 job->portname = NULL;
2780 job->document_title = strdupW(default_doc_title);
2781 job->printer_name = strdupW(printer->name);
2782 job->devmode = dup_devmode( printer->devmode );
2783 list_add_tail(&printer->queue->jobs, &job->entry);
2785 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2786 if(*pcbNeeded <= cbBuf) {
2787 addjob = (ADDJOB_INFO_1W*)pData;
2788 addjob->JobId = job->job_id;
2789 addjob->Path = (WCHAR *)(addjob + 1);
2790 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2791 ret = TRUE;
2792 } else
2793 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2795 end:
2796 LeaveCriticalSection(&printer_handles_cs);
2797 return ret;
2800 /*****************************************************************************
2801 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2803 * Return the PATH for the Print-Processors
2805 * See GetPrintProcessorDirectoryW.
2809 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2810 DWORD level, LPBYTE Info,
2811 DWORD cbBuf, LPDWORD pcbNeeded)
2813 LPWSTR serverW = NULL;
2814 LPWSTR envW = NULL;
2815 BOOL ret;
2816 INT len;
2818 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2819 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2822 if (server) {
2823 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2824 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2825 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2828 if (env) {
2829 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2830 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2831 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2834 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2835 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2837 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2838 cbBuf, pcbNeeded);
2840 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2841 cbBuf, NULL, NULL) > 0;
2844 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2845 HeapFree(GetProcessHeap(), 0, envW);
2846 HeapFree(GetProcessHeap(), 0, serverW);
2847 return ret;
2850 /*****************************************************************************
2851 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2853 * Return the PATH for the Print-Processors
2855 * PARAMS
2856 * server [I] Servername (NT only) or NULL (local Computer)
2857 * env [I] Printing-Environment (see below) or NULL (Default)
2858 * level [I] Structure-Level (must be 1)
2859 * Info [O] PTR to Buffer that receives the Result
2860 * cbBuf [I] Size of Buffer at "Info"
2861 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2862 * required for the Buffer at "Info"
2864 * RETURNS
2865 * Success: TRUE and in pcbNeeded the Bytes used in Info
2866 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2867 * if cbBuf is too small
2869 * Native Values returned in Info on Success:
2870 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2871 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2872 *| win9x(Windows 4.0): "%winsysdir%"
2874 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2876 * BUGS
2877 * Only NULL or "" is supported for server
2880 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2881 DWORD level, LPBYTE Info,
2882 DWORD cbBuf, LPDWORD pcbNeeded)
2885 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2886 Info, cbBuf, pcbNeeded);
2888 if ((backend == NULL) && !load_backend()) return FALSE;
2890 if (level != 1) {
2891 /* (Level != 1) is ignored in win9x */
2892 SetLastError(ERROR_INVALID_LEVEL);
2893 return FALSE;
2896 if (pcbNeeded == NULL) {
2897 /* (pcbNeeded == NULL) is ignored in win9x */
2898 SetLastError(RPC_X_NULL_REF_POINTER);
2899 return FALSE;
2902 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2905 /*****************************************************************************
2906 * WINSPOOL_OpenDriverReg [internal]
2908 * opens the registry for the printer drivers depending on the given input
2909 * variable pEnvironment
2911 * RETURNS:
2912 * the opened hkey on success
2913 * NULL on error
2915 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2917 HKEY retval = NULL;
2918 LPWSTR buffer;
2919 const printenv_t * env;
2921 TRACE("(%s)\n", debugstr_w(pEnvironment));
2923 env = validate_envW(pEnvironment);
2924 if (!env) return NULL;
2926 buffer = HeapAlloc( GetProcessHeap(), 0,
2927 (strlenW(DriversW) + strlenW(env->envname) +
2928 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2929 if(buffer) {
2930 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2931 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2932 HeapFree(GetProcessHeap(), 0, buffer);
2934 return retval;
2937 /*****************************************************************************
2938 * set_devices_and_printerports [internal]
2940 * set the [Devices] and [PrinterPorts] entries for a printer.
2943 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2945 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2946 WCHAR *devline;
2947 HKEY hkey;
2949 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2951 /* FIXME: the driver must change to "winspool" */
2952 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2953 if (devline) {
2954 lstrcpyW(devline, driver_nt);
2955 lstrcatW(devline, commaW);
2956 lstrcatW(devline, pi->pPortName);
2958 TRACE("using %s\n", debugstr_w(devline));
2959 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2960 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2961 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2962 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2963 RegCloseKey(hkey);
2966 lstrcatW(devline, timeout_15_45);
2967 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2968 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2969 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2970 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2971 RegCloseKey(hkey);
2973 HeapFree(GetProcessHeap(), 0, devline);
2977 /*****************************************************************************
2978 * AddPrinterW [WINSPOOL.@]
2980 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2982 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2983 LPDEVMODEW dm;
2984 HANDLE retval;
2985 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2986 LONG size;
2988 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2990 if(pName != NULL) {
2991 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2992 SetLastError(ERROR_INVALID_PARAMETER);
2993 return 0;
2995 if(Level != 2) {
2996 ERR("Level = %d, unsupported!\n", Level);
2997 SetLastError(ERROR_INVALID_LEVEL);
2998 return 0;
3000 if(!pPrinter) {
3001 SetLastError(ERROR_INVALID_PARAMETER);
3002 return 0;
3004 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3005 ERROR_SUCCESS) {
3006 ERR("Can't create Printers key\n");
3007 return 0;
3009 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3010 if (!RegQueryValueW(hkeyPrinter, AttributesW, NULL, NULL)) {
3011 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3012 RegCloseKey(hkeyPrinter);
3013 RegCloseKey(hkeyPrinters);
3014 return 0;
3016 RegCloseKey(hkeyPrinter);
3018 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
3019 if(!hkeyDrivers) {
3020 ERR("Can't create Drivers key\n");
3021 RegCloseKey(hkeyPrinters);
3022 return 0;
3024 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3025 ERROR_SUCCESS) {
3026 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3027 RegCloseKey(hkeyPrinters);
3028 RegCloseKey(hkeyDrivers);
3029 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3030 return 0;
3032 RegCloseKey(hkeyDriver);
3033 RegCloseKey(hkeyDrivers);
3035 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3036 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3037 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3038 RegCloseKey(hkeyPrinters);
3039 return 0;
3042 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3043 ERROR_SUCCESS) {
3044 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3045 SetLastError(ERROR_INVALID_PRINTER_NAME);
3046 RegCloseKey(hkeyPrinters);
3047 return 0;
3050 set_devices_and_printerports(pi);
3052 set_reg_DWORD(hkeyPrinter, AttributesW, pi->Attributes);
3053 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3054 set_reg_DWORD(hkeyPrinter, Default_PriorityW, pi->DefaultPriority);
3055 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3056 set_reg_DWORD(hkeyPrinter, dnsTimeoutW, 0);
3057 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3058 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3059 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3060 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3061 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3062 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3063 set_reg_DWORD(hkeyPrinter, PriorityW, pi->Priority);
3064 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3065 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3066 set_reg_DWORD(hkeyPrinter, StartTimeW, pi->StartTime);
3067 set_reg_DWORD(hkeyPrinter, StatusW, pi->Status);
3068 set_reg_DWORD(hkeyPrinter, txTimeoutW, 0);
3069 set_reg_DWORD(hkeyPrinter, UntilTimeW, pi->UntilTime);
3071 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3073 if (size < 0)
3075 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3076 size = sizeof(DEVMODEW);
3078 if(pi->pDevMode)
3079 dm = pi->pDevMode;
3080 else
3082 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3083 dm->dmSize = size;
3084 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
3086 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3087 HeapFree( GetProcessHeap(), 0, dm );
3088 dm = NULL;
3090 else
3092 /* set devmode to printer name */
3093 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
3097 set_reg_devmode( hkeyPrinter, Default_DevModeW, dm );
3098 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
3100 RegCloseKey(hkeyPrinter);
3101 RegCloseKey(hkeyPrinters);
3102 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3103 ERR("OpenPrinter failing\n");
3104 return 0;
3106 return retval;
3109 /*****************************************************************************
3110 * AddPrinterA [WINSPOOL.@]
3112 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3114 UNICODE_STRING pNameW;
3115 PWSTR pwstrNameW;
3116 PRINTER_INFO_2W *piW;
3117 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3118 HANDLE ret;
3120 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
3121 if(Level != 2) {
3122 ERR("Level = %d, unsupported!\n", Level);
3123 SetLastError(ERROR_INVALID_LEVEL);
3124 return 0;
3126 pwstrNameW = asciitounicode(&pNameW,pName);
3127 piW = printer_info_AtoW( piA, Level );
3129 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3131 free_printer_info( piW, Level );
3132 RtlFreeUnicodeString(&pNameW);
3133 return ret;
3137 /*****************************************************************************
3138 * ClosePrinter [WINSPOOL.@]
3140 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3142 UINT_PTR i = (UINT_PTR)hPrinter;
3143 opened_printer_t *printer = NULL;
3144 BOOL ret = FALSE;
3146 TRACE("(%p)\n", hPrinter);
3148 EnterCriticalSection(&printer_handles_cs);
3150 if ((i > 0) && (i <= nb_printer_handles))
3151 printer = printer_handles[i - 1];
3154 if(printer)
3156 struct list *cursor, *cursor2;
3158 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
3160 if (printer->backend_printer) {
3161 backend->fpClosePrinter(printer->backend_printer);
3164 if(printer->doc)
3165 EndDocPrinter(hPrinter);
3167 if(InterlockedDecrement(&printer->queue->ref) == 0)
3169 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3171 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3172 ScheduleJob(hPrinter, job->job_id);
3174 HeapFree(GetProcessHeap(), 0, printer->queue);
3177 free_printer_entry( printer );
3178 printer_handles[i - 1] = NULL;
3179 ret = TRUE;
3181 LeaveCriticalSection(&printer_handles_cs);
3182 return ret;
3185 /*****************************************************************************
3186 * DeleteFormA [WINSPOOL.@]
3188 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3190 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3191 return 1;
3194 /*****************************************************************************
3195 * DeleteFormW [WINSPOOL.@]
3197 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3199 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3200 return 1;
3203 /*****************************************************************************
3204 * DeletePrinter [WINSPOOL.@]
3206 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3208 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3209 HKEY hkeyPrinters, hkey;
3210 WCHAR def[MAX_PATH];
3211 DWORD size = sizeof( def ) / sizeof( def[0] );
3213 if(!lpNameW) {
3214 SetLastError(ERROR_INVALID_HANDLE);
3215 return FALSE;
3217 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3218 RegDeleteTreeW(hkeyPrinters, lpNameW);
3219 RegCloseKey(hkeyPrinters);
3221 WriteProfileStringW(devicesW, lpNameW, NULL);
3222 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
3224 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3225 RegDeleteValueW(hkey, lpNameW);
3226 RegCloseKey(hkey);
3229 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
3230 RegDeleteValueW(hkey, lpNameW);
3231 RegCloseKey(hkey);
3234 if (GetDefaultPrinterW( def, &size ) && !strcmpW( def, lpNameW ))
3236 WriteProfileStringW( windowsW, deviceW, NULL );
3237 if (!RegCreateKeyW( HKEY_CURRENT_USER, user_default_reg_key, &hkey ))
3239 RegDeleteValueW( hkey, deviceW );
3240 RegCloseKey( hkey );
3242 SetDefaultPrinterW( NULL );
3245 return TRUE;
3248 /*****************************************************************************
3249 * SetPrinterA [WINSPOOL.@]
3251 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3253 BYTE *dataW = data;
3254 BOOL ret;
3256 if (level != 0)
3258 dataW = printer_info_AtoW( data, level );
3259 if (!dataW) return FALSE;
3262 ret = SetPrinterW( printer, level, dataW, command );
3264 if (dataW != data) free_printer_info( dataW, level );
3266 return ret;
3269 static void set_printer_2( HKEY key, const PRINTER_INFO_2W *pi )
3271 set_reg_szW( key, NameW, pi->pPrinterName );
3272 set_reg_szW( key, Share_NameW, pi->pShareName );
3273 set_reg_szW( key, PortW, pi->pPortName );
3274 set_reg_szW( key, Printer_DriverW, pi->pDriverName );
3275 set_reg_szW( key, DescriptionW, pi->pComment );
3276 set_reg_szW( key, LocationW, pi->pLocation );
3278 if (pi->pDevMode)
3279 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3281 set_reg_szW( key, Separator_FileW, pi->pSepFile );
3282 set_reg_szW( key, Print_ProcessorW, pi->pPrintProcessor );
3283 set_reg_szW( key, DatatypeW, pi->pDatatype );
3284 set_reg_szW( key, ParametersW, pi->pParameters );
3286 set_reg_DWORD( key, AttributesW, pi->Attributes );
3287 set_reg_DWORD( key, PriorityW, pi->Priority );
3288 set_reg_DWORD( key, Default_PriorityW, pi->DefaultPriority );
3289 set_reg_DWORD( key, StartTimeW, pi->StartTime );
3290 set_reg_DWORD( key, UntilTimeW, pi->UntilTime );
3293 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
3295 if (!pi->pDevMode) return FALSE;
3297 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
3298 return TRUE;
3301 /******************************************************************************
3302 * SetPrinterW [WINSPOOL.@]
3304 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
3306 HKEY key;
3307 BOOL ret = FALSE;
3309 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
3311 if (command != 0) FIXME( "Ignoring command %d\n", command );
3313 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
3314 return FALSE;
3316 switch (level)
3318 case 2:
3320 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)data;
3321 set_printer_2( key, pi2 );
3322 ret = TRUE;
3323 break;
3326 case 9:
3328 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
3329 ret = set_printer_9( key, pi );
3330 break;
3333 default:
3334 FIXME( "Unimplemented level %d\n", level );
3335 SetLastError( ERROR_INVALID_LEVEL );
3338 RegCloseKey( key );
3339 return ret;
3342 /*****************************************************************************
3343 * SetJobA [WINSPOOL.@]
3345 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3346 LPBYTE pJob, DWORD Command)
3348 BOOL ret;
3349 LPBYTE JobW;
3350 UNICODE_STRING usBuffer;
3352 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3354 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3355 are all ignored by SetJob, so we don't bother copying them */
3356 switch(Level)
3358 case 0:
3359 JobW = NULL;
3360 break;
3361 case 1:
3363 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3364 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3366 JobW = (LPBYTE)info1W;
3367 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3368 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3369 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3370 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3371 info1W->Status = info1A->Status;
3372 info1W->Priority = info1A->Priority;
3373 info1W->Position = info1A->Position;
3374 info1W->PagesPrinted = info1A->PagesPrinted;
3375 break;
3377 case 2:
3379 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3380 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3382 JobW = (LPBYTE)info2W;
3383 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3384 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3385 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3386 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3387 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3388 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3389 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3390 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3391 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3392 info2W->Status = info2A->Status;
3393 info2W->Priority = info2A->Priority;
3394 info2W->Position = info2A->Position;
3395 info2W->StartTime = info2A->StartTime;
3396 info2W->UntilTime = info2A->UntilTime;
3397 info2W->PagesPrinted = info2A->PagesPrinted;
3398 break;
3400 case 3:
3401 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3402 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3403 break;
3404 default:
3405 SetLastError(ERROR_INVALID_LEVEL);
3406 return FALSE;
3409 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3411 switch(Level)
3413 case 1:
3415 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3416 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3417 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3418 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3419 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3420 break;
3422 case 2:
3424 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3425 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3426 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3427 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3428 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3429 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3430 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3431 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3432 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3433 break;
3436 HeapFree(GetProcessHeap(), 0, JobW);
3438 return ret;
3441 /*****************************************************************************
3442 * SetJobW [WINSPOOL.@]
3444 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3445 LPBYTE pJob, DWORD Command)
3447 BOOL ret = FALSE;
3448 job_t *job;
3450 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3451 FIXME("Ignoring everything other than document title\n");
3453 EnterCriticalSection(&printer_handles_cs);
3454 job = get_job(hPrinter, JobId);
3455 if(!job)
3456 goto end;
3458 switch(Level)
3460 case 0:
3461 break;
3462 case 1:
3464 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3465 HeapFree(GetProcessHeap(), 0, job->document_title);
3466 job->document_title = strdupW(info1->pDocument);
3467 break;
3469 case 2:
3471 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3472 HeapFree(GetProcessHeap(), 0, job->document_title);
3473 job->document_title = strdupW(info2->pDocument);
3474 HeapFree(GetProcessHeap(), 0, job->devmode);
3475 job->devmode = dup_devmode( info2->pDevMode );
3476 break;
3478 case 3:
3479 break;
3480 default:
3481 SetLastError(ERROR_INVALID_LEVEL);
3482 goto end;
3484 ret = TRUE;
3485 end:
3486 LeaveCriticalSection(&printer_handles_cs);
3487 return ret;
3490 /*****************************************************************************
3491 * EndDocPrinter [WINSPOOL.@]
3493 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3495 opened_printer_t *printer;
3496 BOOL ret = FALSE;
3497 TRACE("(%p)\n", hPrinter);
3499 EnterCriticalSection(&printer_handles_cs);
3501 printer = get_opened_printer(hPrinter);
3502 if(!printer)
3504 SetLastError(ERROR_INVALID_HANDLE);
3505 goto end;
3508 if(!printer->doc)
3510 SetLastError(ERROR_SPL_NO_STARTDOC);
3511 goto end;
3514 CloseHandle(printer->doc->hf);
3515 ScheduleJob(hPrinter, printer->doc->job_id);
3516 HeapFree(GetProcessHeap(), 0, printer->doc);
3517 printer->doc = NULL;
3518 ret = TRUE;
3519 end:
3520 LeaveCriticalSection(&printer_handles_cs);
3521 return ret;
3524 /*****************************************************************************
3525 * EndPagePrinter [WINSPOOL.@]
3527 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3529 FIXME("(%p): stub\n", hPrinter);
3530 return TRUE;
3533 /*****************************************************************************
3534 * StartDocPrinterA [WINSPOOL.@]
3536 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3538 UNICODE_STRING usBuffer;
3539 DOC_INFO_2W doc2W;
3540 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3541 DWORD ret;
3543 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3544 or one (DOC_INFO_3) extra DWORDs */
3546 switch(Level) {
3547 case 2:
3548 doc2W.JobId = doc2->JobId;
3549 /* fall through */
3550 case 3:
3551 doc2W.dwMode = doc2->dwMode;
3552 /* fall through */
3553 case 1:
3554 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3555 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3556 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3557 break;
3559 default:
3560 SetLastError(ERROR_INVALID_LEVEL);
3561 return FALSE;
3564 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3566 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3567 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3568 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3570 return ret;
3573 /*****************************************************************************
3574 * StartDocPrinterW [WINSPOOL.@]
3576 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3578 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3579 opened_printer_t *printer;
3580 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3581 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3582 JOB_INFO_1W job_info;
3583 DWORD needed, ret = 0;
3584 HANDLE hf;
3585 WCHAR *filename;
3586 job_t *job;
3588 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3589 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3590 debugstr_w(doc->pDatatype));
3592 if(Level < 1 || Level > 3)
3594 SetLastError(ERROR_INVALID_LEVEL);
3595 return 0;
3598 EnterCriticalSection(&printer_handles_cs);
3599 printer = get_opened_printer(hPrinter);
3600 if(!printer)
3602 SetLastError(ERROR_INVALID_HANDLE);
3603 goto end;
3606 if(printer->doc)
3608 SetLastError(ERROR_INVALID_PRINTER_STATE);
3609 goto end;
3612 /* Even if we're printing to a file we still add a print job, we'll
3613 just ignore the spool file name */
3615 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3617 ERR("AddJob failed gle %u\n", GetLastError());
3618 goto end;
3621 /* use pOutputFile only, when it is a real filename */
3622 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3623 filename = doc->pOutputFile;
3624 else
3625 filename = addjob->Path;
3627 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3628 if(hf == INVALID_HANDLE_VALUE)
3629 goto end;
3631 memset(&job_info, 0, sizeof(job_info));
3632 job_info.pDocument = doc->pDocName;
3633 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3635 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3636 printer->doc->hf = hf;
3637 ret = printer->doc->job_id = addjob->JobId;
3638 job = get_job(hPrinter, ret);
3639 job->portname = strdupW(doc->pOutputFile);
3641 end:
3642 LeaveCriticalSection(&printer_handles_cs);
3644 return ret;
3647 /*****************************************************************************
3648 * StartPagePrinter [WINSPOOL.@]
3650 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3652 FIXME("(%p): stub\n", hPrinter);
3653 return TRUE;
3656 /*****************************************************************************
3657 * GetFormA [WINSPOOL.@]
3659 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3660 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3662 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3663 Level,pForm,cbBuf,pcbNeeded);
3664 return FALSE;
3667 /*****************************************************************************
3668 * GetFormW [WINSPOOL.@]
3670 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3671 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3673 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3674 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3675 return FALSE;
3678 /*****************************************************************************
3679 * SetFormA [WINSPOOL.@]
3681 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3682 LPBYTE pForm)
3684 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3685 return FALSE;
3688 /*****************************************************************************
3689 * SetFormW [WINSPOOL.@]
3691 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3692 LPBYTE pForm)
3694 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3695 return FALSE;
3698 /*****************************************************************************
3699 * ReadPrinter [WINSPOOL.@]
3701 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3702 LPDWORD pNoBytesRead)
3704 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3705 return FALSE;
3708 /*****************************************************************************
3709 * ResetPrinterA [WINSPOOL.@]
3711 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3713 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3714 return FALSE;
3717 /*****************************************************************************
3718 * ResetPrinterW [WINSPOOL.@]
3720 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3722 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3723 return FALSE;
3726 /*****************************************************************************
3727 * get_filename_from_reg [internal]
3729 * Get ValueName from hkey storing result in out
3730 * when the Value in the registry has only a filename, use driverdir as prefix
3731 * outlen is space left in out
3732 * String is stored either as unicode or ascii
3736 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3737 LPBYTE out, DWORD outlen, LPDWORD needed)
3739 WCHAR filename[MAX_PATH];
3740 DWORD size;
3741 DWORD type;
3742 LONG ret;
3743 LPWSTR buffer = filename;
3744 LPWSTR ptr;
3746 *needed = 0;
3747 size = sizeof(filename);
3748 buffer[0] = '\0';
3749 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3750 if (ret == ERROR_MORE_DATA) {
3751 TRACE("need dynamic buffer: %u\n", size);
3752 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3753 if (!buffer) {
3754 /* No Memory is bad */
3755 return FALSE;
3757 buffer[0] = '\0';
3758 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3761 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3762 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3763 return FALSE;
3766 ptr = buffer;
3767 while (ptr) {
3768 /* do we have a full path ? */
3769 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3770 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3772 if (!ret) {
3773 /* we must build the full Path */
3774 *needed += dirlen;
3775 if ((out) && (outlen > dirlen)) {
3776 lstrcpyW((LPWSTR)out, driverdir);
3777 out += dirlen;
3778 outlen -= dirlen;
3780 else
3781 out = NULL;
3784 /* write the filename */
3785 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3786 if ((out) && (outlen >= size)) {
3787 lstrcpyW((LPWSTR)out, ptr);
3788 out += size;
3789 outlen -= size;
3791 else
3792 out = NULL;
3793 *needed += size;
3794 ptr += lstrlenW(ptr)+1;
3795 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3798 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3800 /* write the multisz-termination */
3801 if (type == REG_MULTI_SZ) {
3802 size = sizeof(WCHAR);
3804 *needed += size;
3805 if (out && (outlen >= size)) {
3806 memset (out, 0, size);
3809 return TRUE;
3812 /*****************************************************************************
3813 * WINSPOOL_GetStringFromReg
3815 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3816 * String is stored as unicode.
3818 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3819 DWORD buflen, DWORD *needed)
3821 DWORD sz = buflen, type;
3822 LONG ret;
3824 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3825 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3826 WARN("Got ret = %d\n", ret);
3827 *needed = 0;
3828 return FALSE;
3830 /* add space for terminating '\0' */
3831 sz += sizeof(WCHAR);
3832 *needed = sz;
3834 if (ptr)
3835 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3837 return TRUE;
3840 /*****************************************************************************
3841 * WINSPOOL_GetDefaultDevMode
3843 * Get a default DevMode values for wineps.
3844 * FIXME - use ppd.
3847 static void WINSPOOL_GetDefaultDevMode(
3848 LPBYTE ptr,
3849 DWORD buflen, DWORD *needed)
3851 DEVMODEW dm;
3852 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3854 /* fill default DEVMODE - should be read from ppd... */
3855 ZeroMemory( &dm, sizeof(dm) );
3856 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3857 dm.dmSpecVersion = DM_SPECVERSION;
3858 dm.dmDriverVersion = 1;
3859 dm.dmSize = sizeof(DEVMODEW);
3860 dm.dmDriverExtra = 0;
3861 dm.dmFields =
3862 DM_ORIENTATION | DM_PAPERSIZE |
3863 DM_PAPERLENGTH | DM_PAPERWIDTH |
3864 DM_SCALE |
3865 DM_COPIES |
3866 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3867 DM_YRESOLUTION | DM_TTOPTION;
3869 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3870 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3871 dm.u1.s1.dmPaperLength = 2970;
3872 dm.u1.s1.dmPaperWidth = 2100;
3874 dm.u1.s1.dmScale = 100;
3875 dm.u1.s1.dmCopies = 1;
3876 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3877 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3878 /* dm.dmColor */
3879 /* dm.dmDuplex */
3880 dm.dmYResolution = 300; /* 300dpi */
3881 dm.dmTTOption = DMTT_BITMAP;
3882 /* dm.dmCollate */
3883 /* dm.dmFormName */
3884 /* dm.dmLogPixels */
3885 /* dm.dmBitsPerPel */
3886 /* dm.dmPelsWidth */
3887 /* dm.dmPelsHeight */
3888 /* dm.u2.dmDisplayFlags */
3889 /* dm.dmDisplayFrequency */
3890 /* dm.dmICMMethod */
3891 /* dm.dmICMIntent */
3892 /* dm.dmMediaType */
3893 /* dm.dmDitherType */
3894 /* dm.dmReserved1 */
3895 /* dm.dmReserved2 */
3896 /* dm.dmPanningWidth */
3897 /* dm.dmPanningHeight */
3899 if(buflen >= sizeof(DEVMODEW))
3900 memcpy(ptr, &dm, sizeof(DEVMODEW));
3901 *needed = sizeof(DEVMODEW);
3904 /*****************************************************************************
3905 * WINSPOOL_GetDevModeFromReg
3907 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3908 * DevMode is stored either as unicode or ascii.
3910 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3911 LPBYTE ptr,
3912 DWORD buflen, DWORD *needed)
3914 DWORD sz = buflen, type;
3915 LONG ret;
3917 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3918 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3919 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3920 if (sz < sizeof(DEVMODEA))
3922 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3923 return FALSE;
3925 /* ensures that dmSize is not erratically bogus if registry is invalid */
3926 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3927 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3928 sz += (CCHDEVICENAME + CCHFORMNAME);
3929 if (ptr && (buflen >= sz)) {
3930 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3931 memcpy(ptr, dmW, sz);
3932 HeapFree(GetProcessHeap(),0,dmW);
3934 *needed = sz;
3935 return TRUE;
3938 /*********************************************************************
3939 * WINSPOOL_GetPrinter_1
3941 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3943 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3944 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3946 DWORD size, left = cbBuf;
3947 BOOL space = (cbBuf > 0);
3948 LPBYTE ptr = buf;
3950 *pcbNeeded = 0;
3952 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3953 if(space && size <= left) {
3954 pi1->pName = (LPWSTR)ptr;
3955 ptr += size;
3956 left -= size;
3957 } else
3958 space = FALSE;
3959 *pcbNeeded += size;
3962 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3963 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3964 if(space && size <= left) {
3965 pi1->pDescription = (LPWSTR)ptr;
3966 ptr += size;
3967 left -= size;
3968 } else
3969 space = FALSE;
3970 *pcbNeeded += size;
3973 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3974 if(space && size <= left) {
3975 pi1->pComment = (LPWSTR)ptr;
3976 ptr += size;
3977 left -= size;
3978 } else
3979 space = FALSE;
3980 *pcbNeeded += size;
3983 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3985 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3986 memset(pi1, 0, sizeof(*pi1));
3988 return space;
3990 /*********************************************************************
3991 * WINSPOOL_GetPrinter_2
3993 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3995 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3996 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3998 DWORD size, left = cbBuf;
3999 BOOL space = (cbBuf > 0);
4000 LPBYTE ptr = buf;
4002 *pcbNeeded = 0;
4004 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4005 if(space && size <= left) {
4006 pi2->pPrinterName = (LPWSTR)ptr;
4007 ptr += size;
4008 left -= size;
4009 } else
4010 space = FALSE;
4011 *pcbNeeded += size;
4013 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
4014 if(space && size <= left) {
4015 pi2->pShareName = (LPWSTR)ptr;
4016 ptr += size;
4017 left -= size;
4018 } else
4019 space = FALSE;
4020 *pcbNeeded += size;
4022 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4023 if(space && size <= left) {
4024 pi2->pPortName = (LPWSTR)ptr;
4025 ptr += size;
4026 left -= size;
4027 } else
4028 space = FALSE;
4029 *pcbNeeded += size;
4031 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
4032 if(space && size <= left) {
4033 pi2->pDriverName = (LPWSTR)ptr;
4034 ptr += size;
4035 left -= size;
4036 } else
4037 space = FALSE;
4038 *pcbNeeded += size;
4040 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
4041 if(space && size <= left) {
4042 pi2->pComment = (LPWSTR)ptr;
4043 ptr += size;
4044 left -= size;
4045 } else
4046 space = FALSE;
4047 *pcbNeeded += size;
4049 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
4050 if(space && size <= left) {
4051 pi2->pLocation = (LPWSTR)ptr;
4052 ptr += size;
4053 left -= size;
4054 } else
4055 space = FALSE;
4056 *pcbNeeded += size;
4058 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
4059 if(space && size <= left) {
4060 pi2->pDevMode = (LPDEVMODEW)ptr;
4061 ptr += size;
4062 left -= size;
4063 } else
4064 space = FALSE;
4065 *pcbNeeded += size;
4067 else
4069 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
4070 if(space && size <= left) {
4071 pi2->pDevMode = (LPDEVMODEW)ptr;
4072 ptr += size;
4073 left -= size;
4074 } else
4075 space = FALSE;
4076 *pcbNeeded += size;
4078 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
4079 if(space && size <= left) {
4080 pi2->pSepFile = (LPWSTR)ptr;
4081 ptr += size;
4082 left -= size;
4083 } else
4084 space = FALSE;
4085 *pcbNeeded += size;
4087 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
4088 if(space && size <= left) {
4089 pi2->pPrintProcessor = (LPWSTR)ptr;
4090 ptr += size;
4091 left -= size;
4092 } else
4093 space = FALSE;
4094 *pcbNeeded += size;
4096 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
4097 if(space && size <= left) {
4098 pi2->pDatatype = (LPWSTR)ptr;
4099 ptr += size;
4100 left -= size;
4101 } else
4102 space = FALSE;
4103 *pcbNeeded += size;
4105 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
4106 if(space && size <= left) {
4107 pi2->pParameters = (LPWSTR)ptr;
4108 ptr += size;
4109 left -= size;
4110 } else
4111 space = FALSE;
4112 *pcbNeeded += size;
4114 if(pi2) {
4115 pi2->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4116 pi2->Priority = get_dword_from_reg( hkeyPrinter, PriorityW );
4117 pi2->DefaultPriority = get_dword_from_reg( hkeyPrinter, Default_PriorityW );
4118 pi2->StartTime = get_dword_from_reg( hkeyPrinter, StartTimeW );
4119 pi2->UntilTime = get_dword_from_reg( hkeyPrinter, UntilTimeW );
4122 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4123 memset(pi2, 0, sizeof(*pi2));
4125 return space;
4128 /*********************************************************************
4129 * WINSPOOL_GetPrinter_4
4131 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4133 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4134 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4136 DWORD size, left = cbBuf;
4137 BOOL space = (cbBuf > 0);
4138 LPBYTE ptr = buf;
4140 *pcbNeeded = 0;
4142 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4143 if(space && size <= left) {
4144 pi4->pPrinterName = (LPWSTR)ptr;
4145 ptr += size;
4146 left -= size;
4147 } else
4148 space = FALSE;
4149 *pcbNeeded += size;
4151 if(pi4) {
4152 pi4->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4155 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4156 memset(pi4, 0, sizeof(*pi4));
4158 return space;
4161 /*********************************************************************
4162 * WINSPOOL_GetPrinter_5
4164 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4166 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4167 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
4169 DWORD size, left = cbBuf;
4170 BOOL space = (cbBuf > 0);
4171 LPBYTE ptr = buf;
4173 *pcbNeeded = 0;
4175 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
4176 if(space && size <= left) {
4177 pi5->pPrinterName = (LPWSTR)ptr;
4178 ptr += size;
4179 left -= size;
4180 } else
4181 space = FALSE;
4182 *pcbNeeded += size;
4184 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
4185 if(space && size <= left) {
4186 pi5->pPortName = (LPWSTR)ptr;
4187 ptr += size;
4188 left -= size;
4189 } else
4190 space = FALSE;
4191 *pcbNeeded += size;
4193 if(pi5) {
4194 pi5->Attributes = get_dword_from_reg( hkeyPrinter, AttributesW );
4195 pi5->DeviceNotSelectedTimeout = get_dword_from_reg( hkeyPrinter, dnsTimeoutW );
4196 pi5->TransmissionRetryTimeout = get_dword_from_reg( hkeyPrinter, txTimeoutW );
4199 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4200 memset(pi5, 0, sizeof(*pi5));
4202 return space;
4205 /*********************************************************************
4206 * WINSPOOL_GetPrinter_7
4208 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4210 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4211 DWORD cbBuf, LPDWORD pcbNeeded)
4213 DWORD size, left = cbBuf;
4214 BOOL space = (cbBuf > 0);
4215 LPBYTE ptr = buf;
4217 *pcbNeeded = 0;
4219 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
4221 ptr = NULL;
4222 size = sizeof(pi7->pszObjectGUID);
4224 if (space && size <= left) {
4225 pi7->pszObjectGUID = (LPWSTR)ptr;
4226 ptr += size;
4227 left -= size;
4228 } else
4229 space = FALSE;
4230 *pcbNeeded += size;
4231 if (pi7) {
4232 /* We do not have a Directory Service */
4233 pi7->dwAction = DSPRINT_UNPUBLISH;
4236 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4237 memset(pi7, 0, sizeof(*pi7));
4239 return space;
4242 /*********************************************************************
4243 * WINSPOOL_GetPrinter_9
4245 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4247 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4248 DWORD cbBuf, LPDWORD pcbNeeded)
4250 DWORD size;
4251 BOOL space = (cbBuf > 0);
4253 *pcbNeeded = 0;
4255 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
4256 if(space && size <= cbBuf) {
4257 pi9->pDevMode = (LPDEVMODEW)buf;
4258 } else
4259 space = FALSE;
4260 *pcbNeeded += size;
4262 else
4264 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
4265 if(space && size <= cbBuf) {
4266 pi9->pDevMode = (LPDEVMODEW)buf;
4267 } else
4268 space = FALSE;
4269 *pcbNeeded += size;
4272 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4273 memset(pi9, 0, sizeof(*pi9));
4275 return space;
4278 /*****************************************************************************
4279 * GetPrinterW [WINSPOOL.@]
4281 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4282 DWORD cbBuf, LPDWORD pcbNeeded)
4284 DWORD size, needed = 0, err;
4285 LPBYTE ptr = NULL;
4286 HKEY hkeyPrinter;
4287 BOOL ret;
4289 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4291 err = WINSPOOL_GetOpenedPrinterRegKey( hPrinter, &hkeyPrinter );
4292 if (err)
4294 SetLastError( err );
4295 return FALSE;
4298 switch(Level) {
4299 case 2:
4301 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4303 size = sizeof(PRINTER_INFO_2W);
4304 if(size <= cbBuf) {
4305 ptr = pPrinter + size;
4306 cbBuf -= size;
4307 memset(pPrinter, 0, size);
4308 } else {
4309 pi2 = NULL;
4310 cbBuf = 0;
4312 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
4313 needed += size;
4314 break;
4317 case 4:
4319 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4321 size = sizeof(PRINTER_INFO_4W);
4322 if(size <= cbBuf) {
4323 ptr = pPrinter + size;
4324 cbBuf -= size;
4325 memset(pPrinter, 0, size);
4326 } else {
4327 pi4 = NULL;
4328 cbBuf = 0;
4330 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
4331 needed += size;
4332 break;
4336 case 5:
4338 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4340 size = sizeof(PRINTER_INFO_5W);
4341 if(size <= cbBuf) {
4342 ptr = pPrinter + size;
4343 cbBuf -= size;
4344 memset(pPrinter, 0, size);
4345 } else {
4346 pi5 = NULL;
4347 cbBuf = 0;
4350 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
4351 needed += size;
4352 break;
4356 case 6:
4358 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4360 size = sizeof(PRINTER_INFO_6);
4361 if (size <= cbBuf) {
4362 /* FIXME: We do not update the status yet */
4363 pi6->dwStatus = get_dword_from_reg( hkeyPrinter, StatusW );
4364 ret = TRUE;
4365 } else {
4366 ret = FALSE;
4369 needed += size;
4370 break;
4373 case 7:
4375 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4377 size = sizeof(PRINTER_INFO_7W);
4378 if (size <= cbBuf) {
4379 ptr = pPrinter + size;
4380 cbBuf -= size;
4381 memset(pPrinter, 0, size);
4382 } else {
4383 pi7 = NULL;
4384 cbBuf = 0;
4387 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
4388 needed += size;
4389 break;
4393 case 8:
4394 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4395 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4396 /* fall through */
4397 case 9:
4399 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4401 size = sizeof(PRINTER_INFO_9W);
4402 if(size <= cbBuf) {
4403 ptr = pPrinter + size;
4404 cbBuf -= size;
4405 memset(pPrinter, 0, size);
4406 } else {
4407 pi9 = NULL;
4408 cbBuf = 0;
4411 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4412 needed += size;
4413 break;
4417 default:
4418 FIXME("Unimplemented level %d\n", Level);
4419 SetLastError(ERROR_INVALID_LEVEL);
4420 RegCloseKey(hkeyPrinter);
4421 return FALSE;
4424 RegCloseKey(hkeyPrinter);
4426 TRACE("returning %d needed = %d\n", ret, needed);
4427 if(pcbNeeded) *pcbNeeded = needed;
4428 if(!ret)
4429 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4430 return ret;
4433 /*****************************************************************************
4434 * GetPrinterA [WINSPOOL.@]
4436 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4437 DWORD cbBuf, LPDWORD pcbNeeded)
4439 BOOL ret;
4440 LPBYTE buf = NULL;
4442 if (cbBuf)
4443 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4445 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4446 if (ret)
4447 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4448 HeapFree(GetProcessHeap(), 0, buf);
4450 return ret;
4453 /*****************************************************************************
4454 * WINSPOOL_EnumPrintersW
4456 * Implementation of EnumPrintersW
4458 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4459 DWORD dwLevel, LPBYTE lpbPrinters,
4460 DWORD cbBuf, LPDWORD lpdwNeeded,
4461 LPDWORD lpdwReturned)
4464 HKEY hkeyPrinters, hkeyPrinter;
4465 WCHAR PrinterName[255];
4466 DWORD needed = 0, number = 0;
4467 DWORD used, i, left;
4468 PBYTE pi, buf;
4470 if(lpbPrinters)
4471 memset(lpbPrinters, 0, cbBuf);
4472 if(lpdwReturned)
4473 *lpdwReturned = 0;
4474 if(lpdwNeeded)
4475 *lpdwNeeded = 0;
4477 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4478 if(dwType == PRINTER_ENUM_DEFAULT)
4479 return TRUE;
4481 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4482 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4483 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4484 if (!dwType) {
4485 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4486 return TRUE;
4491 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4492 FIXME("dwType = %08x\n", dwType);
4493 SetLastError(ERROR_INVALID_FLAGS);
4494 return FALSE;
4497 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4498 ERROR_SUCCESS) {
4499 ERR("Can't create Printers key\n");
4500 return FALSE;
4503 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4504 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4505 RegCloseKey(hkeyPrinters);
4506 ERR("Can't query Printers key\n");
4507 return FALSE;
4509 TRACE("Found %d printers\n", number);
4511 switch(dwLevel) {
4512 case 1:
4513 used = number * sizeof(PRINTER_INFO_1W);
4514 break;
4515 case 2:
4516 used = number * sizeof(PRINTER_INFO_2W);
4517 break;
4518 case 4:
4519 used = number * sizeof(PRINTER_INFO_4W);
4520 break;
4521 case 5:
4522 used = number * sizeof(PRINTER_INFO_5W);
4523 break;
4525 default:
4526 SetLastError(ERROR_INVALID_LEVEL);
4527 RegCloseKey(hkeyPrinters);
4528 return FALSE;
4530 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4532 for(i = 0; i < number; i++) {
4533 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4534 ERROR_SUCCESS) {
4535 ERR("Can't enum key number %d\n", i);
4536 RegCloseKey(hkeyPrinters);
4537 return FALSE;
4539 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4540 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4541 ERROR_SUCCESS) {
4542 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4543 RegCloseKey(hkeyPrinters);
4544 return FALSE;
4547 if(cbBuf > used) {
4548 buf = lpbPrinters + used;
4549 left = cbBuf - used;
4550 } else {
4551 buf = NULL;
4552 left = 0;
4555 switch(dwLevel) {
4556 case 1:
4557 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4558 left, &needed);
4559 used += needed;
4560 if(pi) pi += sizeof(PRINTER_INFO_1W);
4561 break;
4562 case 2:
4563 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4564 left, &needed);
4565 used += needed;
4566 if(pi) pi += sizeof(PRINTER_INFO_2W);
4567 break;
4568 case 4:
4569 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4570 left, &needed);
4571 used += needed;
4572 if(pi) pi += sizeof(PRINTER_INFO_4W);
4573 break;
4574 case 5:
4575 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4576 left, &needed);
4577 used += needed;
4578 if(pi) pi += sizeof(PRINTER_INFO_5W);
4579 break;
4580 default:
4581 ERR("Shouldn't be here!\n");
4582 RegCloseKey(hkeyPrinter);
4583 RegCloseKey(hkeyPrinters);
4584 return FALSE;
4586 RegCloseKey(hkeyPrinter);
4588 RegCloseKey(hkeyPrinters);
4590 if(lpdwNeeded)
4591 *lpdwNeeded = used;
4593 if(used > cbBuf) {
4594 if(lpbPrinters)
4595 memset(lpbPrinters, 0, cbBuf);
4596 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4597 return FALSE;
4599 if(lpdwReturned)
4600 *lpdwReturned = number;
4601 SetLastError(ERROR_SUCCESS);
4602 return TRUE;
4606 /******************************************************************
4607 * EnumPrintersW [WINSPOOL.@]
4609 * Enumerates the available printers, print servers and print
4610 * providers, depending on the specified flags, name and level.
4612 * RETURNS:
4614 * If level is set to 1:
4615 * Returns an array of PRINTER_INFO_1 data structures in the
4616 * lpbPrinters buffer.
4618 * If level is set to 2:
4619 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4620 * Returns an array of PRINTER_INFO_2 data structures in the
4621 * lpbPrinters buffer. Note that according to MSDN also an
4622 * OpenPrinter should be performed on every remote printer.
4624 * If level is set to 4 (officially WinNT only):
4625 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4626 * Fast: Only the registry is queried to retrieve printer names,
4627 * no connection to the driver is made.
4628 * Returns an array of PRINTER_INFO_4 data structures in the
4629 * lpbPrinters buffer.
4631 * If level is set to 5 (officially WinNT4/Win9x only):
4632 * Fast: Only the registry is queried to retrieve printer names,
4633 * no connection to the driver is made.
4634 * Returns an array of PRINTER_INFO_5 data structures in the
4635 * lpbPrinters buffer.
4637 * If level set to 3 or 6+:
4638 * returns zero (failure!)
4640 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4641 * for information.
4643 * BUGS:
4644 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4645 * - Only levels 2, 4 and 5 are implemented at the moment.
4646 * - 16-bit printer drivers are not enumerated.
4647 * - Returned amount of bytes used/needed does not match the real Windoze
4648 * implementation (as in this implementation, all strings are part
4649 * of the buffer, whereas Win32 keeps them somewhere else)
4650 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4652 * NOTE:
4653 * - In a regular Wine installation, no registry settings for printers
4654 * exist, which makes this function return an empty list.
4656 BOOL WINAPI EnumPrintersW(
4657 DWORD dwType, /* [in] Types of print objects to enumerate */
4658 LPWSTR lpszName, /* [in] name of objects to enumerate */
4659 DWORD dwLevel, /* [in] type of printer info structure */
4660 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4661 DWORD cbBuf, /* [in] max size of buffer in bytes */
4662 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4663 LPDWORD lpdwReturned /* [out] number of entries returned */
4666 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4667 lpdwNeeded, lpdwReturned);
4670 /******************************************************************
4671 * EnumPrintersA [WINSPOOL.@]
4673 * See EnumPrintersW
4676 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4677 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4679 BOOL ret;
4680 UNICODE_STRING pNameU;
4681 LPWSTR pNameW;
4682 LPBYTE pPrintersW;
4684 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4685 pPrinters, cbBuf, pcbNeeded, pcReturned);
4687 pNameW = asciitounicode(&pNameU, pName);
4689 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4690 MS Office need this */
4691 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4693 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4695 RtlFreeUnicodeString(&pNameU);
4696 if (ret) {
4697 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4699 HeapFree(GetProcessHeap(), 0, pPrintersW);
4700 return ret;
4703 /*****************************************************************************
4704 * WINSPOOL_GetDriverInfoFromReg [internal]
4706 * Enters the information from the registry into the DRIVER_INFO struct
4708 * RETURNS
4709 * zero if the printer driver does not exist in the registry
4710 * (only if Level > 1) otherwise nonzero
4712 static BOOL WINSPOOL_GetDriverInfoFromReg(
4713 HKEY hkeyDrivers,
4714 LPWSTR DriverName,
4715 const printenv_t * env,
4716 DWORD Level,
4717 LPBYTE ptr, /* DRIVER_INFO */
4718 LPBYTE pDriverStrings, /* strings buffer */
4719 DWORD cbBuf, /* size of string buffer */
4720 LPDWORD pcbNeeded) /* space needed for str. */
4722 DWORD size, tmp;
4723 HKEY hkeyDriver;
4724 WCHAR driverdir[MAX_PATH];
4725 DWORD dirlen;
4726 LPBYTE strPtr = pDriverStrings;
4727 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4729 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4730 debugstr_w(DriverName), env,
4731 Level, di, pDriverStrings, cbBuf);
4733 if (di) ZeroMemory(di, di_sizeof[Level]);
4735 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4736 if (*pcbNeeded <= cbBuf)
4737 strcpyW((LPWSTR)strPtr, DriverName);
4739 /* pName for level 1 has a different offset! */
4740 if (Level == 1) {
4741 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4742 return TRUE;
4745 /* .cVersion and .pName for level > 1 */
4746 if (di) {
4747 di->cVersion = env->driverversion;
4748 di->pName = (LPWSTR) strPtr;
4749 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4752 /* Reserve Space for the largest subdir and a Backslash*/
4753 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4754 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4755 /* Should never Fail */
4756 return FALSE;
4758 lstrcatW(driverdir, env->versionsubdir);
4759 lstrcatW(driverdir, backslashW);
4761 /* dirlen must not include the terminating zero */
4762 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4764 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4765 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4766 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4767 return FALSE;
4770 /* pEnvironment */
4771 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4773 *pcbNeeded += size;
4774 if (*pcbNeeded <= cbBuf) {
4775 lstrcpyW((LPWSTR)strPtr, env->envname);
4776 if (di) di->pEnvironment = (LPWSTR)strPtr;
4777 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4780 /* .pDriverPath is the Graphics rendering engine.
4781 The full Path is required to avoid a crash in some apps */
4782 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4783 *pcbNeeded += size;
4784 if (*pcbNeeded <= cbBuf)
4785 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4787 if (di) di->pDriverPath = (LPWSTR)strPtr;
4788 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4791 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4792 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4793 *pcbNeeded += size;
4794 if (*pcbNeeded <= cbBuf)
4795 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4797 if (di) di->pDataFile = (LPWSTR)strPtr;
4798 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4801 /* .pConfigFile is the Driver user Interface */
4802 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4803 *pcbNeeded += size;
4804 if (*pcbNeeded <= cbBuf)
4805 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4807 if (di) di->pConfigFile = (LPWSTR)strPtr;
4808 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4811 if (Level == 2 ) {
4812 RegCloseKey(hkeyDriver);
4813 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4814 return TRUE;
4817 if (Level == 5 ) {
4818 RegCloseKey(hkeyDriver);
4819 FIXME("level 5: incomplete\n");
4820 return TRUE;
4823 /* .pHelpFile */
4824 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4825 *pcbNeeded += size;
4826 if (*pcbNeeded <= cbBuf)
4827 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4829 if (di) di->pHelpFile = (LPWSTR)strPtr;
4830 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4833 /* .pDependentFiles */
4834 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4835 *pcbNeeded += size;
4836 if (*pcbNeeded <= cbBuf)
4837 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4839 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4840 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4842 else if (GetVersion() & 0x80000000) {
4843 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4844 size = 2 * sizeof(WCHAR);
4845 *pcbNeeded += size;
4846 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4848 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4849 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4852 /* .pMonitorName is the optional Language Monitor */
4853 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4854 *pcbNeeded += size;
4855 if (*pcbNeeded <= cbBuf)
4856 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4858 if (di) di->pMonitorName = (LPWSTR)strPtr;
4859 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4862 /* .pDefaultDataType */
4863 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4864 *pcbNeeded += size;
4865 if(*pcbNeeded <= cbBuf)
4866 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4868 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4869 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4872 if (Level == 3 ) {
4873 RegCloseKey(hkeyDriver);
4874 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4875 return TRUE;
4878 /* .pszzPreviousNames */
4879 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4880 *pcbNeeded += size;
4881 if(*pcbNeeded <= cbBuf)
4882 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4884 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4885 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4888 if (Level == 4 ) {
4889 RegCloseKey(hkeyDriver);
4890 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4891 return TRUE;
4894 /* support is missing, but not important enough for a FIXME */
4895 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4897 /* .pszMfgName */
4898 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4899 *pcbNeeded += size;
4900 if(*pcbNeeded <= cbBuf)
4901 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4903 if (di) di->pszMfgName = (LPWSTR)strPtr;
4904 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4907 /* .pszOEMUrl */
4908 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4909 *pcbNeeded += size;
4910 if(*pcbNeeded <= cbBuf)
4911 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4913 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4914 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4917 /* .pszHardwareID */
4918 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4919 *pcbNeeded += size;
4920 if(*pcbNeeded <= cbBuf)
4921 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4923 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4924 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4927 /* .pszProvider */
4928 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4929 *pcbNeeded += size;
4930 if(*pcbNeeded <= cbBuf)
4931 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4933 if (di) di->pszProvider = (LPWSTR)strPtr;
4934 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4937 if (Level == 6 ) {
4938 RegCloseKey(hkeyDriver);
4939 return TRUE;
4942 /* support is missing, but not important enough for a FIXME */
4943 TRACE("level 8: incomplete\n");
4945 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4946 RegCloseKey(hkeyDriver);
4947 return TRUE;
4950 /*****************************************************************************
4951 * GetPrinterDriverW [WINSPOOL.@]
4953 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4954 DWORD Level, LPBYTE pDriverInfo,
4955 DWORD cbBuf, LPDWORD pcbNeeded)
4957 LPCWSTR name;
4958 WCHAR DriverName[100];
4959 DWORD ret, type, size, needed = 0;
4960 LPBYTE ptr = NULL;
4961 HKEY hkeyPrinter, hkeyDrivers;
4962 const printenv_t * env;
4964 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4965 Level,pDriverInfo,cbBuf, pcbNeeded);
4967 if (cbBuf > 0)
4968 ZeroMemory(pDriverInfo, cbBuf);
4970 if (!(name = get_opened_printer_name(hPrinter))) {
4971 SetLastError(ERROR_INVALID_HANDLE);
4972 return FALSE;
4975 if (Level < 1 || Level == 7 || Level > 8) {
4976 SetLastError(ERROR_INVALID_LEVEL);
4977 return FALSE;
4980 env = validate_envW(pEnvironment);
4981 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4983 ret = open_printer_reg_key( name, &hkeyPrinter );
4984 if (ret)
4986 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name) );
4987 SetLastError( ret );
4988 return FALSE;
4991 size = sizeof(DriverName);
4992 DriverName[0] = 0;
4993 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4994 (LPBYTE)DriverName, &size);
4995 RegCloseKey(hkeyPrinter);
4996 if(ret != ERROR_SUCCESS) {
4997 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4998 return FALSE;
5001 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5002 if(!hkeyDrivers) {
5003 ERR("Can't create Drivers key\n");
5004 return FALSE;
5007 size = di_sizeof[Level];
5008 if ((size <= cbBuf) && pDriverInfo)
5009 ptr = pDriverInfo + size;
5011 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5012 env, Level, pDriverInfo, ptr,
5013 (cbBuf < size) ? 0 : cbBuf - size,
5014 &needed)) {
5015 RegCloseKey(hkeyDrivers);
5016 return FALSE;
5019 RegCloseKey(hkeyDrivers);
5021 if(pcbNeeded) *pcbNeeded = size + needed;
5022 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5023 if(cbBuf >= size + needed) return TRUE;
5024 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5025 return FALSE;
5028 /*****************************************************************************
5029 * GetPrinterDriverA [WINSPOOL.@]
5031 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5032 DWORD Level, LPBYTE pDriverInfo,
5033 DWORD cbBuf, LPDWORD pcbNeeded)
5035 BOOL ret;
5036 UNICODE_STRING pEnvW;
5037 PWSTR pwstrEnvW;
5038 LPBYTE buf = NULL;
5040 if (cbBuf)
5042 ZeroMemory(pDriverInfo, cbBuf);
5043 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5046 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5047 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
5048 cbBuf, pcbNeeded);
5049 if (ret)
5050 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
5052 HeapFree(GetProcessHeap(), 0, buf);
5054 RtlFreeUnicodeString(&pEnvW);
5055 return ret;
5058 /*****************************************************************************
5059 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5061 * Return the PATH for the Printer-Drivers (UNICODE)
5063 * PARAMS
5064 * pName [I] Servername (NT only) or NULL (local Computer)
5065 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5066 * Level [I] Structure-Level (must be 1)
5067 * pDriverDirectory [O] PTR to Buffer that receives the Result
5068 * cbBuf [I] Size of Buffer at pDriverDirectory
5069 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5070 * required for pDriverDirectory
5072 * RETURNS
5073 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5074 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5075 * if cbBuf is too small
5077 * Native Values returned in pDriverDirectory on Success:
5078 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5079 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5080 *| win9x(Windows 4.0): "%winsysdir%"
5082 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5084 * FIXME
5085 *- Only NULL or "" is supported for pName
5088 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5089 DWORD Level, LPBYTE pDriverDirectory,
5090 DWORD cbBuf, LPDWORD pcbNeeded)
5092 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5093 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5095 if ((backend == NULL) && !load_backend()) return FALSE;
5097 if (Level != 1) {
5098 /* (Level != 1) is ignored in win9x */
5099 SetLastError(ERROR_INVALID_LEVEL);
5100 return FALSE;
5102 if (pcbNeeded == NULL) {
5103 /* (pcbNeeded == NULL) is ignored in win9x */
5104 SetLastError(RPC_X_NULL_REF_POINTER);
5105 return FALSE;
5108 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5109 pDriverDirectory, cbBuf, pcbNeeded);
5114 /*****************************************************************************
5115 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5117 * Return the PATH for the Printer-Drivers (ANSI)
5119 * See GetPrinterDriverDirectoryW.
5121 * NOTES
5122 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5125 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5126 DWORD Level, LPBYTE pDriverDirectory,
5127 DWORD cbBuf, LPDWORD pcbNeeded)
5129 UNICODE_STRING nameW, environmentW;
5130 BOOL ret;
5131 DWORD pcbNeededW;
5132 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5133 WCHAR *driverDirectoryW = NULL;
5135 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5136 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5138 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5140 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5141 else nameW.Buffer = NULL;
5142 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5143 else environmentW.Buffer = NULL;
5145 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5146 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5147 if (ret) {
5148 DWORD needed;
5149 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5150 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5151 if(pcbNeeded)
5152 *pcbNeeded = needed;
5153 ret = (needed <= cbBuf) ? TRUE : FALSE;
5154 } else
5155 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5157 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5159 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5160 RtlFreeUnicodeString(&environmentW);
5161 RtlFreeUnicodeString(&nameW);
5163 return ret;
5166 /*****************************************************************************
5167 * AddPrinterDriverA [WINSPOOL.@]
5169 * See AddPrinterDriverW.
5172 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5174 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5175 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5178 /******************************************************************************
5179 * AddPrinterDriverW (WINSPOOL.@)
5181 * Install a Printer Driver
5183 * PARAMS
5184 * pName [I] Servername or NULL (local Computer)
5185 * level [I] Level for the supplied DRIVER_INFO_*W struct
5186 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5188 * RESULTS
5189 * Success: TRUE
5190 * Failure: FALSE
5193 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5195 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5196 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5199 /*****************************************************************************
5200 * AddPrintProcessorA [WINSPOOL.@]
5202 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5203 LPSTR pPrintProcessorName)
5205 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5206 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5207 return FALSE;
5210 /*****************************************************************************
5211 * AddPrintProcessorW [WINSPOOL.@]
5213 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5214 LPWSTR pPrintProcessorName)
5216 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5217 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5218 return TRUE;
5221 /*****************************************************************************
5222 * AddPrintProvidorA [WINSPOOL.@]
5224 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5226 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5227 return FALSE;
5230 /*****************************************************************************
5231 * AddPrintProvidorW [WINSPOOL.@]
5233 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5235 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5236 return FALSE;
5239 /*****************************************************************************
5240 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5242 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5243 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5245 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5246 pDevModeOutput, pDevModeInput);
5247 return 0;
5250 /*****************************************************************************
5251 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5253 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5254 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5256 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5257 pDevModeOutput, pDevModeInput);
5258 return 0;
5261 /*****************************************************************************
5262 * PrinterProperties [WINSPOOL.@]
5264 * Displays a dialog to set the properties of the printer.
5266 * RETURNS
5267 * nonzero on success or zero on failure
5269 * BUGS
5270 * implemented as stub only
5272 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5273 HANDLE hPrinter /* [in] handle to printer object */
5275 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5276 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5277 return FALSE;
5280 /*****************************************************************************
5281 * EnumJobsA [WINSPOOL.@]
5284 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5285 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5286 LPDWORD pcReturned)
5288 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5289 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5291 if(pcbNeeded) *pcbNeeded = 0;
5292 if(pcReturned) *pcReturned = 0;
5293 return FALSE;
5297 /*****************************************************************************
5298 * EnumJobsW [WINSPOOL.@]
5301 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5302 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5303 LPDWORD pcReturned)
5305 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5306 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5308 if(pcbNeeded) *pcbNeeded = 0;
5309 if(pcReturned) *pcReturned = 0;
5310 return FALSE;
5313 /*****************************************************************************
5314 * WINSPOOL_EnumPrinterDrivers [internal]
5316 * Delivers information about all printer drivers installed on the
5317 * localhost or a given server
5319 * RETURNS
5320 * nonzero on success or zero on failure. If the buffer for the returned
5321 * information is too small the function will return an error
5323 * BUGS
5324 * - only implemented for localhost, foreign hosts will return an error
5326 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5327 DWORD Level, LPBYTE pDriverInfo,
5328 DWORD driver_index,
5329 DWORD cbBuf, LPDWORD pcbNeeded,
5330 LPDWORD pcFound, DWORD data_offset)
5332 { HKEY hkeyDrivers;
5333 DWORD i, size = 0;
5334 const printenv_t * env;
5336 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5337 debugstr_w(pName), debugstr_w(pEnvironment),
5338 Level, pDriverInfo, driver_index, cbBuf, data_offset);
5340 env = validate_envW(pEnvironment);
5341 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5343 *pcFound = 0;
5345 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
5346 if(!hkeyDrivers) {
5347 ERR("Can't open Drivers key\n");
5348 return FALSE;
5351 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
5352 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5353 RegCloseKey(hkeyDrivers);
5354 ERR("Can't query Drivers key\n");
5355 return FALSE;
5357 TRACE("Found %d Drivers\n", *pcFound);
5359 /* get size of single struct
5360 * unicode and ascii structure have the same size
5362 size = di_sizeof[Level];
5364 if (data_offset == 0)
5365 data_offset = size * (*pcFound);
5366 *pcbNeeded = data_offset;
5368 for( i = 0; i < *pcFound; i++) {
5369 WCHAR DriverNameW[255];
5370 PBYTE table_ptr = NULL;
5371 PBYTE data_ptr = NULL;
5372 DWORD needed = 0;
5374 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5375 != ERROR_SUCCESS) {
5376 ERR("Can't enum key number %d\n", i);
5377 RegCloseKey(hkeyDrivers);
5378 return FALSE;
5381 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
5382 table_ptr = pDriverInfo + (driver_index + i) * size;
5383 if (pDriverInfo && *pcbNeeded <= cbBuf)
5384 data_ptr = pDriverInfo + *pcbNeeded;
5386 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5387 env, Level, table_ptr, data_ptr,
5388 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5389 &needed)) {
5390 RegCloseKey(hkeyDrivers);
5391 return FALSE;
5394 *pcbNeeded += needed;
5397 RegCloseKey(hkeyDrivers);
5399 if(cbBuf < *pcbNeeded){
5400 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5401 return FALSE;
5404 return TRUE;
5407 /*****************************************************************************
5408 * EnumPrinterDriversW [WINSPOOL.@]
5410 * see function EnumPrinterDrivers for RETURNS, BUGS
5412 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5413 LPBYTE pDriverInfo, DWORD cbBuf,
5414 LPDWORD pcbNeeded, LPDWORD pcReturned)
5416 static const WCHAR allW[] = {'a','l','l',0};
5417 BOOL ret;
5418 DWORD found;
5420 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5422 SetLastError(RPC_X_NULL_REF_POINTER);
5423 return FALSE;
5426 /* check for local drivers */
5427 if((pName) && (pName[0])) {
5428 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5429 SetLastError(ERROR_ACCESS_DENIED);
5430 return FALSE;
5433 /* check input parameter */
5434 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5435 SetLastError(ERROR_INVALID_LEVEL);
5436 return FALSE;
5439 if(pDriverInfo && cbBuf > 0)
5440 memset( pDriverInfo, 0, cbBuf);
5442 /* Exception: pull all printers */
5443 if (pEnvironment && !strcmpW(pEnvironment, allW))
5445 DWORD i, needed, bufsize = cbBuf;
5446 DWORD total_needed = 0;
5447 DWORD total_found = 0;
5448 DWORD data_offset;
5450 /* Precompute the overall total; we need this to know
5451 where pointers end and data begins (i.e. data_offset) */
5452 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5454 needed = found = 0;
5455 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5456 NULL, 0, 0, &needed, &found, 0);
5457 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5458 total_needed += needed;
5459 total_found += found;
5462 data_offset = di_sizeof[Level] * total_found;
5464 *pcReturned = 0;
5465 *pcbNeeded = 0;
5466 total_found = 0;
5467 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5469 needed = found = 0;
5470 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5471 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5472 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5473 else if (ret)
5474 *pcReturned += found;
5475 *pcbNeeded = needed;
5476 data_offset = needed;
5477 total_found += found;
5479 return ret;
5482 /* Normal behavior */
5483 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5484 0, cbBuf, pcbNeeded, &found, 0);
5485 if (ret)
5486 *pcReturned = found;
5488 return ret;
5491 /*****************************************************************************
5492 * EnumPrinterDriversA [WINSPOOL.@]
5494 * see function EnumPrinterDrivers for RETURNS, BUGS
5496 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5497 LPBYTE pDriverInfo, DWORD cbBuf,
5498 LPDWORD pcbNeeded, LPDWORD pcReturned)
5500 BOOL ret;
5501 UNICODE_STRING pNameW, pEnvironmentW;
5502 PWSTR pwstrNameW, pwstrEnvironmentW;
5503 LPBYTE buf = NULL;
5505 if (cbBuf)
5506 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5508 pwstrNameW = asciitounicode(&pNameW, pName);
5509 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5511 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5512 buf, cbBuf, pcbNeeded, pcReturned);
5513 if (ret)
5514 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5516 HeapFree(GetProcessHeap(), 0, buf);
5518 RtlFreeUnicodeString(&pNameW);
5519 RtlFreeUnicodeString(&pEnvironmentW);
5521 return ret;
5524 /******************************************************************************
5525 * EnumPortsA (WINSPOOL.@)
5527 * See EnumPortsW.
5530 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5531 LPDWORD pcbNeeded, LPDWORD pcReturned)
5533 BOOL res;
5534 LPBYTE bufferW = NULL;
5535 LPWSTR nameW = NULL;
5536 DWORD needed = 0;
5537 DWORD numentries = 0;
5538 INT len;
5540 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5541 cbBuf, pcbNeeded, pcReturned);
5543 /* convert servername to unicode */
5544 if (pName) {
5545 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5546 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5547 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5549 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5550 needed = cbBuf * sizeof(WCHAR);
5551 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5552 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5554 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5555 if (pcbNeeded) needed = *pcbNeeded;
5556 /* HeapReAlloc return NULL, when bufferW was NULL */
5557 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5558 HeapAlloc(GetProcessHeap(), 0, needed);
5560 /* Try again with the large Buffer */
5561 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5563 needed = pcbNeeded ? *pcbNeeded : 0;
5564 numentries = pcReturned ? *pcReturned : 0;
5567 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5568 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5570 if (res) {
5571 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5572 DWORD entrysize = 0;
5573 DWORD index;
5574 LPSTR ptr;
5575 LPPORT_INFO_2W pi2w;
5576 LPPORT_INFO_2A pi2a;
5578 needed = 0;
5579 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5581 /* First pass: calculate the size for all Entries */
5582 pi2w = (LPPORT_INFO_2W) bufferW;
5583 pi2a = (LPPORT_INFO_2A) pPorts;
5584 index = 0;
5585 while (index < numentries) {
5586 index++;
5587 needed += entrysize; /* PORT_INFO_?A */
5588 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5590 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5591 NULL, 0, NULL, NULL);
5592 if (Level > 1) {
5593 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5594 NULL, 0, NULL, NULL);
5595 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5596 NULL, 0, NULL, NULL);
5598 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5599 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5600 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5603 /* check for errors and quit on failure */
5604 if (cbBuf < needed) {
5605 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5606 res = FALSE;
5607 goto cleanup;
5609 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5610 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5611 cbBuf -= len ; /* free Bytes in the user-Buffer */
5612 pi2w = (LPPORT_INFO_2W) bufferW;
5613 pi2a = (LPPORT_INFO_2A) pPorts;
5614 index = 0;
5615 /* Second Pass: Fill the User Buffer (if we have one) */
5616 while ((index < numentries) && pPorts) {
5617 index++;
5618 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5619 pi2a->pPortName = ptr;
5620 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5621 ptr, cbBuf , NULL, NULL);
5622 ptr += len;
5623 cbBuf -= len;
5624 if (Level > 1) {
5625 pi2a->pMonitorName = ptr;
5626 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5627 ptr, cbBuf, NULL, NULL);
5628 ptr += len;
5629 cbBuf -= len;
5631 pi2a->pDescription = ptr;
5632 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5633 ptr, cbBuf, NULL, NULL);
5634 ptr += len;
5635 cbBuf -= len;
5637 pi2a->fPortType = pi2w->fPortType;
5638 pi2a->Reserved = 0; /* documented: "must be zero" */
5641 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5642 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5643 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5647 cleanup:
5648 if (pcbNeeded) *pcbNeeded = needed;
5649 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5651 HeapFree(GetProcessHeap(), 0, nameW);
5652 HeapFree(GetProcessHeap(), 0, bufferW);
5654 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5655 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5657 return (res);
5661 /******************************************************************************
5662 * EnumPortsW (WINSPOOL.@)
5664 * Enumerate available Ports
5666 * PARAMS
5667 * pName [I] Servername or NULL (local Computer)
5668 * Level [I] Structure-Level (1 or 2)
5669 * pPorts [O] PTR to Buffer that receives the Result
5670 * cbBuf [I] Size of Buffer at pPorts
5671 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5672 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5674 * RETURNS
5675 * Success: TRUE
5676 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5679 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5682 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5683 cbBuf, pcbNeeded, pcReturned);
5685 if ((backend == NULL) && !load_backend()) return FALSE;
5687 /* Level is not checked in win9x */
5688 if (!Level || (Level > 2)) {
5689 WARN("level (%d) is ignored in win9x\n", Level);
5690 SetLastError(ERROR_INVALID_LEVEL);
5691 return FALSE;
5693 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5694 SetLastError(RPC_X_NULL_REF_POINTER);
5695 return FALSE;
5698 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5701 /******************************************************************************
5702 * GetDefaultPrinterW (WINSPOOL.@)
5704 * FIXME
5705 * This function must read the value from data 'device' of key
5706 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5708 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5710 BOOL retval = TRUE;
5711 DWORD insize, len;
5712 WCHAR *buffer, *ptr;
5714 if (!namesize)
5716 SetLastError(ERROR_INVALID_PARAMETER);
5717 return FALSE;
5720 /* make the buffer big enough for the stuff from the profile/registry,
5721 * the content must fit into the local buffer to compute the correct
5722 * size even if the extern buffer is too small or not given.
5723 * (20 for ,driver,port) */
5724 insize = *namesize;
5725 len = max(100, (insize + 20));
5726 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5728 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5730 SetLastError (ERROR_FILE_NOT_FOUND);
5731 retval = FALSE;
5732 goto end;
5734 TRACE("%s\n", debugstr_w(buffer));
5736 if ((ptr = strchrW(buffer, ',')) == NULL)
5738 SetLastError(ERROR_INVALID_NAME);
5739 retval = FALSE;
5740 goto end;
5743 *ptr = 0;
5744 *namesize = strlenW(buffer) + 1;
5745 if(!name || (*namesize > insize))
5747 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5748 retval = FALSE;
5749 goto end;
5751 strcpyW(name, buffer);
5753 end:
5754 HeapFree( GetProcessHeap(), 0, buffer);
5755 return retval;
5759 /******************************************************************************
5760 * GetDefaultPrinterA (WINSPOOL.@)
5762 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5764 BOOL retval = TRUE;
5765 DWORD insize = 0;
5766 WCHAR *bufferW = NULL;
5768 if (!namesize)
5770 SetLastError(ERROR_INVALID_PARAMETER);
5771 return FALSE;
5774 if(name && *namesize) {
5775 insize = *namesize;
5776 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5779 if(!GetDefaultPrinterW( bufferW, namesize)) {
5780 retval = FALSE;
5781 goto end;
5784 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5785 NULL, NULL);
5786 if (!*namesize)
5788 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5789 retval = FALSE;
5791 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5793 end:
5794 HeapFree( GetProcessHeap(), 0, bufferW);
5795 return retval;
5799 /******************************************************************************
5800 * SetDefaultPrinterW (WINSPOOL.204)
5802 * Set the Name of the Default Printer
5804 * PARAMS
5805 * pszPrinter [I] Name of the Printer or NULL
5807 * RETURNS
5808 * Success: True
5809 * Failure: FALSE
5811 * NOTES
5812 * When the Parameter is NULL or points to an Empty String and
5813 * a Default Printer was already present, then this Function changes nothing.
5814 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5815 * the First enumerated local Printer is used.
5818 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5820 WCHAR default_printer[MAX_PATH];
5821 LPWSTR buffer = NULL;
5822 HKEY hreg;
5823 DWORD size;
5824 DWORD namelen;
5825 LONG lres;
5827 TRACE("(%s)\n", debugstr_w(pszPrinter));
5828 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5830 default_printer[0] = '\0';
5831 size = sizeof(default_printer)/sizeof(WCHAR);
5833 /* if we have a default Printer, do nothing. */
5834 if (GetDefaultPrinterW(default_printer, &size))
5835 return TRUE;
5837 pszPrinter = NULL;
5838 /* we have no default Printer: search local Printers and use the first */
5839 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5841 default_printer[0] = '\0';
5842 size = sizeof(default_printer)/sizeof(WCHAR);
5843 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5845 pszPrinter = default_printer;
5846 TRACE("using %s\n", debugstr_w(pszPrinter));
5848 RegCloseKey(hreg);
5851 if (pszPrinter == NULL) {
5852 TRACE("no local printer found\n");
5853 SetLastError(ERROR_FILE_NOT_FOUND);
5854 return FALSE;
5858 /* "pszPrinter" is never empty or NULL here. */
5859 namelen = lstrlenW(pszPrinter);
5860 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5861 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5862 if (!buffer ||
5863 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5864 HeapFree(GetProcessHeap(), 0, buffer);
5865 SetLastError(ERROR_FILE_NOT_FOUND);
5866 return FALSE;
5869 /* read the devices entry for the printer (driver,port) to build the string for the
5870 default device entry (printer,driver,port) */
5871 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5872 buffer[namelen] = ',';
5873 namelen++; /* move index to the start of the driver */
5875 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5876 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5877 if (!lres) {
5878 TRACE("set device to %s\n", debugstr_w(buffer));
5880 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5881 TRACE("failed to set the device entry: %d\n", GetLastError());
5882 lres = ERROR_INVALID_PRINTER_NAME;
5885 /* remove the next section, when INIFileMapping is implemented */
5887 HKEY hdev;
5888 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5889 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5890 RegCloseKey(hdev);
5894 else
5896 if (lres != ERROR_FILE_NOT_FOUND)
5897 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5899 SetLastError(ERROR_INVALID_PRINTER_NAME);
5902 RegCloseKey(hreg);
5903 HeapFree(GetProcessHeap(), 0, buffer);
5904 return (lres == ERROR_SUCCESS);
5907 /******************************************************************************
5908 * SetDefaultPrinterA (WINSPOOL.202)
5910 * See SetDefaultPrinterW.
5913 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5915 LPWSTR bufferW = NULL;
5916 BOOL res;
5918 TRACE("(%s)\n", debugstr_a(pszPrinter));
5919 if(pszPrinter) {
5920 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5921 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5922 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5924 res = SetDefaultPrinterW(bufferW);
5925 HeapFree(GetProcessHeap(), 0, bufferW);
5926 return res;
5929 /******************************************************************************
5930 * SetPrinterDataExA (WINSPOOL.@)
5932 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5933 LPCSTR pValueName, DWORD Type,
5934 LPBYTE pData, DWORD cbData)
5936 HKEY hkeyPrinter, hkeySubkey;
5937 DWORD ret;
5939 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5940 debugstr_a(pValueName), Type, pData, cbData);
5942 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5943 != ERROR_SUCCESS)
5944 return ret;
5946 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5947 != ERROR_SUCCESS) {
5948 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5949 RegCloseKey(hkeyPrinter);
5950 return ret;
5952 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5953 RegCloseKey(hkeySubkey);
5954 RegCloseKey(hkeyPrinter);
5955 return ret;
5958 /******************************************************************************
5959 * SetPrinterDataExW (WINSPOOL.@)
5961 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5962 LPCWSTR pValueName, DWORD Type,
5963 LPBYTE pData, DWORD cbData)
5965 HKEY hkeyPrinter, hkeySubkey;
5966 DWORD ret;
5968 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5969 debugstr_w(pValueName), Type, pData, cbData);
5971 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5972 != ERROR_SUCCESS)
5973 return ret;
5975 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5976 != ERROR_SUCCESS) {
5977 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5978 RegCloseKey(hkeyPrinter);
5979 return ret;
5981 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5982 RegCloseKey(hkeySubkey);
5983 RegCloseKey(hkeyPrinter);
5984 return ret;
5987 /******************************************************************************
5988 * SetPrinterDataA (WINSPOOL.@)
5990 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5991 LPBYTE pData, DWORD cbData)
5993 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5994 pData, cbData);
5997 /******************************************************************************
5998 * SetPrinterDataW (WINSPOOL.@)
6000 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
6001 LPBYTE pData, DWORD cbData)
6003 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
6004 pData, cbData);
6007 /******************************************************************************
6008 * GetPrinterDataExA (WINSPOOL.@)
6010 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6011 LPCSTR pValueName, LPDWORD pType,
6012 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6014 opened_printer_t *printer;
6015 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6016 DWORD ret;
6018 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
6019 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
6021 printer = get_opened_printer(hPrinter);
6022 if(!printer) return ERROR_INVALID_HANDLE;
6024 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6025 if (ret) return ret;
6027 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6029 if (printer->name) {
6031 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6032 if (ret) {
6033 RegCloseKey(hkeyPrinters);
6034 return ret;
6036 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6037 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
6038 RegCloseKey(hkeyPrinter);
6039 RegCloseKey(hkeyPrinters);
6040 return ret;
6043 *pcbNeeded = nSize;
6044 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6045 0, pType, pData, pcbNeeded);
6047 if (!ret && !pData) ret = ERROR_MORE_DATA;
6049 RegCloseKey(hkeySubkey);
6050 RegCloseKey(hkeyPrinter);
6051 RegCloseKey(hkeyPrinters);
6053 TRACE("--> %d\n", ret);
6054 return ret;
6057 /******************************************************************************
6058 * GetPrinterDataExW (WINSPOOL.@)
6060 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6061 LPCWSTR pValueName, LPDWORD pType,
6062 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6064 opened_printer_t *printer;
6065 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
6066 DWORD ret;
6068 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
6069 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
6071 printer = get_opened_printer(hPrinter);
6072 if(!printer) return ERROR_INVALID_HANDLE;
6074 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
6075 if (ret) return ret;
6077 TRACE("printer->name: %s\n", debugstr_w(printer->name));
6079 if (printer->name) {
6081 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
6082 if (ret) {
6083 RegCloseKey(hkeyPrinters);
6084 return ret;
6086 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
6087 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
6088 RegCloseKey(hkeyPrinter);
6089 RegCloseKey(hkeyPrinters);
6090 return ret;
6093 *pcbNeeded = nSize;
6094 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
6095 0, pType, pData, pcbNeeded);
6097 if (!ret && !pData) ret = ERROR_MORE_DATA;
6099 RegCloseKey(hkeySubkey);
6100 RegCloseKey(hkeyPrinter);
6101 RegCloseKey(hkeyPrinters);
6103 TRACE("--> %d\n", ret);
6104 return ret;
6107 /******************************************************************************
6108 * GetPrinterDataA (WINSPOOL.@)
6110 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6111 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6113 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6114 pData, nSize, pcbNeeded);
6117 /******************************************************************************
6118 * GetPrinterDataW (WINSPOOL.@)
6120 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6121 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6123 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6124 pData, nSize, pcbNeeded);
6127 /*******************************************************************************
6128 * EnumPrinterDataExW [WINSPOOL.@]
6130 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6131 LPBYTE pEnumValues, DWORD cbEnumValues,
6132 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6134 HKEY hkPrinter, hkSubKey;
6135 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6136 cbValueNameLen, cbMaxValueLen, cbValueLen,
6137 cbBufSize, dwType;
6138 LPWSTR lpValueName;
6139 HANDLE hHeap;
6140 PBYTE lpValue;
6141 PPRINTER_ENUM_VALUESW ppev;
6143 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6145 if (pKeyName == NULL || *pKeyName == 0)
6146 return ERROR_INVALID_PARAMETER;
6148 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6149 if (ret != ERROR_SUCCESS)
6151 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6152 hPrinter, ret);
6153 return ret;
6156 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6157 if (ret != ERROR_SUCCESS)
6159 r = RegCloseKey (hkPrinter);
6160 if (r != ERROR_SUCCESS)
6161 WARN ("RegCloseKey returned %i\n", r);
6162 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6163 debugstr_w (pKeyName), ret);
6164 return ret;
6167 ret = RegCloseKey (hkPrinter);
6168 if (ret != ERROR_SUCCESS)
6170 ERR ("RegCloseKey returned %i\n", ret);
6171 r = RegCloseKey (hkSubKey);
6172 if (r != ERROR_SUCCESS)
6173 WARN ("RegCloseKey returned %i\n", r);
6174 return ret;
6177 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6178 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6179 if (ret != ERROR_SUCCESS)
6181 r = RegCloseKey (hkSubKey);
6182 if (r != ERROR_SUCCESS)
6183 WARN ("RegCloseKey returned %i\n", r);
6184 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6185 return ret;
6188 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6189 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6191 if (cValues == 0) /* empty key */
6193 r = RegCloseKey (hkSubKey);
6194 if (r != ERROR_SUCCESS)
6195 WARN ("RegCloseKey returned %i\n", r);
6196 *pcbEnumValues = *pnEnumValues = 0;
6197 return ERROR_SUCCESS;
6200 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6202 hHeap = GetProcessHeap ();
6203 if (hHeap == NULL)
6205 ERR ("GetProcessHeap failed\n");
6206 r = RegCloseKey (hkSubKey);
6207 if (r != ERROR_SUCCESS)
6208 WARN ("RegCloseKey returned %i\n", r);
6209 return ERROR_OUTOFMEMORY;
6212 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6213 if (lpValueName == NULL)
6215 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6216 r = RegCloseKey (hkSubKey);
6217 if (r != ERROR_SUCCESS)
6218 WARN ("RegCloseKey returned %i\n", r);
6219 return ERROR_OUTOFMEMORY;
6222 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6223 if (lpValue == NULL)
6225 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6226 if (HeapFree (hHeap, 0, lpValueName) == 0)
6227 WARN ("HeapFree failed with code %i\n", GetLastError ());
6228 r = RegCloseKey (hkSubKey);
6229 if (r != ERROR_SUCCESS)
6230 WARN ("RegCloseKey returned %i\n", r);
6231 return ERROR_OUTOFMEMORY;
6234 TRACE ("pass 1: calculating buffer required for all names and values\n");
6236 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6238 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6240 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6242 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6243 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6244 NULL, NULL, lpValue, &cbValueLen);
6245 if (ret != ERROR_SUCCESS)
6247 if (HeapFree (hHeap, 0, lpValue) == 0)
6248 WARN ("HeapFree failed with code %i\n", GetLastError ());
6249 if (HeapFree (hHeap, 0, lpValueName) == 0)
6250 WARN ("HeapFree failed with code %i\n", GetLastError ());
6251 r = RegCloseKey (hkSubKey);
6252 if (r != ERROR_SUCCESS)
6253 WARN ("RegCloseKey returned %i\n", r);
6254 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6255 return ret;
6258 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6259 debugstr_w (lpValueName), dwIndex,
6260 cbValueNameLen + 1, cbValueLen);
6262 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6263 cbBufSize += cbValueLen;
6266 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6268 *pcbEnumValues = cbBufSize;
6269 *pnEnumValues = cValues;
6271 if (cbEnumValues < cbBufSize) /* buffer too small */
6273 if (HeapFree (hHeap, 0, lpValue) == 0)
6274 WARN ("HeapFree failed with code %i\n", GetLastError ());
6275 if (HeapFree (hHeap, 0, lpValueName) == 0)
6276 WARN ("HeapFree failed with code %i\n", GetLastError ());
6277 r = RegCloseKey (hkSubKey);
6278 if (r != ERROR_SUCCESS)
6279 WARN ("RegCloseKey returned %i\n", r);
6280 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6281 return ERROR_MORE_DATA;
6284 TRACE ("pass 2: copying all names and values to buffer\n");
6286 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6287 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6289 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6291 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6292 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6293 NULL, &dwType, lpValue, &cbValueLen);
6294 if (ret != ERROR_SUCCESS)
6296 if (HeapFree (hHeap, 0, lpValue) == 0)
6297 WARN ("HeapFree failed with code %i\n", GetLastError ());
6298 if (HeapFree (hHeap, 0, lpValueName) == 0)
6299 WARN ("HeapFree failed with code %i\n", GetLastError ());
6300 r = RegCloseKey (hkSubKey);
6301 if (r != ERROR_SUCCESS)
6302 WARN ("RegCloseKey returned %i\n", r);
6303 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6304 return ret;
6307 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6308 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6309 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6310 pEnumValues += cbValueNameLen;
6312 /* return # of *bytes* (including trailing \0), not # of chars */
6313 ppev[dwIndex].cbValueName = cbValueNameLen;
6315 ppev[dwIndex].dwType = dwType;
6317 memcpy (pEnumValues, lpValue, cbValueLen);
6318 ppev[dwIndex].pData = pEnumValues;
6319 pEnumValues += cbValueLen;
6321 ppev[dwIndex].cbData = cbValueLen;
6323 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6324 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6327 if (HeapFree (hHeap, 0, lpValue) == 0)
6329 ret = GetLastError ();
6330 ERR ("HeapFree failed with code %i\n", ret);
6331 if (HeapFree (hHeap, 0, lpValueName) == 0)
6332 WARN ("HeapFree failed with code %i\n", GetLastError ());
6333 r = RegCloseKey (hkSubKey);
6334 if (r != ERROR_SUCCESS)
6335 WARN ("RegCloseKey returned %i\n", r);
6336 return ret;
6339 if (HeapFree (hHeap, 0, lpValueName) == 0)
6341 ret = GetLastError ();
6342 ERR ("HeapFree failed with code %i\n", ret);
6343 r = RegCloseKey (hkSubKey);
6344 if (r != ERROR_SUCCESS)
6345 WARN ("RegCloseKey returned %i\n", r);
6346 return ret;
6349 ret = RegCloseKey (hkSubKey);
6350 if (ret != ERROR_SUCCESS)
6352 ERR ("RegCloseKey returned %i\n", ret);
6353 return ret;
6356 return ERROR_SUCCESS;
6359 /*******************************************************************************
6360 * EnumPrinterDataExA [WINSPOOL.@]
6362 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6363 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6364 * what Windows 2000 SP1 does.
6367 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6368 LPBYTE pEnumValues, DWORD cbEnumValues,
6369 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6371 INT len;
6372 LPWSTR pKeyNameW;
6373 DWORD ret, dwIndex, dwBufSize;
6374 HANDLE hHeap;
6375 LPSTR pBuffer;
6377 TRACE ("%p %s\n", hPrinter, pKeyName);
6379 if (pKeyName == NULL || *pKeyName == 0)
6380 return ERROR_INVALID_PARAMETER;
6382 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6383 if (len == 0)
6385 ret = GetLastError ();
6386 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6387 return ret;
6390 hHeap = GetProcessHeap ();
6391 if (hHeap == NULL)
6393 ERR ("GetProcessHeap failed\n");
6394 return ERROR_OUTOFMEMORY;
6397 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6398 if (pKeyNameW == NULL)
6400 ERR ("Failed to allocate %i bytes from process heap\n",
6401 (LONG)(len * sizeof (WCHAR)));
6402 return ERROR_OUTOFMEMORY;
6405 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6407 ret = GetLastError ();
6408 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6409 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6410 WARN ("HeapFree failed with code %i\n", GetLastError ());
6411 return ret;
6414 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6415 pcbEnumValues, pnEnumValues);
6416 if (ret != ERROR_SUCCESS)
6418 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6419 WARN ("HeapFree failed with code %i\n", GetLastError ());
6420 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6421 return ret;
6424 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6426 ret = GetLastError ();
6427 ERR ("HeapFree failed with code %i\n", ret);
6428 return ret;
6431 if (*pnEnumValues == 0) /* empty key */
6432 return ERROR_SUCCESS;
6434 dwBufSize = 0;
6435 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6437 PPRINTER_ENUM_VALUESW ppev =
6438 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6440 if (dwBufSize < ppev->cbValueName)
6441 dwBufSize = ppev->cbValueName;
6443 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6444 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6445 dwBufSize = ppev->cbData;
6448 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6450 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6451 if (pBuffer == NULL)
6453 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6454 return ERROR_OUTOFMEMORY;
6457 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6459 PPRINTER_ENUM_VALUESW ppev =
6460 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6462 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6463 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6464 NULL);
6465 if (len == 0)
6467 ret = GetLastError ();
6468 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6469 if (HeapFree (hHeap, 0, pBuffer) == 0)
6470 WARN ("HeapFree failed with code %i\n", GetLastError ());
6471 return ret;
6474 memcpy (ppev->pValueName, pBuffer, len);
6476 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6478 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6479 ppev->dwType != REG_MULTI_SZ)
6480 continue;
6482 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6483 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6484 if (len == 0)
6486 ret = GetLastError ();
6487 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6488 if (HeapFree (hHeap, 0, pBuffer) == 0)
6489 WARN ("HeapFree failed with code %i\n", GetLastError ());
6490 return ret;
6493 memcpy (ppev->pData, pBuffer, len);
6495 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6496 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6499 if (HeapFree (hHeap, 0, pBuffer) == 0)
6501 ret = GetLastError ();
6502 ERR ("HeapFree failed with code %i\n", ret);
6503 return ret;
6506 return ERROR_SUCCESS;
6509 /******************************************************************************
6510 * AbortPrinter (WINSPOOL.@)
6512 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6514 FIXME("(%p), stub!\n", hPrinter);
6515 return TRUE;
6518 /******************************************************************************
6519 * AddPortA (WINSPOOL.@)
6521 * See AddPortW.
6524 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6526 LPWSTR nameW = NULL;
6527 LPWSTR monitorW = NULL;
6528 DWORD len;
6529 BOOL res;
6531 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6533 if (pName) {
6534 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6535 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6536 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6539 if (pMonitorName) {
6540 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6541 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6542 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6544 res = AddPortW(nameW, hWnd, monitorW);
6545 HeapFree(GetProcessHeap(), 0, nameW);
6546 HeapFree(GetProcessHeap(), 0, monitorW);
6547 return res;
6550 /******************************************************************************
6551 * AddPortW (WINSPOOL.@)
6553 * Add a Port for a specific Monitor
6555 * PARAMS
6556 * pName [I] Servername or NULL (local Computer)
6557 * hWnd [I] Handle to parent Window for the Dialog-Box
6558 * pMonitorName [I] Name of the Monitor that manage the Port
6560 * RETURNS
6561 * Success: TRUE
6562 * Failure: FALSE
6565 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6567 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6569 if ((backend == NULL) && !load_backend()) return FALSE;
6571 if (!pMonitorName) {
6572 SetLastError(RPC_X_NULL_REF_POINTER);
6573 return FALSE;
6576 return backend->fpAddPort(pName, hWnd, pMonitorName);
6579 /******************************************************************************
6580 * AddPortExA (WINSPOOL.@)
6582 * See AddPortExW.
6585 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6587 PORT_INFO_2W pi2W;
6588 PORT_INFO_2A * pi2A;
6589 LPWSTR nameW = NULL;
6590 LPWSTR monitorW = NULL;
6591 DWORD len;
6592 BOOL res;
6594 pi2A = (PORT_INFO_2A *) pBuffer;
6596 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6597 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6599 if ((level < 1) || (level > 2)) {
6600 SetLastError(ERROR_INVALID_LEVEL);
6601 return FALSE;
6604 if (!pi2A) {
6605 SetLastError(ERROR_INVALID_PARAMETER);
6606 return FALSE;
6609 if (pName) {
6610 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6611 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6612 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6615 if (pMonitorName) {
6616 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6617 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6618 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6621 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6623 if (pi2A->pPortName) {
6624 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6625 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6626 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6629 if (level > 1) {
6630 if (pi2A->pMonitorName) {
6631 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6632 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6633 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6636 if (pi2A->pDescription) {
6637 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6638 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6639 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6641 pi2W.fPortType = pi2A->fPortType;
6642 pi2W.Reserved = pi2A->Reserved;
6645 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6647 HeapFree(GetProcessHeap(), 0, nameW);
6648 HeapFree(GetProcessHeap(), 0, monitorW);
6649 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6650 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6651 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6652 return res;
6656 /******************************************************************************
6657 * AddPortExW (WINSPOOL.@)
6659 * Add a Port for a specific Monitor, without presenting a user interface
6661 * PARAMS
6662 * pName [I] Servername or NULL (local Computer)
6663 * level [I] Structure-Level (1 or 2) for pBuffer
6664 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6665 * pMonitorName [I] Name of the Monitor that manage the Port
6667 * RETURNS
6668 * Success: TRUE
6669 * Failure: FALSE
6672 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6674 PORT_INFO_2W * pi2;
6676 pi2 = (PORT_INFO_2W *) pBuffer;
6678 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6679 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6680 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6681 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6683 if ((backend == NULL) && !load_backend()) return FALSE;
6685 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6686 SetLastError(ERROR_INVALID_PARAMETER);
6687 return FALSE;
6690 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6693 /******************************************************************************
6694 * AddPrinterConnectionA (WINSPOOL.@)
6696 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6698 FIXME("%s\n", debugstr_a(pName));
6699 return FALSE;
6702 /******************************************************************************
6703 * AddPrinterConnectionW (WINSPOOL.@)
6705 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6707 FIXME("%s\n", debugstr_w(pName));
6708 return FALSE;
6711 /******************************************************************************
6712 * AddPrinterDriverExW (WINSPOOL.@)
6714 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6716 * PARAMS
6717 * pName [I] Servername or NULL (local Computer)
6718 * level [I] Level for the supplied DRIVER_INFO_*W struct
6719 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6720 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6722 * RESULTS
6723 * Success: TRUE
6724 * Failure: FALSE
6727 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6729 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6731 if ((backend == NULL) && !load_backend()) return FALSE;
6733 if (level < 2 || level == 5 || level == 7 || level > 8) {
6734 SetLastError(ERROR_INVALID_LEVEL);
6735 return FALSE;
6738 if (!pDriverInfo) {
6739 SetLastError(ERROR_INVALID_PARAMETER);
6740 return FALSE;
6743 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6746 /******************************************************************************
6747 * AddPrinterDriverExA (WINSPOOL.@)
6749 * See AddPrinterDriverExW.
6752 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6754 DRIVER_INFO_8A *diA;
6755 DRIVER_INFO_8W diW;
6756 LPWSTR nameW = NULL;
6757 DWORD lenA;
6758 DWORD len;
6759 DWORD res = FALSE;
6761 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6763 diA = (DRIVER_INFO_8A *) pDriverInfo;
6764 ZeroMemory(&diW, sizeof(diW));
6766 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6767 SetLastError(ERROR_INVALID_LEVEL);
6768 return FALSE;
6771 if (diA == NULL) {
6772 SetLastError(ERROR_INVALID_PARAMETER);
6773 return FALSE;
6776 /* convert servername to unicode */
6777 if (pName) {
6778 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6779 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6780 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6783 /* common fields */
6784 diW.cVersion = diA->cVersion;
6786 if (diA->pName) {
6787 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6788 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6789 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6792 if (diA->pEnvironment) {
6793 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6794 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6795 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6798 if (diA->pDriverPath) {
6799 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6800 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6801 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6804 if (diA->pDataFile) {
6805 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6806 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6807 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6810 if (diA->pConfigFile) {
6811 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6812 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6813 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6816 if ((Level > 2) && diA->pDependentFiles) {
6817 lenA = multi_sz_lenA(diA->pDependentFiles);
6818 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6819 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6820 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6823 if ((Level > 2) && diA->pMonitorName) {
6824 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6825 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6826 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6829 if ((Level > 3) && diA->pDefaultDataType) {
6830 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6831 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6832 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6835 if ((Level > 3) && diA->pszzPreviousNames) {
6836 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6837 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6838 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6839 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6842 if ((Level > 5) && diA->pszMfgName) {
6843 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6844 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6845 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6848 if ((Level > 5) && diA->pszOEMUrl) {
6849 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6850 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6851 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6854 if ((Level > 5) && diA->pszHardwareID) {
6855 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6856 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6857 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6860 if ((Level > 5) && diA->pszProvider) {
6861 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6862 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6863 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6866 if (Level > 7) {
6867 FIXME("level %u is incomplete\n", Level);
6870 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6871 TRACE("got %u with %u\n", res, GetLastError());
6872 HeapFree(GetProcessHeap(), 0, nameW);
6873 HeapFree(GetProcessHeap(), 0, diW.pName);
6874 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6875 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6876 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6877 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6878 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6879 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6880 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6881 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6882 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6883 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6884 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6885 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6887 TRACE("=> %u with %u\n", res, GetLastError());
6888 return res;
6891 /******************************************************************************
6892 * ConfigurePortA (WINSPOOL.@)
6894 * See ConfigurePortW.
6897 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6899 LPWSTR nameW = NULL;
6900 LPWSTR portW = NULL;
6901 INT len;
6902 DWORD res;
6904 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6906 /* convert servername to unicode */
6907 if (pName) {
6908 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6909 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6910 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6913 /* convert portname to unicode */
6914 if (pPortName) {
6915 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6916 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6917 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6920 res = ConfigurePortW(nameW, hWnd, portW);
6921 HeapFree(GetProcessHeap(), 0, nameW);
6922 HeapFree(GetProcessHeap(), 0, portW);
6923 return res;
6926 /******************************************************************************
6927 * ConfigurePortW (WINSPOOL.@)
6929 * Display the Configuration-Dialog for a specific Port
6931 * PARAMS
6932 * pName [I] Servername or NULL (local Computer)
6933 * hWnd [I] Handle to parent Window for the Dialog-Box
6934 * pPortName [I] Name of the Port, that should be configured
6936 * RETURNS
6937 * Success: TRUE
6938 * Failure: FALSE
6941 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6944 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6946 if ((backend == NULL) && !load_backend()) return FALSE;
6948 if (!pPortName) {
6949 SetLastError(RPC_X_NULL_REF_POINTER);
6950 return FALSE;
6953 return backend->fpConfigurePort(pName, hWnd, pPortName);
6956 /******************************************************************************
6957 * ConnectToPrinterDlg (WINSPOOL.@)
6959 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6961 FIXME("%p %x\n", hWnd, Flags);
6962 return NULL;
6965 /******************************************************************************
6966 * DeletePrinterConnectionA (WINSPOOL.@)
6968 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6970 FIXME("%s\n", debugstr_a(pName));
6971 return TRUE;
6974 /******************************************************************************
6975 * DeletePrinterConnectionW (WINSPOOL.@)
6977 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6979 FIXME("%s\n", debugstr_w(pName));
6980 return TRUE;
6983 /******************************************************************************
6984 * DeletePrinterDriverExW (WINSPOOL.@)
6986 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6987 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6989 HKEY hkey_drivers;
6990 BOOL ret = FALSE;
6992 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6993 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6995 if(pName && pName[0])
6997 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6998 SetLastError(ERROR_INVALID_PARAMETER);
6999 return FALSE;
7002 if(dwDeleteFlag)
7004 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7005 SetLastError(ERROR_INVALID_PARAMETER);
7006 return FALSE;
7009 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
7011 if(!hkey_drivers)
7013 ERR("Can't open drivers key\n");
7014 return FALSE;
7017 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7018 ret = TRUE;
7020 RegCloseKey(hkey_drivers);
7022 return ret;
7025 /******************************************************************************
7026 * DeletePrinterDriverExA (WINSPOOL.@)
7028 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7029 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7031 UNICODE_STRING NameW, EnvW, DriverW;
7032 BOOL ret;
7034 asciitounicode(&NameW, pName);
7035 asciitounicode(&EnvW, pEnvironment);
7036 asciitounicode(&DriverW, pDriverName);
7038 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7040 RtlFreeUnicodeString(&DriverW);
7041 RtlFreeUnicodeString(&EnvW);
7042 RtlFreeUnicodeString(&NameW);
7044 return ret;
7047 /******************************************************************************
7048 * DeletePrinterDataExW (WINSPOOL.@)
7050 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7051 LPCWSTR pValueName)
7053 FIXME("%p %s %s\n", hPrinter,
7054 debugstr_w(pKeyName), debugstr_w(pValueName));
7055 return ERROR_INVALID_PARAMETER;
7058 /******************************************************************************
7059 * DeletePrinterDataExA (WINSPOOL.@)
7061 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7062 LPCSTR pValueName)
7064 FIXME("%p %s %s\n", hPrinter,
7065 debugstr_a(pKeyName), debugstr_a(pValueName));
7066 return ERROR_INVALID_PARAMETER;
7069 /******************************************************************************
7070 * DeletePrintProcessorA (WINSPOOL.@)
7072 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7074 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7075 debugstr_a(pPrintProcessorName));
7076 return TRUE;
7079 /******************************************************************************
7080 * DeletePrintProcessorW (WINSPOOL.@)
7082 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7084 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7085 debugstr_w(pPrintProcessorName));
7086 return TRUE;
7089 /******************************************************************************
7090 * DeletePrintProvidorA (WINSPOOL.@)
7092 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7094 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7095 debugstr_a(pPrintProviderName));
7096 return TRUE;
7099 /******************************************************************************
7100 * DeletePrintProvidorW (WINSPOOL.@)
7102 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7104 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7105 debugstr_w(pPrintProviderName));
7106 return TRUE;
7109 /******************************************************************************
7110 * EnumFormsA (WINSPOOL.@)
7112 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7113 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7115 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7116 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7117 return FALSE;
7120 /******************************************************************************
7121 * EnumFormsW (WINSPOOL.@)
7123 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7124 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7126 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7127 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7128 return FALSE;
7131 /*****************************************************************************
7132 * EnumMonitorsA [WINSPOOL.@]
7134 * See EnumMonitorsW.
7137 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7138 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7140 BOOL res;
7141 LPBYTE bufferW = NULL;
7142 LPWSTR nameW = NULL;
7143 DWORD needed = 0;
7144 DWORD numentries = 0;
7145 INT len;
7147 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7148 cbBuf, pcbNeeded, pcReturned);
7150 /* convert servername to unicode */
7151 if (pName) {
7152 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7153 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7154 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7156 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7157 needed = cbBuf * sizeof(WCHAR);
7158 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7159 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7161 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7162 if (pcbNeeded) needed = *pcbNeeded;
7163 /* HeapReAlloc return NULL, when bufferW was NULL */
7164 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7165 HeapAlloc(GetProcessHeap(), 0, needed);
7167 /* Try again with the large Buffer */
7168 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7170 numentries = pcReturned ? *pcReturned : 0;
7171 needed = 0;
7173 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7174 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7176 if (res) {
7177 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7178 DWORD entrysize = 0;
7179 DWORD index;
7180 LPSTR ptr;
7181 LPMONITOR_INFO_2W mi2w;
7182 LPMONITOR_INFO_2A mi2a;
7184 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7185 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7187 /* First pass: calculate the size for all Entries */
7188 mi2w = (LPMONITOR_INFO_2W) bufferW;
7189 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7190 index = 0;
7191 while (index < numentries) {
7192 index++;
7193 needed += entrysize; /* MONITOR_INFO_?A */
7194 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7196 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7197 NULL, 0, NULL, NULL);
7198 if (Level > 1) {
7199 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7200 NULL, 0, NULL, NULL);
7201 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7202 NULL, 0, NULL, NULL);
7204 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7205 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7206 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7209 /* check for errors and quit on failure */
7210 if (cbBuf < needed) {
7211 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7212 res = FALSE;
7213 goto emA_cleanup;
7215 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7216 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7217 cbBuf -= len ; /* free Bytes in the user-Buffer */
7218 mi2w = (LPMONITOR_INFO_2W) bufferW;
7219 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7220 index = 0;
7221 /* Second Pass: Fill the User Buffer (if we have one) */
7222 while ((index < numentries) && pMonitors) {
7223 index++;
7224 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7225 mi2a->pName = ptr;
7226 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7227 ptr, cbBuf , NULL, NULL);
7228 ptr += len;
7229 cbBuf -= len;
7230 if (Level > 1) {
7231 mi2a->pEnvironment = ptr;
7232 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7233 ptr, cbBuf, NULL, NULL);
7234 ptr += len;
7235 cbBuf -= len;
7237 mi2a->pDLLName = ptr;
7238 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7239 ptr, cbBuf, NULL, NULL);
7240 ptr += len;
7241 cbBuf -= len;
7243 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7244 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7245 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7248 emA_cleanup:
7249 if (pcbNeeded) *pcbNeeded = needed;
7250 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7252 HeapFree(GetProcessHeap(), 0, nameW);
7253 HeapFree(GetProcessHeap(), 0, bufferW);
7255 TRACE("returning %d with %d (%d byte for %d entries)\n",
7256 (res), GetLastError(), needed, numentries);
7258 return (res);
7262 /*****************************************************************************
7263 * EnumMonitorsW [WINSPOOL.@]
7265 * Enumerate available Port-Monitors
7267 * PARAMS
7268 * pName [I] Servername or NULL (local Computer)
7269 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7270 * pMonitors [O] PTR to Buffer that receives the Result
7271 * cbBuf [I] Size of Buffer at pMonitors
7272 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7273 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7275 * RETURNS
7276 * Success: TRUE
7277 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7280 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7281 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7284 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7285 cbBuf, pcbNeeded, pcReturned);
7287 if ((backend == NULL) && !load_backend()) return FALSE;
7289 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
7290 SetLastError(RPC_X_NULL_REF_POINTER);
7291 return FALSE;
7294 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
7297 /******************************************************************************
7298 * SpoolerInit (WINSPOOL.@)
7300 * Initialize the Spooler
7302 * RETURNS
7303 * Success: TRUE
7304 * Failure: FALSE
7306 * NOTES
7307 * The function fails on windows, when the spooler service is not running
7310 BOOL WINAPI SpoolerInit(void)
7313 if ((backend == NULL) && !load_backend()) return FALSE;
7314 return TRUE;
7317 /******************************************************************************
7318 * XcvDataW (WINSPOOL.@)
7320 * Execute commands in the Printmonitor DLL
7322 * PARAMS
7323 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7324 * pszDataName [i] Name of the command to execute
7325 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7326 * cbInputData [i] Size in Bytes of Buffer at pInputData
7327 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7328 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7329 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7330 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7332 * RETURNS
7333 * Success: TRUE
7334 * Failure: FALSE
7336 * NOTES
7337 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7338 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7340 * Minimal List of commands, that a Printmonitor DLL should support:
7342 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7343 *| "AddPort" : Add a Port
7344 *| "DeletePort": Delete a Port
7346 * Many Printmonitors support additional commands. Examples for localspl.dll:
7347 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7348 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7351 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7352 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7353 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7355 opened_printer_t *printer;
7357 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7358 pInputData, cbInputData, pOutputData,
7359 cbOutputData, pcbOutputNeeded, pdwStatus);
7361 if ((backend == NULL) && !load_backend()) return FALSE;
7363 printer = get_opened_printer(hXcv);
7364 if (!printer || (!printer->backend_printer)) {
7365 SetLastError(ERROR_INVALID_HANDLE);
7366 return FALSE;
7369 if (!pcbOutputNeeded) {
7370 SetLastError(ERROR_INVALID_PARAMETER);
7371 return FALSE;
7374 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7375 SetLastError(RPC_X_NULL_REF_POINTER);
7376 return FALSE;
7379 *pcbOutputNeeded = 0;
7381 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7382 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7386 /*****************************************************************************
7387 * EnumPrinterDataA [WINSPOOL.@]
7390 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7391 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7392 DWORD cbData, LPDWORD pcbData )
7394 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7395 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7396 return ERROR_NO_MORE_ITEMS;
7399 /*****************************************************************************
7400 * EnumPrinterDataW [WINSPOOL.@]
7403 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7404 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7405 DWORD cbData, LPDWORD pcbData )
7407 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7408 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7409 return ERROR_NO_MORE_ITEMS;
7412 /*****************************************************************************
7413 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7416 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7417 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7418 LPDWORD pcbNeeded, LPDWORD pcReturned)
7420 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7421 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7422 pcbNeeded, pcReturned);
7423 return FALSE;
7426 /*****************************************************************************
7427 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7430 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7431 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7432 LPDWORD pcbNeeded, LPDWORD pcReturned)
7434 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7435 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7436 pcbNeeded, pcReturned);
7437 return FALSE;
7440 /*****************************************************************************
7441 * EnumPrintProcessorsA [WINSPOOL.@]
7443 * See EnumPrintProcessorsW.
7446 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7447 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7449 BOOL res;
7450 LPBYTE bufferW = NULL;
7451 LPWSTR nameW = NULL;
7452 LPWSTR envW = NULL;
7453 DWORD needed = 0;
7454 DWORD numentries = 0;
7455 INT len;
7457 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7458 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7460 /* convert names to unicode */
7461 if (pName) {
7462 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7463 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7464 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7466 if (pEnvironment) {
7467 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7468 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7469 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7472 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7473 needed = cbBuf * sizeof(WCHAR);
7474 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7475 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7477 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7478 if (pcbNeeded) needed = *pcbNeeded;
7479 /* HeapReAlloc return NULL, when bufferW was NULL */
7480 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7481 HeapAlloc(GetProcessHeap(), 0, needed);
7483 /* Try again with the large Buffer */
7484 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7486 numentries = pcReturned ? *pcReturned : 0;
7487 needed = 0;
7489 if (res) {
7490 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7491 DWORD index;
7492 LPSTR ptr;
7493 PPRINTPROCESSOR_INFO_1W ppiw;
7494 PPRINTPROCESSOR_INFO_1A ppia;
7496 /* First pass: calculate the size for all Entries */
7497 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7498 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7499 index = 0;
7500 while (index < numentries) {
7501 index++;
7502 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7503 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7505 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7506 NULL, 0, NULL, NULL);
7508 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7509 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7512 /* check for errors and quit on failure */
7513 if (cbBuf < needed) {
7514 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7515 res = FALSE;
7516 goto epp_cleanup;
7519 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7520 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7521 cbBuf -= len ; /* free Bytes in the user-Buffer */
7522 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7523 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7524 index = 0;
7525 /* Second Pass: Fill the User Buffer (if we have one) */
7526 while ((index < numentries) && pPPInfo) {
7527 index++;
7528 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7529 ppia->pName = ptr;
7530 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7531 ptr, cbBuf , NULL, NULL);
7532 ptr += len;
7533 cbBuf -= len;
7535 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7536 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7540 epp_cleanup:
7541 if (pcbNeeded) *pcbNeeded = needed;
7542 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7544 HeapFree(GetProcessHeap(), 0, nameW);
7545 HeapFree(GetProcessHeap(), 0, envW);
7546 HeapFree(GetProcessHeap(), 0, bufferW);
7548 TRACE("returning %d with %d (%d byte for %d entries)\n",
7549 (res), GetLastError(), needed, numentries);
7551 return (res);
7554 /*****************************************************************************
7555 * EnumPrintProcessorsW [WINSPOOL.@]
7557 * Enumerate available Print Processors
7559 * PARAMS
7560 * pName [I] Servername or NULL (local Computer)
7561 * pEnvironment [I] Printing-Environment or NULL (Default)
7562 * Level [I] Structure-Level (Only 1 is allowed)
7563 * pPPInfo [O] PTR to Buffer that receives the Result
7564 * cbBuf [I] Size of Buffer at pPPInfo
7565 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7566 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7568 * RETURNS
7569 * Success: TRUE
7570 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7573 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7574 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7577 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7578 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7580 if ((backend == NULL) && !load_backend()) return FALSE;
7582 if (!pcbNeeded || !pcReturned) {
7583 SetLastError(RPC_X_NULL_REF_POINTER);
7584 return FALSE;
7587 if (!pPPInfo && (cbBuf > 0)) {
7588 SetLastError(ERROR_INVALID_USER_BUFFER);
7589 return FALSE;
7592 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7593 cbBuf, pcbNeeded, pcReturned);
7596 /*****************************************************************************
7597 * ExtDeviceMode [WINSPOOL.@]
7600 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7601 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7602 DWORD fMode)
7604 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7605 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7606 debugstr_a(pProfile), fMode);
7607 return -1;
7610 /*****************************************************************************
7611 * FindClosePrinterChangeNotification [WINSPOOL.@]
7614 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7616 FIXME("Stub: %p\n", hChange);
7617 return TRUE;
7620 /*****************************************************************************
7621 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7624 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7625 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7627 FIXME("Stub: %p %x %x %p\n",
7628 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7629 return INVALID_HANDLE_VALUE;
7632 /*****************************************************************************
7633 * FindNextPrinterChangeNotification [WINSPOOL.@]
7636 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7637 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7639 FIXME("Stub: %p %p %p %p\n",
7640 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7641 return FALSE;
7644 /*****************************************************************************
7645 * FreePrinterNotifyInfo [WINSPOOL.@]
7648 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7650 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7651 return TRUE;
7654 /*****************************************************************************
7655 * string_to_buf
7657 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7658 * ansi depending on the unicode parameter.
7660 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7662 if(!str)
7664 *size = 0;
7665 return TRUE;
7668 if(unicode)
7670 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7671 if(*size <= cb)
7673 memcpy(ptr, str, *size);
7674 return TRUE;
7676 return FALSE;
7678 else
7680 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7681 if(*size <= cb)
7683 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7684 return TRUE;
7686 return FALSE;
7690 /*****************************************************************************
7691 * get_job_info_1
7693 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7694 LPDWORD pcbNeeded, BOOL unicode)
7696 DWORD size, left = cbBuf;
7697 BOOL space = (cbBuf > 0);
7698 LPBYTE ptr = buf;
7700 *pcbNeeded = 0;
7702 if(space)
7704 ji1->JobId = job->job_id;
7707 string_to_buf(job->document_title, ptr, left, &size, unicode);
7708 if(space && size <= left)
7710 ji1->pDocument = (LPWSTR)ptr;
7711 ptr += size;
7712 left -= size;
7714 else
7715 space = FALSE;
7716 *pcbNeeded += size;
7718 if (job->printer_name)
7720 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7721 if(space && size <= left)
7723 ji1->pPrinterName = (LPWSTR)ptr;
7724 ptr += size;
7725 left -= size;
7727 else
7728 space = FALSE;
7729 *pcbNeeded += size;
7732 return space;
7735 /*****************************************************************************
7736 * get_job_info_2
7738 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7739 LPDWORD pcbNeeded, BOOL unicode)
7741 DWORD size, left = cbBuf;
7742 DWORD shift;
7743 BOOL space = (cbBuf > 0);
7744 LPBYTE ptr = buf;
7745 LPDEVMODEA dmA = NULL;
7746 LPDEVMODEW devmode;
7748 *pcbNeeded = 0;
7750 if(space)
7752 ji2->JobId = job->job_id;
7755 string_to_buf(job->document_title, ptr, left, &size, unicode);
7756 if(space && size <= left)
7758 ji2->pDocument = (LPWSTR)ptr;
7759 ptr += size;
7760 left -= size;
7762 else
7763 space = FALSE;
7764 *pcbNeeded += size;
7766 if (job->printer_name)
7768 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7769 if(space && size <= left)
7771 ji2->pPrinterName = (LPWSTR)ptr;
7772 ptr += size;
7773 left -= size;
7775 else
7776 space = FALSE;
7777 *pcbNeeded += size;
7780 if (job->devmode)
7782 if (!unicode)
7784 dmA = DEVMODEdupWtoA(job->devmode);
7785 devmode = (LPDEVMODEW) dmA;
7786 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7788 else
7790 devmode = job->devmode;
7791 size = devmode->dmSize + devmode->dmDriverExtra;
7794 if (!devmode)
7795 FIXME("Can't convert DEVMODE W to A\n");
7796 else
7798 /* align DEVMODE to a DWORD boundary */
7799 shift = (4 - (*pcbNeeded & 3)) & 3;
7800 size += shift;
7802 if (size <= left)
7804 ptr += shift;
7805 memcpy(ptr, devmode, size-shift);
7806 ji2->pDevMode = (LPDEVMODEW)ptr;
7807 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7808 ptr += size-shift;
7809 left -= size;
7811 else
7812 space = FALSE;
7813 *pcbNeeded +=size;
7817 return space;
7820 /*****************************************************************************
7821 * get_job_info
7823 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7824 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7826 BOOL ret = FALSE;
7827 DWORD needed = 0, size;
7828 job_t *job;
7829 LPBYTE ptr = pJob;
7831 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7833 EnterCriticalSection(&printer_handles_cs);
7834 job = get_job(hPrinter, JobId);
7835 if(!job)
7836 goto end;
7838 switch(Level)
7840 case 1:
7841 size = sizeof(JOB_INFO_1W);
7842 if(cbBuf >= size)
7844 cbBuf -= size;
7845 ptr += size;
7846 memset(pJob, 0, size);
7848 else
7849 cbBuf = 0;
7850 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7851 needed += size;
7852 break;
7854 case 2:
7855 size = sizeof(JOB_INFO_2W);
7856 if(cbBuf >= size)
7858 cbBuf -= size;
7859 ptr += size;
7860 memset(pJob, 0, size);
7862 else
7863 cbBuf = 0;
7864 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7865 needed += size;
7866 break;
7868 case 3:
7869 size = sizeof(JOB_INFO_3);
7870 if(cbBuf >= size)
7872 cbBuf -= size;
7873 memset(pJob, 0, size);
7874 ret = TRUE;
7876 else
7877 cbBuf = 0;
7878 needed = size;
7879 break;
7881 default:
7882 SetLastError(ERROR_INVALID_LEVEL);
7883 goto end;
7885 if(pcbNeeded)
7886 *pcbNeeded = needed;
7887 end:
7888 LeaveCriticalSection(&printer_handles_cs);
7889 return ret;
7892 /*****************************************************************************
7893 * GetJobA [WINSPOOL.@]
7896 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7897 DWORD cbBuf, LPDWORD pcbNeeded)
7899 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7902 /*****************************************************************************
7903 * GetJobW [WINSPOOL.@]
7906 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7907 DWORD cbBuf, LPDWORD pcbNeeded)
7909 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7912 /*****************************************************************************
7913 * schedule_pipe
7915 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7917 #ifdef HAVE_FORK
7918 char *unixname, *cmdA;
7919 DWORD len;
7920 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7921 BOOL ret = FALSE;
7922 char buf[1024];
7923 pid_t pid, wret;
7924 int status;
7926 if(!(unixname = wine_get_unix_file_name(filename)))
7927 return FALSE;
7929 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7930 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7931 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7933 TRACE("printing with: %s\n", cmdA);
7935 if((file_fd = open(unixname, O_RDONLY)) == -1)
7936 goto end;
7938 if (pipe(fds))
7940 ERR("pipe() failed!\n");
7941 goto end;
7944 if ((pid = fork()) == 0)
7946 close(0);
7947 dup2(fds[0], 0);
7948 close(fds[1]);
7950 /* reset signals that we previously set to SIG_IGN */
7951 signal(SIGPIPE, SIG_DFL);
7953 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7954 _exit(1);
7956 else if (pid == -1)
7958 ERR("fork() failed!\n");
7959 goto end;
7962 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7963 write(fds[1], buf, no_read);
7965 close(fds[1]);
7966 fds[1] = -1;
7968 /* reap child */
7969 do {
7970 wret = waitpid(pid, &status, 0);
7971 } while (wret < 0 && errno == EINTR);
7972 if (wret < 0)
7974 ERR("waitpid() failed!\n");
7975 goto end;
7977 if (!WIFEXITED(status) || WEXITSTATUS(status))
7979 ERR("child process failed! %d\n", status);
7980 goto end;
7983 ret = TRUE;
7985 end:
7986 if(file_fd != -1) close(file_fd);
7987 if(fds[0] != -1) close(fds[0]);
7988 if(fds[1] != -1) close(fds[1]);
7990 HeapFree(GetProcessHeap(), 0, cmdA);
7991 HeapFree(GetProcessHeap(), 0, unixname);
7992 return ret;
7993 #else
7994 return FALSE;
7995 #endif
7998 /*****************************************************************************
7999 * schedule_lpr
8001 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
8003 WCHAR *cmd;
8004 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8005 BOOL r;
8007 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
8008 sprintfW(cmd, fmtW, printer_name);
8010 r = schedule_pipe(cmd, filename);
8012 HeapFree(GetProcessHeap(), 0, cmd);
8013 return r;
8016 #ifdef SONAME_LIBCUPS
8017 /*****************************************************************************
8018 * get_cups_jobs_ticket_options
8020 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8021 * The CUPS scheduler only looks for these in Print-File requests, and since
8022 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8023 * parsed.
8025 static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
8027 FILE *fp = fopen( file, "r" );
8028 char buf[257]; /* DSC max of 256 + '\0' */
8029 const char *ps_adobe = "%!PS-Adobe-";
8030 const char *cups_job = "%cupsJobTicket:";
8032 if (!fp) return num_options;
8033 if (!fgets( buf, sizeof(buf), fp )) goto end;
8034 if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
8035 while (fgets( buf, sizeof(buf), fp ))
8037 if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
8038 num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
8041 end:
8042 fclose( fp );
8043 return num_options;
8045 #endif
8047 /*****************************************************************************
8048 * schedule_cups
8050 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
8052 #ifdef SONAME_LIBCUPS
8053 if(pcupsPrintFile)
8055 char *unixname, *queue, *unix_doc_title;
8056 DWORD len;
8057 BOOL ret;
8058 int num_options = 0, i;
8059 cups_option_t *options = NULL;
8061 if(!(unixname = wine_get_unix_file_name(filename)))
8062 return FALSE;
8064 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
8065 queue = HeapAlloc(GetProcessHeap(), 0, len);
8066 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
8068 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
8069 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
8070 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
8072 num_options = get_cups_job_ticket_options( unixname, num_options, &options );
8074 TRACE( "printing via cups with options:\n" );
8075 for (i = 0; i < num_options; i++)
8076 TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
8078 ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
8080 pcupsFreeOptions( num_options, options );
8082 HeapFree(GetProcessHeap(), 0, unix_doc_title);
8083 HeapFree(GetProcessHeap(), 0, queue);
8084 HeapFree(GetProcessHeap(), 0, unixname);
8085 return ret;
8087 else
8088 #endif
8090 return schedule_lpr(printer_name, filename);
8094 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
8096 LPWSTR filename;
8098 switch(msg)
8100 case WM_INITDIALOG:
8101 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
8102 return TRUE;
8104 case WM_COMMAND:
8105 if(HIWORD(wparam) == BN_CLICKED)
8107 if(LOWORD(wparam) == IDOK)
8109 HANDLE hf;
8110 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
8111 LPWSTR *output;
8113 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
8114 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
8116 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
8118 WCHAR caption[200], message[200];
8119 int mb_ret;
8121 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8122 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
8123 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
8124 if(mb_ret == IDCANCEL)
8126 HeapFree(GetProcessHeap(), 0, filename);
8127 return TRUE;
8130 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8131 if(hf == INVALID_HANDLE_VALUE)
8133 WCHAR caption[200], message[200];
8135 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
8136 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
8137 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
8138 HeapFree(GetProcessHeap(), 0, filename);
8139 return TRUE;
8141 CloseHandle(hf);
8142 DeleteFileW(filename);
8143 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
8144 *output = filename;
8145 EndDialog(hwnd, IDOK);
8146 return TRUE;
8148 if(LOWORD(wparam) == IDCANCEL)
8150 EndDialog(hwnd, IDCANCEL);
8151 return TRUE;
8154 return FALSE;
8156 return FALSE;
8159 /*****************************************************************************
8160 * get_filename
8162 static BOOL get_filename(LPWSTR *filename)
8164 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
8165 file_dlg_proc, (LPARAM)filename) == IDOK;
8168 /*****************************************************************************
8169 * schedule_file
8171 static BOOL schedule_file(LPCWSTR filename)
8173 LPWSTR output = NULL;
8175 if(get_filename(&output))
8177 BOOL r;
8178 TRACE("copy to %s\n", debugstr_w(output));
8179 r = CopyFileW(filename, output, FALSE);
8180 HeapFree(GetProcessHeap(), 0, output);
8181 return r;
8183 return FALSE;
8186 /*****************************************************************************
8187 * schedule_unixfile
8189 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
8191 int in_fd, out_fd, no_read;
8192 char buf[1024];
8193 BOOL ret = FALSE;
8194 char *unixname, *outputA;
8195 DWORD len;
8197 if(!(unixname = wine_get_unix_file_name(filename)))
8198 return FALSE;
8200 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
8201 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8202 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
8204 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8205 in_fd = open(unixname, O_RDONLY);
8206 if(out_fd == -1 || in_fd == -1)
8207 goto end;
8209 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8210 write(out_fd, buf, no_read);
8212 ret = TRUE;
8213 end:
8214 if(in_fd != -1) close(in_fd);
8215 if(out_fd != -1) close(out_fd);
8216 HeapFree(GetProcessHeap(), 0, outputA);
8217 HeapFree(GetProcessHeap(), 0, unixname);
8218 return ret;
8221 /*****************************************************************************
8222 * ScheduleJob [WINSPOOL.@]
8225 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8227 opened_printer_t *printer;
8228 BOOL ret = FALSE;
8229 struct list *cursor, *cursor2;
8231 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8232 EnterCriticalSection(&printer_handles_cs);
8233 printer = get_opened_printer(hPrinter);
8234 if(!printer)
8235 goto end;
8237 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8239 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8240 HANDLE hf;
8242 if(job->job_id != dwJobID) continue;
8244 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8245 if(hf != INVALID_HANDLE_VALUE)
8247 PRINTER_INFO_5W *pi5 = NULL;
8248 LPWSTR portname = job->portname;
8249 DWORD needed;
8250 HKEY hkey;
8251 WCHAR output[1024];
8252 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8253 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8255 if (!portname)
8257 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8258 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8259 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8260 portname = pi5->pPortName;
8262 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8263 debugstr_w(portname));
8265 output[0] = 0;
8267 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8268 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8270 DWORD type, count = sizeof(output);
8271 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
8272 RegCloseKey(hkey);
8274 if(output[0] == '|')
8276 ret = schedule_pipe(output + 1, job->filename);
8278 else if(output[0])
8280 ret = schedule_unixfile(output, job->filename);
8282 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
8284 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
8286 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
8288 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
8290 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
8292 ret = schedule_file(job->filename);
8294 else
8296 FIXME("can't schedule to port %s\n", debugstr_w(portname));
8298 HeapFree(GetProcessHeap(), 0, pi5);
8299 CloseHandle(hf);
8300 DeleteFileW(job->filename);
8302 list_remove(cursor);
8303 HeapFree(GetProcessHeap(), 0, job->document_title);
8304 HeapFree(GetProcessHeap(), 0, job->printer_name);
8305 HeapFree(GetProcessHeap(), 0, job->portname);
8306 HeapFree(GetProcessHeap(), 0, job->filename);
8307 HeapFree(GetProcessHeap(), 0, job->devmode);
8308 HeapFree(GetProcessHeap(), 0, job);
8309 break;
8311 end:
8312 LeaveCriticalSection(&printer_handles_cs);
8313 return ret;
8316 /*****************************************************************************
8317 * StartDocDlgA [WINSPOOL.@]
8319 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8321 UNICODE_STRING usBuffer;
8322 DOCINFOW docW;
8323 LPWSTR retW;
8324 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8325 LPSTR ret = NULL;
8327 docW.cbSize = sizeof(docW);
8328 if (doc->lpszDocName)
8330 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8331 if (!(docW.lpszDocName = docnameW)) return NULL;
8333 if (doc->lpszOutput)
8335 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8336 if (!(docW.lpszOutput = outputW)) return NULL;
8338 if (doc->lpszDatatype)
8340 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8341 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8343 docW.fwType = doc->fwType;
8345 retW = StartDocDlgW(hPrinter, &docW);
8347 if(retW)
8349 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8350 ret = HeapAlloc(GetProcessHeap(), 0, len);
8351 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8352 HeapFree(GetProcessHeap(), 0, retW);
8355 HeapFree(GetProcessHeap(), 0, datatypeW);
8356 HeapFree(GetProcessHeap(), 0, outputW);
8357 HeapFree(GetProcessHeap(), 0, docnameW);
8359 return ret;
8362 /*****************************************************************************
8363 * StartDocDlgW [WINSPOOL.@]
8365 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8366 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8367 * port is "FILE:". Also returns the full path if passed a relative path.
8369 * The caller should free the returned string from the process heap.
8371 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8373 LPWSTR ret = NULL;
8374 DWORD len, attr;
8376 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8378 PRINTER_INFO_5W *pi5;
8379 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8380 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8381 return NULL;
8382 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8383 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8384 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8386 HeapFree(GetProcessHeap(), 0, pi5);
8387 return NULL;
8389 HeapFree(GetProcessHeap(), 0, pi5);
8392 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8394 LPWSTR name;
8396 if (get_filename(&name))
8398 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8400 HeapFree(GetProcessHeap(), 0, name);
8401 return NULL;
8403 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8404 GetFullPathNameW(name, len, ret, NULL);
8405 HeapFree(GetProcessHeap(), 0, name);
8407 return ret;
8410 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8411 return NULL;
8413 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8414 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8416 attr = GetFileAttributesW(ret);
8417 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8419 HeapFree(GetProcessHeap(), 0, ret);
8420 ret = NULL;
8422 return ret;