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
28 #include "wine/port.h"
37 #ifdef HAVE_SYS_WAIT_H
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
48 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
49 #define GetCurrentProcess GetCurrentProcess_Mac
50 #define GetCurrentThread GetCurrentThread_Mac
51 #define LoadResource LoadResource_Mac
52 #define AnimatePalette AnimatePalette_Mac
53 #define EqualRgn EqualRgn_Mac
54 #define FillRgn FillRgn_Mac
55 #define FrameRgn FrameRgn_Mac
56 #define GetPixel GetPixel_Mac
57 #define InvertRgn InvertRgn_Mac
58 #define LineTo LineTo_Mac
59 #define OffsetRgn OffsetRgn_Mac
60 #define PaintRgn PaintRgn_Mac
61 #define Polygon Polygon_Mac
62 #define ResizePalette ResizePalette_Mac
63 #define SetRectRgn SetRectRgn_Mac
64 #define EqualRect EqualRect_Mac
65 #define FillRect FillRect_Mac
66 #define FrameRect FrameRect_Mac
67 #define GetCursor GetCursor_Mac
68 #define InvertRect InvertRect_Mac
69 #define OffsetRect OffsetRect_Mac
70 #define PtInRect PtInRect_Mac
71 #define SetCursor SetCursor_Mac
72 #define SetRect SetRect_Mac
73 #define ShowCursor ShowCursor_Mac
74 #define UnionRect UnionRect_Mac
75 #include <ApplicationServices/ApplicationServices.h>
76 #undef GetCurrentProcess
77 #undef GetCurrentThread
105 #define NONAMELESSUNION
106 #define NONAMELESSSTRUCT
107 #include "wine/library.h"
111 #include "winerror.h"
114 #include "winspool.h"
115 #include "winternl.h"
116 #include "wine/windef16.h"
117 #include "wine/unicode.h"
118 #include "wine/debug.h"
119 #include "wine/list.h"
122 #include "ddk/winsplp.h"
125 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
127 /* ############################### */
129 static CRITICAL_SECTION printer_handles_cs
;
130 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
132 0, 0, &printer_handles_cs
,
133 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
134 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
136 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
138 /* ############################### */
153 HANDLE backend_printer
;
164 WCHAR
*document_title
;
174 LPCWSTR versionregpath
;
175 LPCWSTR versionsubdir
;
178 /* ############################### */
180 static opened_printer_t
**printer_handles
;
181 static UINT nb_printer_handles
;
182 static LONG next_job_id
= 1;
184 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
185 WORD fwCapability
, LPSTR lpszOutput
,
187 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
188 LPSTR lpszDevice
, LPSTR lpszPort
,
189 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
192 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
193 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
194 'c','o','n','t','r','o','l','\\',
195 'P','r','i','n','t','\\',
196 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
197 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
199 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
200 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
201 'C','o','n','t','r','o','l','\\',
202 'P','r','i','n','t','\\',
203 'P','r','i','n','t','e','r','s',0};
205 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
207 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
208 'M','i','c','r','o','s','o','f','t','\\',
209 'W','i','n','d','o','w','s',' ','N','T','\\',
210 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
211 'W','i','n','d','o','w','s',0};
213 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
214 'M','i','c','r','o','s','o','f','t','\\',
215 'W','i','n','d','o','w','s',' ','N','T','\\',
216 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
217 'D','e','v','i','c','e','s',0};
219 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
220 'M','i','c','r','o','s','o','f','t','\\',
221 'W','i','n','d','o','w','s',' ','N','T','\\',
222 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
223 'P','o','r','t','s',0};
225 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
226 'M','i','c','r','o','s','o','f','t','\\',
227 'W','i','n','d','o','w','s',' ','N','T','\\',
228 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
229 'P','r','i','n','t','e','r','P','o','r','t','s',0};
231 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
232 static WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
233 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
234 static WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
235 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
236 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
237 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
238 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
239 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
240 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
241 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
243 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
245 static const WCHAR AttributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0};
246 static const WCHAR backslashW
[] = {'\\',0};
247 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
248 'i','o','n',' ','F','i','l','e',0};
249 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
250 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
251 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
252 static const WCHAR Default_PriorityW
[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
253 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
254 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
255 static const WCHAR dnsTimeoutW
[] = {'d','n','s','T','i','m','e','o','u','t',0};
256 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
257 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
258 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
259 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
260 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
261 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
262 static const WCHAR NameW
[] = {'N','a','m','e',0};
263 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
264 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
265 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
266 static const WCHAR PortW
[] = {'P','o','r','t',0};
267 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
268 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
269 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
270 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
271 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
272 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
273 static const WCHAR PriorityW
[] = {'P','r','i','o','r','i','t','y',0};
274 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
275 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
276 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
277 static const WCHAR StartTimeW
[] = {'S','t','a','r','t','T','i','m','e',0};
278 static const WCHAR StatusW
[] = {'S','t','a','t','u','s',0};
279 static const WCHAR txTimeoutW
[] = {'t','x','T','i','m','e','o','u','t',0};
280 static const WCHAR UntilTimeW
[] = {'U','n','t','i','l','T','i','m','e',0};
281 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
282 static WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
283 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
284 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
285 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
286 static WCHAR rawW
[] = {'R','A','W',0};
287 static WCHAR driver_9x
[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
288 static WCHAR driver_nt
[] = {'w','i','n','e','p','s','.','d','r','v',0};
289 static const WCHAR timeout_15_45
[] = {',','1','5',',','4','5',0};
290 static const WCHAR commaW
[] = {',',0};
291 static WCHAR emptyStringW
[] = {0};
293 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
295 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
296 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
297 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
299 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
300 'D','o','c','u','m','e','n','t',0};
302 static const WCHAR PPD_Overrides
[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
303 static const WCHAR DefaultPageSize
[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
305 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
306 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
307 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
308 0, sizeof(DRIVER_INFO_8W
)};
311 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
312 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
313 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
314 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
315 sizeof(PRINTER_INFO_9W
)};
317 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
318 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
319 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
321 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
323 /******************************************************************
324 * validate the user-supplied printing-environment [internal]
327 * env [I] PTR to Environment-String or NULL
331 * Success: PTR to printenv_t
334 * An empty string is handled the same way as NULL.
335 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
339 static const printenv_t
* validate_envW(LPCWSTR env
)
341 const printenv_t
*result
= NULL
;
344 TRACE("testing %s\n", debugstr_w(env
));
347 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
349 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
351 result
= all_printenv
[i
];
356 if (result
== NULL
) {
357 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
358 SetLastError(ERROR_INVALID_ENVIRONMENT
);
360 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
364 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
366 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
372 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
373 if passed a NULL string. This returns NULLs to the result.
375 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
379 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
380 return usBufferPtr
->Buffer
;
382 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
386 static LPWSTR
strdupW(LPCWSTR p
)
392 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
393 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
398 static LPSTR
strdupWtoA( LPCWSTR str
)
403 if (!str
) return NULL
;
404 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
405 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
406 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
410 static DEVMODEW
*dup_devmode( const DEVMODEW
*dm
)
414 if (!dm
) return NULL
;
415 ret
= HeapAlloc( GetProcessHeap(), 0, dm
->dmSize
+ dm
->dmDriverExtra
);
416 if (ret
) memcpy( ret
, dm
, dm
->dmSize
+ dm
->dmDriverExtra
);
420 /***********************************************************
422 * Creates an ansi copy of supplied devmode
424 static DEVMODEA
*DEVMODEdupWtoA( const DEVMODEW
*dmW
)
429 if (!dmW
) return NULL
;
430 size
= dmW
->dmSize
- CCHDEVICENAME
-
431 ((dmW
->dmSize
> FIELD_OFFSET( DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
433 dmA
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
434 if (!dmA
) return NULL
;
436 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmDeviceName
, -1,
437 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
439 if (FIELD_OFFSET( DEVMODEW
, dmFormName
) >= dmW
->dmSize
)
441 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
442 dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
446 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
447 FIELD_OFFSET( DEVMODEW
, dmFormName
) - FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
448 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmFormName
, -1,
449 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
451 memcpy( &dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmLogPixels
) );
455 memcpy( (char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
460 /******************************************************************
461 * verify, that the filename is a local file
464 static inline BOOL
is_local_file(LPWSTR name
)
466 return (name
[0] && (name
[1] == ':') && (name
[2] == '\\'));
469 /* ################################ */
471 static int multi_sz_lenA(const char *str
)
473 const char *ptr
= str
;
477 ptr
+= lstrlenA(ptr
) + 1;
480 return ptr
- str
+ 1;
483 /*****************************************************************************
486 * Return DWORD associated with name from hkey.
488 static DWORD
get_dword_from_reg( HKEY hkey
, const WCHAR
*name
)
490 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
493 ret
= RegQueryValueExW( hkey
, name
, 0, &type
, (LPBYTE
)&value
, &sz
);
495 if (ret
!= ERROR_SUCCESS
)
497 WARN( "Got ret = %d on name %s\n", ret
, debugstr_w(name
) );
500 if (type
!= REG_DWORD
)
502 ERR( "Got type %d\n", type
);
508 static inline DWORD
set_reg_DWORD( HKEY hkey
, const WCHAR
*keyname
, const DWORD value
)
510 return RegSetValueExW( hkey
, keyname
, 0, REG_DWORD
, (const BYTE
*)&value
, sizeof(value
) );
513 /******************************************************************
515 * Get the pointer to the opened printer referred by the handle
517 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
519 UINT_PTR idx
= (UINT_PTR
)hprn
;
520 opened_printer_t
*ret
= NULL
;
522 EnterCriticalSection(&printer_handles_cs
);
524 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
525 ret
= printer_handles
[idx
- 1];
527 LeaveCriticalSection(&printer_handles_cs
);
531 /******************************************************************
532 * get_opened_printer_name
533 * Get the pointer to the opened printer name referred by the handle
535 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
537 opened_printer_t
*printer
= get_opened_printer(hprn
);
538 if(!printer
) return NULL
;
539 return printer
->name
;
542 static DWORD
open_printer_reg_key( const WCHAR
*name
, HKEY
*key
)
548 err
= RegCreateKeyW( HKEY_LOCAL_MACHINE
, PrintersW
, &printers
);
551 err
= RegOpenKeyW( printers
, name
, key
);
552 if (err
) err
= ERROR_INVALID_PRINTER_NAME
;
553 RegCloseKey( printers
);
557 /******************************************************************
558 * WINSPOOL_GetOpenedPrinterRegKey
561 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
563 LPCWSTR name
= get_opened_printer_name(hPrinter
);
565 if(!name
) return ERROR_INVALID_HANDLE
;
566 return open_printer_reg_key( name
, phkey
);
570 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
573 /* If forcing, or no profile string entry for device yet, set the entry
575 * The always change entry if not WINEPS yet is discussable.
578 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
580 !strstr(qbuf
,"WINEPS.DRV")
582 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
585 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
586 WriteProfileStringA("windows","device",buf
);
587 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
588 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
591 HeapFree(GetProcessHeap(),0,buf
);
595 static BOOL
add_printer_driver(const WCHAR
*name
, WCHAR
*ppd
)
599 ZeroMemory(&di3
, sizeof(DRIVER_INFO_3W
));
601 di3
.pName
= (WCHAR
*)name
;
602 di3
.pEnvironment
= envname_x86W
;
603 di3
.pDriverPath
= driver_nt
;
605 di3
.pConfigFile
= driver_nt
;
606 di3
.pDefaultDataType
= rawW
;
608 if (AddPrinterDriverExW( NULL
, 3, (LPBYTE
)&di3
, APD_COPY_NEW_FILES
| APD_COPY_FROM_DIRECTORY
) ||
609 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
612 di3
.pEnvironment
= envname_win40W
;
613 di3
.pDriverPath
= driver_9x
;
614 di3
.pConfigFile
= driver_9x
;
615 if (AddPrinterDriverExW( NULL
, 3, (LPBYTE
)&di3
, APD_COPY_NEW_FILES
| APD_COPY_FROM_DIRECTORY
) ||
616 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
621 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3
.pDriverPath
), debugstr_w(di3
.pEnvironment
));
625 static inline char *expand_env_string( char *str
, DWORD type
)
627 if (type
== REG_EXPAND_SZ
)
630 DWORD needed
= ExpandEnvironmentStringsA( str
, NULL
, 0 );
631 tmp
= HeapAlloc( GetProcessHeap(), 0, needed
);
634 ExpandEnvironmentStringsA( str
, tmp
, needed
);
635 HeapFree( GetProcessHeap(), 0, str
);
642 static char *get_fallback_ppd_name( const char *printer_name
)
644 static const WCHAR ppds_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
645 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
649 const char *data_dir
, *filename
;
651 if (RegOpenKeyW( HKEY_CURRENT_USER
, ppds_key
, &hkey
) == ERROR_SUCCESS
)
653 const char *value_name
= NULL
;
655 if (RegQueryValueExA( hkey
, printer_name
, 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
656 value_name
= printer_name
;
657 else if (RegQueryValueExA( hkey
, "generic", 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
658 value_name
= "generic";
662 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
663 if (!ret
) return NULL
;
664 RegQueryValueExA( hkey
, value_name
, 0, &type
, (BYTE
*)ret
, &needed
);
667 if (ret
) return expand_env_string( ret
, type
);
670 if ((data_dir
= wine_get_data_dir())) filename
= "/generic.ppd";
671 else if ((data_dir
= wine_get_build_dir())) filename
= "/dlls/wineps.drv/generic.ppd";
674 ERR( "Error getting PPD file name for printer '%s'\n", debugstr_a(printer_name
) );
677 ret
= HeapAlloc( GetProcessHeap(), 0, strlen(data_dir
) + strlen(filename
) + 1 );
680 strcpy( ret
, data_dir
);
681 strcat( ret
, filename
);
687 static BOOL
copy_file( const char *src
, const char *dst
)
689 int fds
[2] = {-1, -1}, num
;
693 fds
[0] = open( src
, O_RDONLY
);
694 fds
[1] = open( dst
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666 );
695 if (fds
[0] == -1 || fds
[1] == -1) goto fail
;
697 while ((num
= read( fds
[0], buf
, sizeof(buf
) )) != 0)
699 if (num
== -1) goto fail
;
700 if (write( fds
[1], buf
, num
) != num
) goto fail
;
705 if (fds
[1] != -1) close( fds
[1] );
706 if (fds
[0] != -1) close( fds
[0] );
710 static BOOL
get_fallback_ppd( const char *printer_name
, const WCHAR
*ppd
)
712 char *src
= get_fallback_ppd_name( printer_name
);
713 char *dst
= wine_get_unix_file_name( ppd
);
716 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name
), debugstr_w(ppd
), debugstr_a(src
) );
718 if (!src
|| !dst
) goto fail
;
720 if (symlink( src
, dst
) == -1)
721 if (errno
!= ENOSYS
|| !copy_file( src
, dst
))
726 HeapFree( GetProcessHeap(), 0, dst
);
727 HeapFree( GetProcessHeap(), 0, src
);
731 static WCHAR
*get_ppd_filename( const WCHAR
*dir
, const WCHAR
*file_name
)
733 static const WCHAR dot_ppd
[] = {'.','p','p','d',0};
734 int len
= (strlenW( dir
) + strlenW( file_name
)) * sizeof(WCHAR
) + sizeof(dot_ppd
);
735 WCHAR
*ppd
= HeapAlloc( GetProcessHeap(), 0, len
);
737 if (!ppd
) return NULL
;
739 strcatW( ppd
, file_name
);
740 strcatW( ppd
, dot_ppd
);
745 static WCHAR
*get_ppd_dir( void )
747 static const WCHAR wine_ppds
[] = {'w','i','n','e','_','p','p','d','s','\\',0};
749 WCHAR
*dir
, tmp_path
[MAX_PATH
];
752 len
= GetTempPathW( sizeof(tmp_path
) / sizeof(tmp_path
[0]), tmp_path
);
753 if (!len
) return NULL
;
754 dir
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) + sizeof(wine_ppds
) ) ;
755 if (!dir
) return NULL
;
757 memcpy( dir
, tmp_path
, len
* sizeof(WCHAR
) );
758 memcpy( dir
+ len
, wine_ppds
, sizeof(wine_ppds
) );
759 res
= CreateDirectoryW( dir
, NULL
);
760 if (!res
&& GetLastError() != ERROR_ALREADY_EXISTS
)
762 HeapFree( GetProcessHeap(), 0, dir
);
765 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir
) );
769 static void unlink_ppd( const WCHAR
*ppd
)
771 char *unix_name
= wine_get_unix_file_name( ppd
);
773 HeapFree( GetProcessHeap(), 0, unix_name
);
776 #ifdef SONAME_LIBCUPS
778 static void *cupshandle
;
781 DO_FUNC(cupsFreeDests); \
782 DO_FUNC(cupsFreeOptions); \
783 DO_FUNC(cupsGetDests); \
784 DO_FUNC(cupsGetOption); \
785 DO_FUNC(cupsGetPPD); \
786 DO_FUNC(cupsParseOptions); \
787 DO_FUNC(cupsPrintFile);
788 #define CUPS_OPT_FUNCS \
789 DO_FUNC(cupsGetPPD3);
791 #define DO_FUNC(f) static typeof(f) *p##f
794 static http_status_t (*pcupsGetPPD3
)(http_t
*,const char *, time_t *, char *, size_t);
796 static http_status_t
cupsGetPPD3_wrapper( http_t
*http
, const char *name
,
797 time_t *modtime
, char *buffer
,
802 if (pcupsGetPPD3
) return pcupsGetPPD3( http
, name
, modtime
, buffer
, bufsize
);
804 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
807 ppd
= pcupsGetPPD( name
);
809 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd
) );
811 if (!ppd
) return HTTP_NOT_FOUND
;
813 if (rename( ppd
, buffer
) == -1)
815 BOOL res
= copy_file( ppd
, buffer
);
817 if (!res
) return HTTP_NOT_FOUND
;
822 static BOOL
get_cups_ppd( const char *printer_name
, const WCHAR
*ppd
)
825 http_status_t http_status
;
826 char *unix_name
= wine_get_unix_file_name( ppd
);
828 TRACE( "(%s, %s)\n", debugstr_a(printer_name
), debugstr_w(ppd
) );
830 if (!unix_name
) return FALSE
;
832 http_status
= cupsGetPPD3_wrapper( 0, printer_name
, &modtime
,
833 unix_name
, strlen( unix_name
) + 1 );
834 HeapFree( GetProcessHeap(), 0, unix_name
);
836 if (http_status
== HTTP_OK
) return TRUE
;
838 TRACE( "failed to get ppd for printer %s from cups, calling fallback\n", debugstr_a(printer_name
) );
839 return get_fallback_ppd( printer_name
, ppd
);
842 static WCHAR
*get_cups_option( const char *name
, int num_options
, cups_option_t
*options
)
848 value
= pcupsGetOption( name
, num_options
, options
);
849 if (!value
) return NULL
;
851 len
= MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, NULL
, 0 );
852 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
853 if (ret
) MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, ret
, len
);
858 static BOOL
CUPS_LoadPrinters(void)
861 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
864 WCHAR
*port
, *ppd_dir
= NULL
, *ppd
;
865 HKEY hkeyPrinter
, hkeyPrinters
;
867 WCHAR nameW
[MAX_PATH
];
868 HANDLE added_printer
;
870 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
872 TRACE("%s\n", loaderror
);
875 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
877 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
880 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 );
884 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
886 ERR("Can't create Printers key\n");
890 nrofdests
= pcupsGetDests(&dests
);
891 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
892 for (i
=0;i
<nrofdests
;i
++) {
893 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[i
].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
895 port
= HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port
) + lstrlenW(nameW
) * sizeof(WCHAR
));
896 lstrcpyW(port
, CUPS_Port
);
897 lstrcatW(port
, nameW
);
899 TRACE("Printer %d: %s\n", i
, debugstr_w(nameW
));
900 if(RegOpenKeyW(hkeyPrinters
, nameW
, &hkeyPrinter
) == ERROR_SUCCESS
) {
901 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
902 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
904 TRACE("Printer already exists\n");
905 /* overwrite old LPR:* port */
906 RegSetValueExW(hkeyPrinter
, PortW
, 0, REG_SZ
, (LPBYTE
)port
, (lstrlenW(port
) + 1) * sizeof(WCHAR
));
907 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
908 /* flag that the PPD file should be checked for an update */
909 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
910 RegCloseKey(hkeyPrinter
);
912 BOOL added_driver
= FALSE
;
914 if (!ppd_dir
) ppd_dir
= get_ppd_dir();
915 ppd
= get_ppd_filename( ppd_dir
, nameW
);
916 if (get_cups_ppd( dests
[i
].name
, ppd
))
918 added_driver
= add_printer_driver( nameW
, ppd
);
921 HeapFree( GetProcessHeap(), 0, ppd
);
922 if (!added_driver
) continue;
924 memset(&pi2
, 0, sizeof(PRINTER_INFO_2W
));
925 pi2
.pPrinterName
= nameW
;
926 pi2
.pDatatype
= rawW
;
927 pi2
.pPrintProcessor
= WinPrintW
;
928 pi2
.pDriverName
= nameW
;
929 pi2
.pComment
= get_cups_option( "printer-info", dests
[i
].num_options
, dests
[i
].options
);
930 pi2
.pLocation
= get_cups_option( "printer-location", dests
[i
].num_options
, dests
[i
].options
);
931 pi2
.pPortName
= port
;
932 pi2
.pParameters
= emptyStringW
;
933 pi2
.pShareName
= emptyStringW
;
934 pi2
.pSepFile
= emptyStringW
;
936 added_printer
= AddPrinterW( NULL
, 2, (LPBYTE
)&pi2
);
937 if (added_printer
) ClosePrinter( added_printer
);
938 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
939 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW
), GetLastError() );
941 HeapFree( GetProcessHeap(), 0, pi2
.pComment
);
942 HeapFree( GetProcessHeap(), 0, pi2
.pLocation
);
944 HeapFree( GetProcessHeap(), 0, port
);
947 if (dests
[i
].is_default
) {
948 SetDefaultPrinterW(nameW
);
955 RemoveDirectoryW( ppd_dir
);
956 HeapFree( GetProcessHeap(), 0, ppd_dir
);
959 if (hadprinter
&& !haddefault
) {
960 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[0].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
961 SetDefaultPrinterW(nameW
);
963 pcupsFreeDests(nrofdests
, dests
);
964 RegCloseKey(hkeyPrinters
);
970 static char *get_queue_name( HANDLE printer
, BOOL
*cups
)
972 WCHAR
*port
, *name
= NULL
;
973 DWORD err
, needed
, type
;
979 err
= WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
);
980 if (err
) return NULL
;
981 err
= RegQueryValueExW( key
, PortW
, 0, &type
, NULL
, &needed
);
983 port
= HeapAlloc( GetProcessHeap(), 0, needed
);
985 RegQueryValueExW( key
, PortW
, 0, &type
, (BYTE
*)port
, &needed
);
987 if (!strncmpW( port
, CUPS_Port
, sizeof(CUPS_Port
) / sizeof(WCHAR
) -1 ))
989 name
= port
+ sizeof(CUPS_Port
) / sizeof(WCHAR
) - 1;
992 else if (!strncmpW( port
, LPR_Port
, sizeof(LPR_Port
) / sizeof(WCHAR
) -1 ))
993 name
= port
+ sizeof(LPR_Port
) / sizeof(WCHAR
) - 1;
996 needed
= WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, NULL
, 0, NULL
, NULL
);
997 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
998 if(ret
) WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, ret
, needed
, NULL
, NULL
);
1000 HeapFree( GetProcessHeap(), 0, port
);
1007 static void set_ppd_overrides( HANDLE printer
)
1011 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1013 PMPrintSession session
= NULL
;
1014 PMPageFormat format
= NULL
;
1016 CFStringRef paper_name
;
1019 status
= PMCreateSession( &session
);
1020 if (status
) goto end
;
1022 status
= PMCreatePageFormat( &format
);
1023 if (status
) goto end
;
1025 status
= PMSessionDefaultPageFormat( session
, format
);
1026 if (status
) goto end
;
1028 status
= PMGetPageFormatPaper( format
, &paper
);
1029 if (status
) goto end
;
1031 status
= PMPaperGetPPDPaperName( paper
, &paper_name
);
1032 if (status
) goto end
;
1035 range
.length
= CFStringGetLength( paper_name
);
1036 size
= (range
.length
+ 1) * sizeof(WCHAR
);
1038 wstr
= HeapAlloc( GetProcessHeap(), 0, size
);
1039 CFStringGetCharacters( paper_name
, range
, (UniChar
*)wstr
);
1040 wstr
[range
.length
] = 0;
1043 if (format
) PMRelease( format
);
1044 if (session
) PMRelease( session
);
1047 SetPrinterDataExW( printer
, PPD_Overrides
, DefaultPageSize
, REG_SZ
, (BYTE
*)wstr
, size
);
1048 HeapFree( GetProcessHeap(), 0, wstr
);
1051 static BOOL
update_driver( HANDLE printer
)
1054 const WCHAR
*name
= get_opened_printer_name( printer
);
1055 WCHAR
*ppd_dir
, *ppd
;
1058 if (!name
) return FALSE
;
1059 queue_name
= get_queue_name( printer
, &is_cups
);
1060 if (!queue_name
) return FALSE
;
1062 ppd_dir
= get_ppd_dir();
1063 ppd
= get_ppd_filename( ppd_dir
, name
);
1065 #ifdef SONAME_LIBCUPS
1067 ret
= get_cups_ppd( queue_name
, ppd
);
1070 ret
= get_fallback_ppd( queue_name
, ppd
);
1074 TRACE( "updating driver %s\n", debugstr_w( name
) );
1075 ret
= add_printer_driver( name
, ppd
);
1078 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1079 HeapFree( GetProcessHeap(), 0, ppd
);
1080 HeapFree( GetProcessHeap(), 0, queue_name
);
1082 set_ppd_overrides( printer
);
1084 /* call into the driver to update the devmode */
1085 DocumentPropertiesW( 0, printer
, NULL
, NULL
, NULL
, 0 );
1090 static BOOL
PRINTCAP_ParseEntry( const char *pent
, BOOL isfirst
)
1092 PRINTER_INFO_2A pinfo2a
;
1095 char *e
,*s
,*name
,*prettyname
,*devname
;
1096 BOOL ret
= FALSE
, set_default
= FALSE
;
1097 char *port
= NULL
, *env_default
;
1098 HKEY hkeyPrinter
, hkeyPrinters
= NULL
;
1099 WCHAR devnameW
[MAX_PATH
], *ppd_dir
= NULL
, *ppd
;
1100 HANDLE added_printer
;
1102 while (isspace(*pent
)) pent
++;
1103 r
= strchr(pent
,':');
1105 name_len
= r
- pent
;
1107 name_len
= strlen(pent
);
1108 name
= HeapAlloc(GetProcessHeap(), 0, name_len
+ 1);
1109 memcpy(name
, pent
, name_len
);
1110 name
[name_len
] = '\0';
1116 TRACE("name=%s entry=%s\n",name
, pent
);
1118 if(ispunct(*name
)) { /* a tc entry, not a real printer */
1119 TRACE("skipping tc entry\n");
1123 if(strstr(pent
,":server")) { /* server only version so skip */
1124 TRACE("skipping server entry\n");
1128 /* Determine whether this is a postscript printer. */
1131 env_default
= getenv("PRINTER");
1133 /* Get longest name, usually the one at the right for later display. */
1134 while((s
=strchr(prettyname
,'|'))) {
1137 while(isspace(*--e
)) *e
= '\0';
1138 TRACE("\t%s\n", debugstr_a(prettyname
));
1139 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
1140 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
1143 e
= prettyname
+ strlen(prettyname
);
1144 while(isspace(*--e
)) *e
= '\0';
1145 TRACE("\t%s\n", debugstr_a(prettyname
));
1146 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
1148 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1149 * if it is too long, we use it as comment below. */
1150 devname
= prettyname
;
1151 if (strlen(devname
)>=CCHDEVICENAME
-1)
1153 if (strlen(devname
)>=CCHDEVICENAME
-1) {
1158 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
1159 sprintf(port
,"LPR:%s",name
);
1161 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
1163 ERR("Can't create Printers key\n");
1168 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, sizeof(devnameW
) / sizeof(WCHAR
));
1170 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
1171 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
1172 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1174 TRACE("Printer already exists\n");
1175 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
1176 /* flag that the PPD file should be checked for an update */
1177 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
1178 RegCloseKey(hkeyPrinter
);
1180 static CHAR data_type
[] = "RAW",
1181 print_proc
[] = "WinPrint",
1182 comment
[] = "WINEPS Printer using LPR",
1183 params
[] = "<parameters?>",
1184 share_name
[] = "<share name?>",
1185 sep_file
[] = "<sep file?>";
1186 BOOL added_driver
= FALSE
;
1188 if (!ppd_dir
) ppd_dir
= get_ppd_dir();
1189 ppd
= get_ppd_filename( ppd_dir
, devnameW
);
1190 if (get_fallback_ppd( devname
, ppd
))
1192 added_driver
= add_printer_driver( devnameW
, ppd
);
1195 HeapFree( GetProcessHeap(), 0, ppd
);
1196 if (!added_driver
) goto end
;
1198 memset(&pinfo2a
,0,sizeof(pinfo2a
));
1199 pinfo2a
.pPrinterName
= devname
;
1200 pinfo2a
.pDatatype
= data_type
;
1201 pinfo2a
.pPrintProcessor
= print_proc
;
1202 pinfo2a
.pDriverName
= devname
;
1203 pinfo2a
.pComment
= comment
;
1204 pinfo2a
.pLocation
= prettyname
;
1205 pinfo2a
.pPortName
= port
;
1206 pinfo2a
.pParameters
= params
;
1207 pinfo2a
.pShareName
= share_name
;
1208 pinfo2a
.pSepFile
= sep_file
;
1210 added_printer
= AddPrinterA( NULL
, 2, (LPBYTE
)&pinfo2a
);
1211 if (added_printer
) ClosePrinter( added_printer
);
1212 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
1213 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name
), GetLastError() );
1216 if (isfirst
|| set_default
)
1217 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
1220 if (hkeyPrinters
) RegCloseKey( hkeyPrinters
);
1223 RemoveDirectoryW( ppd_dir
);
1224 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1226 HeapFree(GetProcessHeap(), 0, port
);
1227 HeapFree(GetProcessHeap(), 0, name
);
1232 PRINTCAP_LoadPrinters(void) {
1233 BOOL hadprinter
= FALSE
;
1237 BOOL had_bash
= FALSE
;
1239 f
= fopen("/etc/printcap","r");
1243 while(fgets(buf
,sizeof(buf
),f
)) {
1246 end
=strchr(buf
,'\n');
1250 while(isspace(*start
)) start
++;
1251 if(*start
== '#' || *start
== '\0')
1254 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
1255 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1256 HeapFree(GetProcessHeap(),0,pent
);
1260 if (end
&& *--end
== '\\') {
1267 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
1270 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
1276 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1277 HeapFree(GetProcessHeap(),0,pent
);
1283 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
1286 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
1287 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
1289 return ERROR_FILE_NOT_FOUND
;
1292 static inline DWORD
set_reg_devmode( HKEY key
, const WCHAR
*name
, const DEVMODEW
*dm
)
1294 DEVMODEA
*dmA
= DEVMODEdupWtoA( dm
);
1295 DWORD ret
= ERROR_FILE_NOT_FOUND
;
1297 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1298 and we support these drivers. NT writes DEVMODEW so somehow
1299 we'll need to distinguish between these when we support NT
1304 ret
= RegSetValueExW( key
, name
, 0, REG_BINARY
,
1305 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1306 HeapFree( GetProcessHeap(), 0, dmA
);
1312 /******************************************************************
1313 * get_servername_from_name (internal)
1315 * for an external server, a copy of the serverpart from the full name is returned
1318 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1322 WCHAR buffer
[MAX_PATH
];
1325 if (name
== NULL
) return NULL
;
1326 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1328 server
= strdupW(&name
[2]); /* skip over both backslash */
1329 if (server
== NULL
) return NULL
;
1331 /* strip '\' and the printername */
1332 ptr
= strchrW(server
, '\\');
1333 if (ptr
) ptr
[0] = '\0';
1335 TRACE("found %s\n", debugstr_w(server
));
1337 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1338 if (GetComputerNameW(buffer
, &len
)) {
1339 if (lstrcmpW(buffer
, server
) == 0) {
1340 /* The requested Servername is our computername */
1341 HeapFree(GetProcessHeap(), 0, server
);
1348 /******************************************************************
1349 * get_basename_from_name (internal)
1351 * skip over the serverpart from the full name
1354 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1356 if (name
== NULL
) return NULL
;
1357 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1358 /* skip over the servername and search for the following '\' */
1359 name
= strchrW(&name
[2], '\\');
1360 if ((name
) && (name
[1])) {
1361 /* found a separator ('\') followed by a name:
1362 skip over the separator and return the rest */
1367 /* no basename present (we found only a servername) */
1374 static void free_printer_entry( opened_printer_t
*printer
)
1376 /* the queue is shared, so don't free that here */
1377 HeapFree( GetProcessHeap(), 0, printer
->printername
);
1378 HeapFree( GetProcessHeap(), 0, printer
->name
);
1379 HeapFree( GetProcessHeap(), 0, printer
->devmode
);
1380 HeapFree( GetProcessHeap(), 0, printer
);
1383 /******************************************************************
1384 * get_opened_printer_entry
1385 * Get the first place empty in the opened printer table
1388 * - pDefault is ignored
1390 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1392 UINT_PTR handle
= nb_printer_handles
, i
;
1393 jobqueue_t
*queue
= NULL
;
1394 opened_printer_t
*printer
= NULL
;
1396 LPCWSTR printername
;
1398 if ((backend
== NULL
) && !load_backend()) return NULL
;
1400 servername
= get_servername_from_name(name
);
1402 FIXME("server %s not supported\n", debugstr_w(servername
));
1403 HeapFree(GetProcessHeap(), 0, servername
);
1404 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1408 printername
= get_basename_from_name(name
);
1409 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1411 /* an empty printername is invalid */
1412 if (printername
&& (!printername
[0])) {
1413 SetLastError(ERROR_INVALID_PARAMETER
);
1417 EnterCriticalSection(&printer_handles_cs
);
1419 for (i
= 0; i
< nb_printer_handles
; i
++)
1421 if (!printer_handles
[i
])
1423 if(handle
== nb_printer_handles
)
1428 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1429 queue
= printer_handles
[i
]->queue
;
1433 if (handle
>= nb_printer_handles
)
1435 opened_printer_t
**new_array
;
1436 if (printer_handles
)
1437 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1438 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1440 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1441 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1448 printer_handles
= new_array
;
1449 nb_printer_handles
+= 16;
1452 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1458 /* get a printer handle from the backend */
1459 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
1464 /* clone the base name. This is NULL for the printserver */
1465 printer
->printername
= strdupW(printername
);
1467 /* clone the full name */
1468 printer
->name
= strdupW(name
);
1469 if (name
&& (!printer
->name
)) {
1474 if (pDefault
&& pDefault
->pDevMode
)
1475 printer
->devmode
= dup_devmode( pDefault
->pDevMode
);
1478 printer
->queue
= queue
;
1481 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1482 if (!printer
->queue
) {
1486 list_init(&printer
->queue
->jobs
);
1487 printer
->queue
->ref
= 0;
1489 InterlockedIncrement(&printer
->queue
->ref
);
1491 printer_handles
[handle
] = printer
;
1494 LeaveCriticalSection(&printer_handles_cs
);
1495 if (!handle
&& printer
) {
1496 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1497 free_printer_entry( printer
);
1500 return (HANDLE
)handle
;
1503 static void old_printer_check( BOOL delete_phase
)
1505 PRINTER_INFO_5W
* pi
;
1506 DWORD needed
, type
, num
, delete, i
, size
;
1507 const DWORD one
= 1;
1511 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1512 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return;
1514 pi
= HeapAlloc( GetProcessHeap(), 0, needed
);
1515 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
);
1516 for (i
= 0; i
< num
; i
++)
1518 if (strncmpW( pi
[i
].pPortName
, CUPS_Port
, strlenW(CUPS_Port
) ) &&
1519 strncmpW( pi
[i
].pPortName
, LPR_Port
, strlenW(LPR_Port
) ))
1522 if (open_printer_reg_key( pi
[i
].pPrinterName
, &key
)) continue;
1526 RegSetValueExW( key
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&one
, sizeof(one
) );
1532 size
= sizeof( delete );
1533 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&delete, &size
);
1537 TRACE( "Deleting old printer %s\n", debugstr_w(pi
[i
].pPrinterName
) );
1538 if (OpenPrinterW( pi
[i
].pPrinterName
, &hprn
, NULL
))
1540 DeletePrinter( hprn
);
1541 ClosePrinter( hprn
);
1543 DeletePrinterDriverExW( NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0 );
1547 HeapFree(GetProcessHeap(), 0, pi
);
1550 static const WCHAR winspool_mutex_name
[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1551 'M','U','T','E','X','_','_','\0'};
1552 static HANDLE init_mutex
;
1554 void WINSPOOL_LoadSystemPrinters(void)
1556 HKEY hkey
, hkeyPrinters
;
1557 DWORD needed
, num
, i
;
1558 WCHAR PrinterName
[256];
1561 /* FIXME: The init code should be moved to spoolsv.exe */
1562 init_mutex
= CreateMutexW( NULL
, TRUE
, winspool_mutex_name
);
1565 ERR( "Failed to create mutex\n" );
1568 if (GetLastError() == ERROR_ALREADY_EXISTS
)
1570 WaitForSingleObject( init_mutex
, INFINITE
);
1571 ReleaseMutex( init_mutex
);
1572 TRACE( "Init already done\n" );
1576 /* This ensures that all printer entries have a valid Name value. If causes
1577 problems later if they don't. If one is found to be missed we create one
1578 and set it equal to the name of the key */
1579 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1580 if(RegQueryInfoKeyW(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1581 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1582 for(i
= 0; i
< num
; i
++) {
1583 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1584 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1585 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1586 set_reg_szW(hkey
, NameW
, PrinterName
);
1593 RegCloseKey(hkeyPrinters
);
1596 old_printer_check( FALSE
);
1598 #ifdef SONAME_LIBCUPS
1599 done
= CUPS_LoadPrinters();
1602 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1603 PRINTCAP_LoadPrinters();
1605 old_printer_check( TRUE
);
1607 ReleaseMutex( init_mutex
);
1611 /******************************************************************
1614 * Get the pointer to the specified job.
1615 * Should hold the printer_handles_cs before calling.
1617 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1619 opened_printer_t
*printer
= get_opened_printer(hprn
);
1622 if(!printer
) return NULL
;
1623 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1625 if(job
->job_id
== JobId
)
1631 /***********************************************************
1634 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1637 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1640 Formname
= (dmA
->dmSize
> off_formname
);
1641 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1642 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1643 dmW
->dmDeviceName
, CCHDEVICENAME
);
1645 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1646 dmA
->dmSize
- CCHDEVICENAME
);
1648 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1649 off_formname
- CCHDEVICENAME
);
1650 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1651 dmW
->dmFormName
, CCHFORMNAME
);
1652 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1653 (off_formname
+ CCHFORMNAME
));
1656 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1657 dmA
->dmDriverExtra
);
1661 /******************************************************************
1662 * convert_printerinfo_W_to_A [internal]
1665 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1666 DWORD level
, DWORD outlen
, DWORD numentries
)
1672 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1674 len
= pi_sizeof
[level
] * numentries
;
1675 ptr
= (LPSTR
) out
+ len
;
1678 /* copy the numbers of all PRINTER_INFO_* first */
1679 memcpy(out
, pPrintersW
, len
);
1681 while (id
< numentries
) {
1685 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1686 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1688 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1689 if (piW
->pDescription
) {
1690 piA
->pDescription
= ptr
;
1691 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1692 ptr
, outlen
, NULL
, NULL
);
1698 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1699 ptr
, outlen
, NULL
, NULL
);
1703 if (piW
->pComment
) {
1704 piA
->pComment
= ptr
;
1705 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1706 ptr
, outlen
, NULL
, NULL
);
1715 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1716 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1719 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1720 if (piW
->pServerName
) {
1721 piA
->pServerName
= ptr
;
1722 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1723 ptr
, outlen
, NULL
, NULL
);
1727 if (piW
->pPrinterName
) {
1728 piA
->pPrinterName
= ptr
;
1729 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1730 ptr
, outlen
, NULL
, NULL
);
1734 if (piW
->pShareName
) {
1735 piA
->pShareName
= ptr
;
1736 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1737 ptr
, outlen
, NULL
, NULL
);
1741 if (piW
->pPortName
) {
1742 piA
->pPortName
= ptr
;
1743 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1744 ptr
, outlen
, NULL
, NULL
);
1748 if (piW
->pDriverName
) {
1749 piA
->pDriverName
= ptr
;
1750 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1751 ptr
, outlen
, NULL
, NULL
);
1755 if (piW
->pComment
) {
1756 piA
->pComment
= ptr
;
1757 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1758 ptr
, outlen
, NULL
, NULL
);
1762 if (piW
->pLocation
) {
1763 piA
->pLocation
= ptr
;
1764 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1765 ptr
, outlen
, NULL
, NULL
);
1770 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1772 /* align DEVMODEA to a DWORD boundary */
1773 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1777 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1778 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1779 memcpy(ptr
, dmA
, len
);
1780 HeapFree(GetProcessHeap(), 0, dmA
);
1786 if (piW
->pSepFile
) {
1787 piA
->pSepFile
= ptr
;
1788 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1789 ptr
, outlen
, NULL
, NULL
);
1793 if (piW
->pPrintProcessor
) {
1794 piA
->pPrintProcessor
= ptr
;
1795 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1796 ptr
, outlen
, NULL
, NULL
);
1800 if (piW
->pDatatype
) {
1801 piA
->pDatatype
= ptr
;
1802 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1803 ptr
, outlen
, NULL
, NULL
);
1807 if (piW
->pParameters
) {
1808 piA
->pParameters
= ptr
;
1809 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1810 ptr
, outlen
, NULL
, NULL
);
1814 if (piW
->pSecurityDescriptor
) {
1815 piA
->pSecurityDescriptor
= NULL
;
1816 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1823 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1824 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1826 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1828 if (piW
->pPrinterName
) {
1829 piA
->pPrinterName
= ptr
;
1830 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1831 ptr
, outlen
, NULL
, NULL
);
1835 if (piW
->pServerName
) {
1836 piA
->pServerName
= ptr
;
1837 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1838 ptr
, outlen
, NULL
, NULL
);
1847 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1848 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1850 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1852 if (piW
->pPrinterName
) {
1853 piA
->pPrinterName
= ptr
;
1854 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1855 ptr
, outlen
, NULL
, NULL
);
1859 if (piW
->pPortName
) {
1860 piA
->pPortName
= ptr
;
1861 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1862 ptr
, outlen
, NULL
, NULL
);
1869 case 6: /* 6A and 6W are the same structure */
1874 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1875 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1877 TRACE("(%u) #%u\n", level
, id
);
1878 if (piW
->pszObjectGUID
) {
1879 piA
->pszObjectGUID
= ptr
;
1880 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1881 ptr
, outlen
, NULL
, NULL
);
1891 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1892 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1895 TRACE("(%u) #%u\n", level
, id
);
1896 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1898 /* align DEVMODEA to a DWORD boundary */
1899 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1903 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1904 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1905 memcpy(ptr
, dmA
, len
);
1906 HeapFree(GetProcessHeap(), 0, dmA
);
1916 FIXME("for level %u\n", level
);
1918 pPrintersW
+= pi_sizeof
[level
];
1919 out
+= pi_sizeof
[level
];
1924 /******************************************************************
1925 * convert_driverinfo_W_to_A [internal]
1928 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1929 DWORD level
, DWORD outlen
, DWORD numentries
)
1935 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1937 len
= di_sizeof
[level
] * numentries
;
1938 ptr
= (LPSTR
) out
+ len
;
1941 /* copy the numbers of all PRINTER_INFO_* first */
1942 memcpy(out
, pDriversW
, len
);
1944 #define COPY_STRING(fld) \
1947 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1948 ptr += len; outlen -= len;\
1950 #define COPY_MULTIZ_STRING(fld) \
1951 { LPWSTR p = diW->fld; if (p){ \
1954 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1955 ptr += len; outlen -= len; p += len;\
1957 while(len > 1 && outlen > 0); \
1960 while (id
< numentries
)
1966 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
1967 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
1969 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1976 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
1977 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
1979 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1982 COPY_STRING(pEnvironment
);
1983 COPY_STRING(pDriverPath
);
1984 COPY_STRING(pDataFile
);
1985 COPY_STRING(pConfigFile
);
1990 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
1991 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
1993 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1996 COPY_STRING(pEnvironment
);
1997 COPY_STRING(pDriverPath
);
1998 COPY_STRING(pDataFile
);
1999 COPY_STRING(pConfigFile
);
2000 COPY_STRING(pHelpFile
);
2001 COPY_MULTIZ_STRING(pDependentFiles
);
2002 COPY_STRING(pMonitorName
);
2003 COPY_STRING(pDefaultDataType
);
2008 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
2009 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
2011 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2014 COPY_STRING(pEnvironment
);
2015 COPY_STRING(pDriverPath
);
2016 COPY_STRING(pDataFile
);
2017 COPY_STRING(pConfigFile
);
2018 COPY_STRING(pHelpFile
);
2019 COPY_MULTIZ_STRING(pDependentFiles
);
2020 COPY_STRING(pMonitorName
);
2021 COPY_STRING(pDefaultDataType
);
2022 COPY_MULTIZ_STRING(pszzPreviousNames
);
2027 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
2028 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
2030 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2033 COPY_STRING(pEnvironment
);
2034 COPY_STRING(pDriverPath
);
2035 COPY_STRING(pDataFile
);
2036 COPY_STRING(pConfigFile
);
2041 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
2042 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
2044 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2047 COPY_STRING(pEnvironment
);
2048 COPY_STRING(pDriverPath
);
2049 COPY_STRING(pDataFile
);
2050 COPY_STRING(pConfigFile
);
2051 COPY_STRING(pHelpFile
);
2052 COPY_MULTIZ_STRING(pDependentFiles
);
2053 COPY_STRING(pMonitorName
);
2054 COPY_STRING(pDefaultDataType
);
2055 COPY_MULTIZ_STRING(pszzPreviousNames
);
2056 COPY_STRING(pszMfgName
);
2057 COPY_STRING(pszOEMUrl
);
2058 COPY_STRING(pszHardwareID
);
2059 COPY_STRING(pszProvider
);
2064 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
2065 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
2067 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2070 COPY_STRING(pEnvironment
);
2071 COPY_STRING(pDriverPath
);
2072 COPY_STRING(pDataFile
);
2073 COPY_STRING(pConfigFile
);
2074 COPY_STRING(pHelpFile
);
2075 COPY_MULTIZ_STRING(pDependentFiles
);
2076 COPY_STRING(pMonitorName
);
2077 COPY_STRING(pDefaultDataType
);
2078 COPY_MULTIZ_STRING(pszzPreviousNames
);
2079 COPY_STRING(pszMfgName
);
2080 COPY_STRING(pszOEMUrl
);
2081 COPY_STRING(pszHardwareID
);
2082 COPY_STRING(pszProvider
);
2083 COPY_STRING(pszPrintProcessor
);
2084 COPY_STRING(pszVendorSetup
);
2085 COPY_MULTIZ_STRING(pszzColorProfiles
);
2086 COPY_STRING(pszInfPath
);
2087 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
2093 FIXME("for level %u\n", level
);
2096 pDriversW
+= di_sizeof
[level
];
2097 out
+= di_sizeof
[level
];
2102 #undef COPY_MULTIZ_STRING
2106 /***********************************************************
2109 static void *printer_info_AtoW( const void *data
, DWORD level
)
2112 UNICODE_STRING usBuffer
;
2114 if (!data
) return NULL
;
2116 if (level
< 1 || level
> 9) return NULL
;
2118 ret
= HeapAlloc( GetProcessHeap(), 0, pi_sizeof
[level
] );
2119 if (!ret
) return NULL
;
2121 memcpy( ret
, data
, pi_sizeof
[level
] ); /* copy everything first */
2127 const PRINTER_INFO_2A
*piA
= (const PRINTER_INFO_2A
*)data
;
2128 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)ret
;
2130 piW
->pServerName
= asciitounicode( &usBuffer
, piA
->pServerName
);
2131 piW
->pPrinterName
= asciitounicode( &usBuffer
, piA
->pPrinterName
);
2132 piW
->pShareName
= asciitounicode( &usBuffer
, piA
->pShareName
);
2133 piW
->pPortName
= asciitounicode( &usBuffer
, piA
->pPortName
);
2134 piW
->pDriverName
= asciitounicode( &usBuffer
, piA
->pDriverName
);
2135 piW
->pComment
= asciitounicode( &usBuffer
, piA
->pComment
);
2136 piW
->pLocation
= asciitounicode( &usBuffer
, piA
->pLocation
);
2137 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2138 piW
->pSepFile
= asciitounicode( &usBuffer
, piA
->pSepFile
);
2139 piW
->pPrintProcessor
= asciitounicode( &usBuffer
, piA
->pPrintProcessor
);
2140 piW
->pDatatype
= asciitounicode( &usBuffer
, piA
->pDatatype
);
2141 piW
->pParameters
= asciitounicode( &usBuffer
, piA
->pParameters
);
2148 const PRINTER_INFO_9A
*piA
= (const PRINTER_INFO_9A
*)data
;
2149 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)ret
;
2151 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2156 FIXME( "Unhandled level %d\n", level
);
2157 HeapFree( GetProcessHeap(), 0, ret
);
2164 /***********************************************************
2167 static void free_printer_info( void *data
, DWORD level
)
2175 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)data
;
2177 HeapFree( GetProcessHeap(), 0, piW
->pServerName
);
2178 HeapFree( GetProcessHeap(), 0, piW
->pPrinterName
);
2179 HeapFree( GetProcessHeap(), 0, piW
->pShareName
);
2180 HeapFree( GetProcessHeap(), 0, piW
->pPortName
);
2181 HeapFree( GetProcessHeap(), 0, piW
->pDriverName
);
2182 HeapFree( GetProcessHeap(), 0, piW
->pComment
);
2183 HeapFree( GetProcessHeap(), 0, piW
->pLocation
);
2184 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2185 HeapFree( GetProcessHeap(), 0, piW
->pSepFile
);
2186 HeapFree( GetProcessHeap(), 0, piW
->pPrintProcessor
);
2187 HeapFree( GetProcessHeap(), 0, piW
->pDatatype
);
2188 HeapFree( GetProcessHeap(), 0, piW
->pParameters
);
2195 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)data
;
2197 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2202 FIXME( "Unhandled level %d\n", level
);
2205 HeapFree( GetProcessHeap(), 0, data
);
2209 /******************************************************************
2210 * DeviceCapabilities [WINSPOOL.@]
2211 * DeviceCapabilitiesA [WINSPOOL.@]
2214 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
2215 LPSTR pOutput
, LPDEVMODEA lpdm
)
2219 if (!GDI_CallDeviceCapabilities16
)
2221 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2223 if (!GDI_CallDeviceCapabilities16
) return -1;
2225 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
2227 /* If DC_PAPERSIZE map POINT16s to POINTs */
2228 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
2229 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
2230 POINT
*pt
= (POINT
*)pOutput
;
2232 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
2233 for(i
= 0; i
< ret
; i
++, pt
++)
2238 HeapFree( GetProcessHeap(), 0, tmp
);
2244 /*****************************************************************************
2245 * DeviceCapabilitiesW [WINSPOOL.@]
2247 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2250 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
2251 WORD fwCapability
, LPWSTR pOutput
,
2252 const DEVMODEW
*pDevMode
)
2254 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
2255 LPSTR pDeviceA
= strdupWtoA(pDevice
);
2256 LPSTR pPortA
= strdupWtoA(pPort
);
2259 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
2260 fwCapability
== DC_FILEDEPENDENCIES
||
2261 fwCapability
== DC_PAPERNAMES
)) {
2262 /* These need A -> W translation */
2265 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
2269 switch(fwCapability
) {
2274 case DC_FILEDEPENDENCIES
:
2278 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
2279 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
2281 for(i
= 0; i
< ret
; i
++)
2282 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
2283 pOutput
+ (i
* size
), size
);
2284 HeapFree(GetProcessHeap(), 0, pOutputA
);
2286 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
2287 (LPSTR
)pOutput
, dmA
);
2289 HeapFree(GetProcessHeap(),0,pPortA
);
2290 HeapFree(GetProcessHeap(),0,pDeviceA
);
2291 HeapFree(GetProcessHeap(),0,dmA
);
2295 /******************************************************************
2296 * DocumentPropertiesA [WINSPOOL.@]
2298 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2300 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
2301 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
2302 LPDEVMODEA pDevModeInput
,DWORD fMode
)
2304 LPSTR lpName
= pDeviceName
;
2305 static CHAR port
[] = "LPT1:";
2308 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2309 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
2313 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2315 ERR("no name from hPrinter?\n");
2316 SetLastError(ERROR_INVALID_HANDLE
);
2319 lpName
= strdupWtoA(lpNameW
);
2322 if (!GDI_CallExtDeviceMode16
)
2324 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2326 if (!GDI_CallExtDeviceMode16
) {
2327 ERR("No CallExtDeviceMode16?\n");
2331 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
2332 pDevModeInput
, NULL
, fMode
);
2335 HeapFree(GetProcessHeap(),0,lpName
);
2340 /*****************************************************************************
2341 * DocumentPropertiesW (WINSPOOL.@)
2343 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2345 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
2347 LPDEVMODEW pDevModeOutput
,
2348 LPDEVMODEW pDevModeInput
, DWORD fMode
)
2351 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
2352 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
2353 LPDEVMODEA pDevModeOutputA
= NULL
;
2356 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2357 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
2359 if(pDevModeOutput
) {
2360 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
2361 if(ret
< 0) return ret
;
2362 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
2364 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
2365 pDevModeInputA
, fMode
);
2366 if(pDevModeOutput
) {
2367 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
2368 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
2370 if(fMode
== 0 && ret
> 0)
2371 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2372 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
2373 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
2377 /*****************************************************************************
2378 * IsValidDevmodeA [WINSPOOL.@]
2380 * Validate a DEVMODE structure and fix errors if possible.
2383 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA
*pDevMode
, SIZE_T size
)
2385 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2393 /*****************************************************************************
2394 * IsValidDevmodeW [WINSPOOL.@]
2396 * Validate a DEVMODE structure and fix errors if possible.
2399 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW
*pDevMode
, SIZE_T size
)
2401 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2409 /******************************************************************
2410 * OpenPrinterA [WINSPOOL.@]
2415 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
2416 LPPRINTER_DEFAULTSA pDefault
)
2418 UNICODE_STRING lpPrinterNameW
;
2419 UNICODE_STRING usBuffer
;
2420 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
2421 PWSTR pwstrPrinterNameW
;
2424 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
2427 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
2428 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
2429 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
2430 pDefaultW
= &DefaultW
;
2432 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
2434 RtlFreeUnicodeString(&usBuffer
);
2435 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
2437 RtlFreeUnicodeString(&lpPrinterNameW
);
2441 /******************************************************************
2442 * OpenPrinterW [WINSPOOL.@]
2444 * Open a Printer / Printserver or a Printer-Object
2447 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2448 * phPrinter [O] The resulting Handle is stored here
2449 * pDefault [I] PTR to Default Printer Settings or NULL
2456 * lpPrinterName is one of:
2457 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2458 *| Printer: "PrinterName"
2459 *| Printer-Object: "PrinterName,Job xxx"
2460 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2461 *| XcvPort: "Servername,XcvPort PortName"
2464 *| Printer-Object not supported
2465 *| pDefaults is ignored
2468 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2471 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2474 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2475 SetLastError(ERROR_INVALID_PARAMETER
);
2479 /* Get the unique handle of the printer or Printserver */
2480 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2485 DWORD deleting
= 0, size
= sizeof( deleting
), type
;
2487 WINSPOOL_GetOpenedPrinterRegKey( *phPrinter
, &key
);
2488 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&deleting
, &size
);
2489 WaitForSingleObject( init_mutex
, INFINITE
);
2490 status
= get_dword_from_reg( key
, StatusW
);
2491 set_reg_DWORD( key
, StatusW
, status
& ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
2492 ReleaseMutex( init_mutex
);
2493 if (!deleting
&& (status
& PRINTER_STATUS_DRIVER_UPDATE_NEEDED
))
2494 update_driver( *phPrinter
);
2498 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2499 return (*phPrinter
!= 0);
2502 /******************************************************************
2503 * AddMonitorA [WINSPOOL.@]
2508 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2510 LPWSTR nameW
= NULL
;
2513 LPMONITOR_INFO_2A mi2a
;
2514 MONITOR_INFO_2W mi2w
;
2516 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2517 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2518 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2519 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2520 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2523 SetLastError(ERROR_INVALID_LEVEL
);
2527 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2533 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2534 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2535 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2538 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2540 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2541 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2542 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2544 if (mi2a
->pEnvironment
) {
2545 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2546 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2547 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2549 if (mi2a
->pDLLName
) {
2550 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2551 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2552 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2555 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2557 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2558 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2559 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2561 HeapFree(GetProcessHeap(), 0, nameW
);
2565 /******************************************************************************
2566 * AddMonitorW [WINSPOOL.@]
2568 * Install a Printmonitor
2571 * pName [I] Servername or NULL (local Computer)
2572 * Level [I] Structure-Level (Must be 2)
2573 * pMonitors [I] PTR to MONITOR_INFO_2
2580 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2583 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2585 LPMONITOR_INFO_2W mi2w
;
2587 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2588 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2589 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2590 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2591 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2593 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2596 SetLastError(ERROR_INVALID_LEVEL
);
2600 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2605 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2608 /******************************************************************
2609 * DeletePrinterDriverA [WINSPOOL.@]
2612 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2614 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2617 /******************************************************************
2618 * DeletePrinterDriverW [WINSPOOL.@]
2621 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2623 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2626 /******************************************************************
2627 * DeleteMonitorA [WINSPOOL.@]
2629 * See DeleteMonitorW.
2632 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2634 LPWSTR nameW
= NULL
;
2635 LPWSTR EnvironmentW
= NULL
;
2636 LPWSTR MonitorNameW
= NULL
;
2641 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2642 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2643 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2647 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2648 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2649 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2652 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2653 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2654 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2657 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2659 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2660 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2661 HeapFree(GetProcessHeap(), 0, nameW
);
2665 /******************************************************************
2666 * DeleteMonitorW [WINSPOOL.@]
2668 * Delete a specific Printmonitor from a Printing-Environment
2671 * pName [I] Servername or NULL (local Computer)
2672 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2673 * pMonitorName [I] Name of the Monitor, that should be deleted
2680 * pEnvironment is ignored in Windows for the local Computer.
2683 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2686 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2687 debugstr_w(pMonitorName
));
2689 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2691 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2695 /******************************************************************
2696 * DeletePortA [WINSPOOL.@]
2701 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2703 LPWSTR nameW
= NULL
;
2704 LPWSTR portW
= NULL
;
2708 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2710 /* convert servername to unicode */
2712 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2713 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2714 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2717 /* convert portname to unicode */
2719 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2720 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2721 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2724 res
= DeletePortW(nameW
, hWnd
, portW
);
2725 HeapFree(GetProcessHeap(), 0, nameW
);
2726 HeapFree(GetProcessHeap(), 0, portW
);
2730 /******************************************************************
2731 * DeletePortW [WINSPOOL.@]
2733 * Delete a specific Port
2736 * pName [I] Servername or NULL (local Computer)
2737 * hWnd [I] Handle to parent Window for the Dialog-Box
2738 * pPortName [I] Name of the Port, that should be deleted
2745 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2747 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2749 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2752 SetLastError(RPC_X_NULL_REF_POINTER
);
2756 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2759 /******************************************************************************
2760 * WritePrinter [WINSPOOL.@]
2762 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2764 opened_printer_t
*printer
;
2767 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2769 EnterCriticalSection(&printer_handles_cs
);
2770 printer
= get_opened_printer(hPrinter
);
2773 SetLastError(ERROR_INVALID_HANDLE
);
2779 SetLastError(ERROR_SPL_NO_STARTDOC
);
2783 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2785 LeaveCriticalSection(&printer_handles_cs
);
2789 /*****************************************************************************
2790 * AddFormA [WINSPOOL.@]
2792 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2794 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2798 /*****************************************************************************
2799 * AddFormW [WINSPOOL.@]
2801 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2803 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2807 /*****************************************************************************
2808 * AddJobA [WINSPOOL.@]
2810 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2813 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2817 SetLastError(ERROR_INVALID_LEVEL
);
2821 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2824 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2825 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2826 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2827 if(*pcbNeeded
> cbBuf
) {
2828 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2831 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2832 addjobA
->JobId
= addjobW
->JobId
;
2833 addjobA
->Path
= (char *)(addjobA
+ 1);
2834 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2840 /*****************************************************************************
2841 * AddJobW [WINSPOOL.@]
2843 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2845 opened_printer_t
*printer
;
2848 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2849 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2850 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2852 ADDJOB_INFO_1W
*addjob
;
2854 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2856 EnterCriticalSection(&printer_handles_cs
);
2858 printer
= get_opened_printer(hPrinter
);
2861 SetLastError(ERROR_INVALID_HANDLE
);
2866 SetLastError(ERROR_INVALID_LEVEL
);
2870 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2874 job
->job_id
= InterlockedIncrement(&next_job_id
);
2876 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2877 if(path
[len
- 1] != '\\')
2879 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2880 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2882 len
= strlenW(filename
);
2883 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2884 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2885 job
->portname
= NULL
;
2886 job
->document_title
= strdupW(default_doc_title
);
2887 job
->printer_name
= strdupW(printer
->name
);
2888 job
->devmode
= dup_devmode( printer
->devmode
);
2889 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2891 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2892 if(*pcbNeeded
<= cbBuf
) {
2893 addjob
= (ADDJOB_INFO_1W
*)pData
;
2894 addjob
->JobId
= job
->job_id
;
2895 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2896 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2899 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2902 LeaveCriticalSection(&printer_handles_cs
);
2906 /*****************************************************************************
2907 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2909 * Return the PATH for the Print-Processors
2911 * See GetPrintProcessorDirectoryW.
2915 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2916 DWORD level
, LPBYTE Info
,
2917 DWORD cbBuf
, LPDWORD pcbNeeded
)
2919 LPWSTR serverW
= NULL
;
2924 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2925 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2929 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2930 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2931 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2935 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2936 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2937 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2940 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2941 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2943 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2946 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2947 cbBuf
, NULL
, NULL
) > 0;
2950 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2951 HeapFree(GetProcessHeap(), 0, envW
);
2952 HeapFree(GetProcessHeap(), 0, serverW
);
2956 /*****************************************************************************
2957 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2959 * Return the PATH for the Print-Processors
2962 * server [I] Servername (NT only) or NULL (local Computer)
2963 * env [I] Printing-Environment (see below) or NULL (Default)
2964 * level [I] Structure-Level (must be 1)
2965 * Info [O] PTR to Buffer that receives the Result
2966 * cbBuf [I] Size of Buffer at "Info"
2967 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2968 * required for the Buffer at "Info"
2971 * Success: TRUE and in pcbNeeded the Bytes used in Info
2972 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2973 * if cbBuf is too small
2975 * Native Values returned in Info on Success:
2976 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2977 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2978 *| win9x(Windows 4.0): "%winsysdir%"
2980 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2983 * Only NULL or "" is supported for server
2986 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2987 DWORD level
, LPBYTE Info
,
2988 DWORD cbBuf
, LPDWORD pcbNeeded
)
2991 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
2992 Info
, cbBuf
, pcbNeeded
);
2994 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2997 /* (Level != 1) is ignored in win9x */
2998 SetLastError(ERROR_INVALID_LEVEL
);
3002 if (pcbNeeded
== NULL
) {
3003 /* (pcbNeeded == NULL) is ignored in win9x */
3004 SetLastError(RPC_X_NULL_REF_POINTER
);
3008 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
3011 /*****************************************************************************
3012 * WINSPOOL_OpenDriverReg [internal]
3014 * opens the registry for the printer drivers depending on the given input
3015 * variable pEnvironment
3018 * the opened hkey on success
3021 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
3025 const printenv_t
* env
;
3027 TRACE("(%s)\n", debugstr_w(pEnvironment
));
3029 env
= validate_envW(pEnvironment
);
3030 if (!env
) return NULL
;
3032 buffer
= HeapAlloc( GetProcessHeap(), 0,
3033 (strlenW(DriversW
) + strlenW(env
->envname
) +
3034 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
3036 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
3037 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
3038 HeapFree(GetProcessHeap(), 0, buffer
);
3043 /*****************************************************************************
3044 * set_devices_and_printerports [internal]
3046 * set the [Devices] and [PrinterPorts] entries for a printer.
3049 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
3051 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
3055 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
3057 /* FIXME: the driver must change to "winspool" */
3058 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
3060 lstrcpyW(devline
, driver_nt
);
3061 lstrcatW(devline
, commaW
);
3062 lstrcatW(devline
, pi
->pPortName
);
3064 TRACE("using %s\n", debugstr_w(devline
));
3065 WriteProfileStringW(devicesW
, pi
->pPrinterName
, devline
);
3066 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
3067 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3068 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3072 lstrcatW(devline
, timeout_15_45
);
3073 WriteProfileStringW(PrinterPortsW
, pi
->pPrinterName
, devline
);
3074 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
3075 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3076 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3079 HeapFree(GetProcessHeap(), 0, devline
);
3083 /*****************************************************************************
3084 * AddPrinterW [WINSPOOL.@]
3086 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3088 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
3091 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
3094 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
3097 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
3098 SetLastError(ERROR_INVALID_PARAMETER
);
3102 ERR("Level = %d, unsupported!\n", Level
);
3103 SetLastError(ERROR_INVALID_LEVEL
);
3107 SetLastError(ERROR_INVALID_PARAMETER
);
3110 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3112 ERR("Can't create Printers key\n");
3115 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
3116 if (!RegQueryValueW(hkeyPrinter
, AttributesW
, NULL
, NULL
)) {
3117 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
3118 RegCloseKey(hkeyPrinter
);
3119 RegCloseKey(hkeyPrinters
);
3122 RegCloseKey(hkeyPrinter
);
3124 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
3126 ERR("Can't create Drivers key\n");
3127 RegCloseKey(hkeyPrinters
);
3130 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
3132 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
3133 RegCloseKey(hkeyPrinters
);
3134 RegCloseKey(hkeyDrivers
);
3135 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
3138 RegCloseKey(hkeyDriver
);
3139 RegCloseKey(hkeyDrivers
);
3141 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
3142 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
3143 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
3144 RegCloseKey(hkeyPrinters
);
3148 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
3150 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
3151 SetLastError(ERROR_INVALID_PRINTER_NAME
);
3152 RegCloseKey(hkeyPrinters
);
3156 set_devices_and_printerports(pi
);
3158 set_reg_DWORD(hkeyPrinter
, AttributesW
, pi
->Attributes
);
3159 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
3160 set_reg_DWORD(hkeyPrinter
, Default_PriorityW
, pi
->DefaultPriority
);
3161 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
3162 set_reg_DWORD(hkeyPrinter
, dnsTimeoutW
, 0);
3163 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
3164 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
3165 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
3166 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
3167 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
3168 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
3169 set_reg_DWORD(hkeyPrinter
, PriorityW
, pi
->Priority
);
3170 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
3171 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
3172 set_reg_DWORD(hkeyPrinter
, StartTimeW
, pi
->StartTime
);
3173 set_reg_DWORD(hkeyPrinter
, StatusW
, pi
->Status
);
3174 set_reg_DWORD(hkeyPrinter
, txTimeoutW
, 0);
3175 set_reg_DWORD(hkeyPrinter
, UntilTimeW
, pi
->UntilTime
);
3177 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
3181 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
3182 size
= sizeof(DEVMODEW
);
3188 dm
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3190 if (DocumentPropertiesW(0, 0, pi
->pPrinterName
, dm
, NULL
, DM_OUT_BUFFER
) < 0)
3192 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
3193 HeapFree( GetProcessHeap(), 0, dm
);
3198 /* set devmode to printer name */
3199 lstrcpynW( dm
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
3203 set_reg_devmode( hkeyPrinter
, Default_DevModeW
, dm
);
3204 if (!pi
->pDevMode
) HeapFree( GetProcessHeap(), 0, dm
);
3206 RegCloseKey(hkeyPrinter
);
3207 RegCloseKey(hkeyPrinters
);
3208 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
3209 ERR("OpenPrinter failing\n");
3215 /*****************************************************************************
3216 * AddPrinterA [WINSPOOL.@]
3218 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3220 UNICODE_STRING pNameW
;
3222 PRINTER_INFO_2W
*piW
;
3223 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
3226 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
3228 ERR("Level = %d, unsupported!\n", Level
);
3229 SetLastError(ERROR_INVALID_LEVEL
);
3232 pwstrNameW
= asciitounicode(&pNameW
,pName
);
3233 piW
= printer_info_AtoW( piA
, Level
);
3235 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
3237 free_printer_info( piW
, Level
);
3238 RtlFreeUnicodeString(&pNameW
);
3243 /*****************************************************************************
3244 * ClosePrinter [WINSPOOL.@]
3246 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
3248 UINT_PTR i
= (UINT_PTR
)hPrinter
;
3249 opened_printer_t
*printer
= NULL
;
3252 TRACE("(%p)\n", hPrinter
);
3254 EnterCriticalSection(&printer_handles_cs
);
3256 if ((i
> 0) && (i
<= nb_printer_handles
))
3257 printer
= printer_handles
[i
- 1];
3262 struct list
*cursor
, *cursor2
;
3264 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
3266 if (printer
->backend_printer
) {
3267 backend
->fpClosePrinter(printer
->backend_printer
);
3271 EndDocPrinter(hPrinter
);
3273 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
3275 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
3277 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
3278 ScheduleJob(hPrinter
, job
->job_id
);
3280 HeapFree(GetProcessHeap(), 0, printer
->queue
);
3283 free_printer_entry( printer
);
3284 printer_handles
[i
- 1] = NULL
;
3287 LeaveCriticalSection(&printer_handles_cs
);
3291 /*****************************************************************************
3292 * DeleteFormA [WINSPOOL.@]
3294 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3296 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3300 /*****************************************************************************
3301 * DeleteFormW [WINSPOOL.@]
3303 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3305 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3309 /*****************************************************************************
3310 * DeletePrinter [WINSPOOL.@]
3312 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3314 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3315 HKEY hkeyPrinters
, hkey
;
3316 WCHAR def
[MAX_PATH
];
3317 DWORD size
= sizeof( def
) / sizeof( def
[0] );
3320 SetLastError(ERROR_INVALID_HANDLE
);
3323 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3324 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3325 RegCloseKey(hkeyPrinters
);
3327 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3328 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
3330 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3331 RegDeleteValueW(hkey
, lpNameW
);
3335 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
3336 RegDeleteValueW(hkey
, lpNameW
);
3340 if (GetDefaultPrinterW( def
, &size
) && !strcmpW( def
, lpNameW
))
3342 WriteProfileStringW( windowsW
, deviceW
, NULL
);
3343 if (!RegCreateKeyW( HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
))
3345 RegDeleteValueW( hkey
, deviceW
);
3346 RegCloseKey( hkey
);
3348 SetDefaultPrinterW( NULL
);
3354 /*****************************************************************************
3355 * SetPrinterA [WINSPOOL.@]
3357 BOOL WINAPI
SetPrinterA( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3364 dataW
= printer_info_AtoW( data
, level
);
3365 if (!dataW
) return FALSE
;
3368 ret
= SetPrinterW( printer
, level
, dataW
, command
);
3370 if (dataW
!= data
) free_printer_info( dataW
, level
);
3375 static void set_printer_2( HKEY key
, const PRINTER_INFO_2W
*pi
)
3377 set_reg_szW( key
, NameW
, pi
->pPrinterName
);
3378 set_reg_szW( key
, Share_NameW
, pi
->pShareName
);
3379 set_reg_szW( key
, PortW
, pi
->pPortName
);
3380 set_reg_szW( key
, Printer_DriverW
, pi
->pDriverName
);
3381 set_reg_szW( key
, DescriptionW
, pi
->pComment
);
3382 set_reg_szW( key
, LocationW
, pi
->pLocation
);
3385 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3387 set_reg_szW( key
, Separator_FileW
, pi
->pSepFile
);
3388 set_reg_szW( key
, Print_ProcessorW
, pi
->pPrintProcessor
);
3389 set_reg_szW( key
, DatatypeW
, pi
->pDatatype
);
3390 set_reg_szW( key
, ParametersW
, pi
->pParameters
);
3392 set_reg_DWORD( key
, AttributesW
, pi
->Attributes
);
3393 set_reg_DWORD( key
, PriorityW
, pi
->Priority
);
3394 set_reg_DWORD( key
, Default_PriorityW
, pi
->DefaultPriority
);
3395 set_reg_DWORD( key
, StartTimeW
, pi
->StartTime
);
3396 set_reg_DWORD( key
, UntilTimeW
, pi
->UntilTime
);
3399 static BOOL
set_printer_9( HKEY key
, const PRINTER_INFO_9W
*pi
)
3401 if (!pi
->pDevMode
) return FALSE
;
3403 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3407 /******************************************************************************
3408 * SetPrinterW [WINSPOOL.@]
3410 BOOL WINAPI
SetPrinterW( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3415 TRACE( "(%p, %d, %p, %d)\n", printer
, level
, data
, command
);
3417 if (command
!= 0) FIXME( "Ignoring command %d\n", command
);
3419 if (WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
))
3426 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)data
;
3427 set_printer_2( key
, pi2
);
3434 PRINTER_INFO_9W
*pi
= (PRINTER_INFO_9W
*)data
;
3435 ret
= set_printer_9( key
, pi
);
3440 FIXME( "Unimplemented level %d\n", level
);
3441 SetLastError( ERROR_INVALID_LEVEL
);
3448 /*****************************************************************************
3449 * SetJobA [WINSPOOL.@]
3451 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3452 LPBYTE pJob
, DWORD Command
)
3456 UNICODE_STRING usBuffer
;
3458 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3460 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3461 are all ignored by SetJob, so we don't bother copying them */
3469 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3470 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3472 JobW
= (LPBYTE
)info1W
;
3473 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3474 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3475 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3476 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3477 info1W
->Status
= info1A
->Status
;
3478 info1W
->Priority
= info1A
->Priority
;
3479 info1W
->Position
= info1A
->Position
;
3480 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3485 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3486 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3488 JobW
= (LPBYTE
)info2W
;
3489 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3490 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3491 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3492 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3493 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3494 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3495 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3496 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3497 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3498 info2W
->Status
= info2A
->Status
;
3499 info2W
->Priority
= info2A
->Priority
;
3500 info2W
->Position
= info2A
->Position
;
3501 info2W
->StartTime
= info2A
->StartTime
;
3502 info2W
->UntilTime
= info2A
->UntilTime
;
3503 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3507 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3508 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3511 SetLastError(ERROR_INVALID_LEVEL
);
3515 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3521 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3522 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3523 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3524 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3525 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3530 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3531 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3532 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3533 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3534 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3535 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3536 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3537 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3538 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3542 HeapFree(GetProcessHeap(), 0, JobW
);
3547 /*****************************************************************************
3548 * SetJobW [WINSPOOL.@]
3550 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3551 LPBYTE pJob
, DWORD Command
)
3556 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3557 FIXME("Ignoring everything other than document title\n");
3559 EnterCriticalSection(&printer_handles_cs
);
3560 job
= get_job(hPrinter
, JobId
);
3570 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3571 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3572 job
->document_title
= strdupW(info1
->pDocument
);
3577 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3578 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3579 job
->document_title
= strdupW(info2
->pDocument
);
3580 HeapFree(GetProcessHeap(), 0, job
->devmode
);
3581 job
->devmode
= dup_devmode( info2
->pDevMode
);
3587 SetLastError(ERROR_INVALID_LEVEL
);
3592 LeaveCriticalSection(&printer_handles_cs
);
3596 /*****************************************************************************
3597 * EndDocPrinter [WINSPOOL.@]
3599 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3601 opened_printer_t
*printer
;
3603 TRACE("(%p)\n", hPrinter
);
3605 EnterCriticalSection(&printer_handles_cs
);
3607 printer
= get_opened_printer(hPrinter
);
3610 SetLastError(ERROR_INVALID_HANDLE
);
3616 SetLastError(ERROR_SPL_NO_STARTDOC
);
3620 CloseHandle(printer
->doc
->hf
);
3621 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3622 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3623 printer
->doc
= NULL
;
3626 LeaveCriticalSection(&printer_handles_cs
);
3630 /*****************************************************************************
3631 * EndPagePrinter [WINSPOOL.@]
3633 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3635 FIXME("(%p): stub\n", hPrinter
);
3639 /*****************************************************************************
3640 * StartDocPrinterA [WINSPOOL.@]
3642 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3644 UNICODE_STRING usBuffer
;
3646 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3649 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3650 or one (DOC_INFO_3) extra DWORDs */
3654 doc2W
.JobId
= doc2
->JobId
;
3657 doc2W
.dwMode
= doc2
->dwMode
;
3660 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3661 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3662 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3666 SetLastError(ERROR_INVALID_LEVEL
);
3670 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3672 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3673 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3674 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3679 /*****************************************************************************
3680 * StartDocPrinterW [WINSPOOL.@]
3682 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3684 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3685 opened_printer_t
*printer
;
3686 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3687 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3688 JOB_INFO_1W job_info
;
3689 DWORD needed
, ret
= 0;
3694 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3695 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3696 debugstr_w(doc
->pDatatype
));
3698 if(Level
< 1 || Level
> 3)
3700 SetLastError(ERROR_INVALID_LEVEL
);
3704 EnterCriticalSection(&printer_handles_cs
);
3705 printer
= get_opened_printer(hPrinter
);
3708 SetLastError(ERROR_INVALID_HANDLE
);
3714 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3718 /* Even if we're printing to a file we still add a print job, we'll
3719 just ignore the spool file name */
3721 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3723 ERR("AddJob failed gle %u\n", GetLastError());
3727 /* use pOutputFile only, when it is a real filename */
3728 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3729 filename
= doc
->pOutputFile
;
3731 filename
= addjob
->Path
;
3733 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3734 if(hf
== INVALID_HANDLE_VALUE
)
3737 memset(&job_info
, 0, sizeof(job_info
));
3738 job_info
.pDocument
= doc
->pDocName
;
3739 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3741 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3742 printer
->doc
->hf
= hf
;
3743 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3744 job
= get_job(hPrinter
, ret
);
3745 job
->portname
= strdupW(doc
->pOutputFile
);
3748 LeaveCriticalSection(&printer_handles_cs
);
3753 /*****************************************************************************
3754 * StartPagePrinter [WINSPOOL.@]
3756 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3758 FIXME("(%p): stub\n", hPrinter
);
3762 /*****************************************************************************
3763 * GetFormA [WINSPOOL.@]
3765 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3766 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3768 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3769 Level
,pForm
,cbBuf
,pcbNeeded
);
3773 /*****************************************************************************
3774 * GetFormW [WINSPOOL.@]
3776 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3777 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3779 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3780 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3784 /*****************************************************************************
3785 * SetFormA [WINSPOOL.@]
3787 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3790 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3794 /*****************************************************************************
3795 * SetFormW [WINSPOOL.@]
3797 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3800 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3804 /*****************************************************************************
3805 * ReadPrinter [WINSPOOL.@]
3807 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3808 LPDWORD pNoBytesRead
)
3810 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3814 /*****************************************************************************
3815 * ResetPrinterA [WINSPOOL.@]
3817 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3819 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3823 /*****************************************************************************
3824 * ResetPrinterW [WINSPOOL.@]
3826 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3828 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3832 /*****************************************************************************
3833 * get_filename_from_reg [internal]
3835 * Get ValueName from hkey storing result in out
3836 * when the Value in the registry has only a filename, use driverdir as prefix
3837 * outlen is space left in out
3838 * String is stored either as unicode or ascii
3842 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3843 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3845 WCHAR filename
[MAX_PATH
];
3849 LPWSTR buffer
= filename
;
3853 size
= sizeof(filename
);
3855 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3856 if (ret
== ERROR_MORE_DATA
) {
3857 TRACE("need dynamic buffer: %u\n", size
);
3858 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3860 /* No Memory is bad */
3864 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3867 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3868 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3874 /* do we have a full path ? */
3875 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3876 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3879 /* we must build the full Path */
3881 if ((out
) && (outlen
> dirlen
)) {
3882 lstrcpyW((LPWSTR
)out
, driverdir
);
3890 /* write the filename */
3891 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3892 if ((out
) && (outlen
>= size
)) {
3893 lstrcpyW((LPWSTR
)out
, ptr
);
3900 ptr
+= lstrlenW(ptr
)+1;
3901 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3904 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3906 /* write the multisz-termination */
3907 if (type
== REG_MULTI_SZ
) {
3908 size
= sizeof(WCHAR
);
3911 if (out
&& (outlen
>= size
)) {
3912 memset (out
, 0, size
);
3918 /*****************************************************************************
3919 * WINSPOOL_GetStringFromReg
3921 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3922 * String is stored as unicode.
3924 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3925 DWORD buflen
, DWORD
*needed
)
3927 DWORD sz
= buflen
, type
;
3930 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3931 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3932 WARN("Got ret = %d\n", ret
);
3936 /* add space for terminating '\0' */
3937 sz
+= sizeof(WCHAR
);
3941 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
3946 /*****************************************************************************
3947 * WINSPOOL_GetDefaultDevMode
3949 * Get a default DevMode values for wineps.
3953 static void WINSPOOL_GetDefaultDevMode(
3955 DWORD buflen
, DWORD
*needed
)
3958 static const WCHAR szWwps
[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3960 /* fill default DEVMODE - should be read from ppd... */
3961 ZeroMemory( &dm
, sizeof(dm
) );
3962 memcpy(dm
.dmDeviceName
,szWwps
,sizeof szWwps
);
3963 dm
.dmSpecVersion
= DM_SPECVERSION
;
3964 dm
.dmDriverVersion
= 1;
3965 dm
.dmSize
= sizeof(DEVMODEW
);
3966 dm
.dmDriverExtra
= 0;
3968 DM_ORIENTATION
| DM_PAPERSIZE
|
3969 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3972 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3973 DM_YRESOLUTION
| DM_TTOPTION
;
3975 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3976 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3977 dm
.u1
.s1
.dmPaperLength
= 2970;
3978 dm
.u1
.s1
.dmPaperWidth
= 2100;
3980 dm
.u1
.s1
.dmScale
= 100;
3981 dm
.u1
.s1
.dmCopies
= 1;
3982 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3983 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3986 dm
.dmYResolution
= 300; /* 300dpi */
3987 dm
.dmTTOption
= DMTT_BITMAP
;
3990 /* dm.dmLogPixels */
3991 /* dm.dmBitsPerPel */
3992 /* dm.dmPelsWidth */
3993 /* dm.dmPelsHeight */
3994 /* dm.u2.dmDisplayFlags */
3995 /* dm.dmDisplayFrequency */
3996 /* dm.dmICMMethod */
3997 /* dm.dmICMIntent */
3998 /* dm.dmMediaType */
3999 /* dm.dmDitherType */
4000 /* dm.dmReserved1 */
4001 /* dm.dmReserved2 */
4002 /* dm.dmPanningWidth */
4003 /* dm.dmPanningHeight */
4005 if(buflen
>= sizeof(DEVMODEW
))
4006 memcpy(ptr
, &dm
, sizeof(DEVMODEW
));
4007 *needed
= sizeof(DEVMODEW
);
4010 /*****************************************************************************
4011 * WINSPOOL_GetDevModeFromReg
4013 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4014 * DevMode is stored either as unicode or ascii.
4016 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
4018 DWORD buflen
, DWORD
*needed
)
4020 DWORD sz
= buflen
, type
;
4023 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
4024 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
4025 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
4026 if (sz
< sizeof(DEVMODEA
))
4028 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
4031 /* ensures that dmSize is not erratically bogus if registry is invalid */
4032 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
4033 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
4034 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
4035 if (ptr
&& (buflen
>= sz
)) {
4036 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
4037 memcpy(ptr
, dmW
, sz
);
4038 HeapFree(GetProcessHeap(),0,dmW
);
4044 /*********************************************************************
4045 * WINSPOOL_GetPrinter_1
4047 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4049 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
4050 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4052 DWORD size
, left
= cbBuf
;
4053 BOOL space
= (cbBuf
> 0);
4058 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4059 if(space
&& size
<= left
) {
4060 pi1
->pName
= (LPWSTR
)ptr
;
4068 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4069 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4070 if(space
&& size
<= left
) {
4071 pi1
->pDescription
= (LPWSTR
)ptr
;
4079 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4080 if(space
&& size
<= left
) {
4081 pi1
->pComment
= (LPWSTR
)ptr
;
4089 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
4091 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
4092 memset(pi1
, 0, sizeof(*pi1
));
4096 /*********************************************************************
4097 * WINSPOOL_GetPrinter_2
4099 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4101 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
4102 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4104 DWORD size
, left
= cbBuf
;
4105 BOOL space
= (cbBuf
> 0);
4110 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4111 if(space
&& size
<= left
) {
4112 pi2
->pPrinterName
= (LPWSTR
)ptr
;
4119 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
4120 if(space
&& size
<= left
) {
4121 pi2
->pShareName
= (LPWSTR
)ptr
;
4128 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4129 if(space
&& size
<= left
) {
4130 pi2
->pPortName
= (LPWSTR
)ptr
;
4137 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
4138 if(space
&& size
<= left
) {
4139 pi2
->pDriverName
= (LPWSTR
)ptr
;
4146 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4147 if(space
&& size
<= left
) {
4148 pi2
->pComment
= (LPWSTR
)ptr
;
4155 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
4156 if(space
&& size
<= left
) {
4157 pi2
->pLocation
= (LPWSTR
)ptr
;
4164 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
4165 if(space
&& size
<= left
) {
4166 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4175 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
4176 if(space
&& size
<= left
) {
4177 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4184 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
4185 if(space
&& size
<= left
) {
4186 pi2
->pSepFile
= (LPWSTR
)ptr
;
4193 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
4194 if(space
&& size
<= left
) {
4195 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
4202 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
4203 if(space
&& size
<= left
) {
4204 pi2
->pDatatype
= (LPWSTR
)ptr
;
4211 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
4212 if(space
&& size
<= left
) {
4213 pi2
->pParameters
= (LPWSTR
)ptr
;
4221 pi2
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4222 pi2
->Priority
= get_dword_from_reg( hkeyPrinter
, PriorityW
);
4223 pi2
->DefaultPriority
= get_dword_from_reg( hkeyPrinter
, Default_PriorityW
);
4224 pi2
->StartTime
= get_dword_from_reg( hkeyPrinter
, StartTimeW
);
4225 pi2
->UntilTime
= get_dword_from_reg( hkeyPrinter
, UntilTimeW
);
4228 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
4229 memset(pi2
, 0, sizeof(*pi2
));
4234 /*********************************************************************
4235 * WINSPOOL_GetPrinter_4
4237 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4239 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
4240 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4242 DWORD size
, left
= cbBuf
;
4243 BOOL space
= (cbBuf
> 0);
4248 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4249 if(space
&& size
<= left
) {
4250 pi4
->pPrinterName
= (LPWSTR
)ptr
;
4258 pi4
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4261 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
4262 memset(pi4
, 0, sizeof(*pi4
));
4267 /*********************************************************************
4268 * WINSPOOL_GetPrinter_5
4270 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4272 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
4273 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4275 DWORD size
, left
= cbBuf
;
4276 BOOL space
= (cbBuf
> 0);
4281 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4282 if(space
&& size
<= left
) {
4283 pi5
->pPrinterName
= (LPWSTR
)ptr
;
4290 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4291 if(space
&& size
<= left
) {
4292 pi5
->pPortName
= (LPWSTR
)ptr
;
4300 pi5
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4301 pi5
->DeviceNotSelectedTimeout
= get_dword_from_reg( hkeyPrinter
, dnsTimeoutW
);
4302 pi5
->TransmissionRetryTimeout
= get_dword_from_reg( hkeyPrinter
, txTimeoutW
);
4305 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
4306 memset(pi5
, 0, sizeof(*pi5
));
4311 /*********************************************************************
4312 * WINSPOOL_GetPrinter_7
4314 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4316 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
4317 DWORD cbBuf
, LPDWORD pcbNeeded
)
4319 DWORD size
, left
= cbBuf
;
4320 BOOL space
= (cbBuf
> 0);
4325 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
4328 size
= sizeof(pi7
->pszObjectGUID
);
4330 if (space
&& size
<= left
) {
4331 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
4338 /* We do not have a Directory Service */
4339 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
4342 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
4343 memset(pi7
, 0, sizeof(*pi7
));
4348 /*********************************************************************
4349 * WINSPOOL_GetPrinter_9
4351 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4353 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
4354 DWORD cbBuf
, LPDWORD pcbNeeded
)
4357 BOOL space
= (cbBuf
> 0);
4361 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
4362 if(space
&& size
<= cbBuf
) {
4363 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4370 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
4371 if(space
&& size
<= cbBuf
) {
4372 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4378 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
4379 memset(pi9
, 0, sizeof(*pi9
));
4384 /*****************************************************************************
4385 * GetPrinterW [WINSPOOL.@]
4387 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4388 DWORD cbBuf
, LPDWORD pcbNeeded
)
4390 DWORD size
, needed
= 0, err
;
4395 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4397 err
= WINSPOOL_GetOpenedPrinterRegKey( hPrinter
, &hkeyPrinter
);
4400 SetLastError( err
);
4407 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4409 size
= sizeof(PRINTER_INFO_2W
);
4411 ptr
= pPrinter
+ size
;
4413 memset(pPrinter
, 0, size
);
4418 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
4425 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4427 size
= sizeof(PRINTER_INFO_4W
);
4429 ptr
= pPrinter
+ size
;
4431 memset(pPrinter
, 0, size
);
4436 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
4444 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4446 size
= sizeof(PRINTER_INFO_5W
);
4448 ptr
= pPrinter
+ size
;
4450 memset(pPrinter
, 0, size
);
4456 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
4464 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4466 size
= sizeof(PRINTER_INFO_6
);
4467 if (size
<= cbBuf
) {
4468 /* FIXME: We do not update the status yet */
4469 pi6
->dwStatus
= get_dword_from_reg( hkeyPrinter
, StatusW
);
4481 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4483 size
= sizeof(PRINTER_INFO_7W
);
4484 if (size
<= cbBuf
) {
4485 ptr
= pPrinter
+ size
;
4487 memset(pPrinter
, 0, size
);
4493 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
4500 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4501 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4505 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4507 size
= sizeof(PRINTER_INFO_9W
);
4509 ptr
= pPrinter
+ size
;
4511 memset(pPrinter
, 0, size
);
4517 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
4524 FIXME("Unimplemented level %d\n", Level
);
4525 SetLastError(ERROR_INVALID_LEVEL
);
4526 RegCloseKey(hkeyPrinter
);
4530 RegCloseKey(hkeyPrinter
);
4532 TRACE("returning %d needed = %d\n", ret
, needed
);
4533 if(pcbNeeded
) *pcbNeeded
= needed
;
4535 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4539 /*****************************************************************************
4540 * GetPrinterA [WINSPOOL.@]
4542 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4543 DWORD cbBuf
, LPDWORD pcbNeeded
)
4549 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4551 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
4553 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
4554 HeapFree(GetProcessHeap(), 0, buf
);
4559 /*****************************************************************************
4560 * WINSPOOL_EnumPrintersW
4562 * Implementation of EnumPrintersW
4564 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
4565 DWORD dwLevel
, LPBYTE lpbPrinters
,
4566 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4567 LPDWORD lpdwReturned
)
4570 HKEY hkeyPrinters
, hkeyPrinter
;
4571 WCHAR PrinterName
[255];
4572 DWORD needed
= 0, number
= 0;
4573 DWORD used
, i
, left
;
4577 memset(lpbPrinters
, 0, cbBuf
);
4583 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4584 if(dwType
== PRINTER_ENUM_DEFAULT
)
4587 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4588 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4589 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4591 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4597 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4598 FIXME("dwType = %08x\n", dwType
);
4599 SetLastError(ERROR_INVALID_FLAGS
);
4603 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4605 ERR("Can't create Printers key\n");
4609 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4610 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4611 RegCloseKey(hkeyPrinters
);
4612 ERR("Can't query Printers key\n");
4615 TRACE("Found %d printers\n", number
);
4619 used
= number
* sizeof(PRINTER_INFO_1W
);
4622 used
= number
* sizeof(PRINTER_INFO_2W
);
4625 used
= number
* sizeof(PRINTER_INFO_4W
);
4628 used
= number
* sizeof(PRINTER_INFO_5W
);
4632 SetLastError(ERROR_INVALID_LEVEL
);
4633 RegCloseKey(hkeyPrinters
);
4636 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4638 for(i
= 0; i
< number
; i
++) {
4639 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4641 ERR("Can't enum key number %d\n", i
);
4642 RegCloseKey(hkeyPrinters
);
4645 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4646 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4648 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4649 RegCloseKey(hkeyPrinters
);
4654 buf
= lpbPrinters
+ used
;
4655 left
= cbBuf
- used
;
4663 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4666 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4669 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4672 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4675 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4678 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4681 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4684 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4687 ERR("Shouldn't be here!\n");
4688 RegCloseKey(hkeyPrinter
);
4689 RegCloseKey(hkeyPrinters
);
4692 RegCloseKey(hkeyPrinter
);
4694 RegCloseKey(hkeyPrinters
);
4701 memset(lpbPrinters
, 0, cbBuf
);
4702 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4706 *lpdwReturned
= number
;
4707 SetLastError(ERROR_SUCCESS
);
4712 /******************************************************************
4713 * EnumPrintersW [WINSPOOL.@]
4715 * Enumerates the available printers, print servers and print
4716 * providers, depending on the specified flags, name and level.
4720 * If level is set to 1:
4721 * Returns an array of PRINTER_INFO_1 data structures in the
4722 * lpbPrinters buffer.
4724 * If level is set to 2:
4725 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4726 * Returns an array of PRINTER_INFO_2 data structures in the
4727 * lpbPrinters buffer. Note that according to MSDN also an
4728 * OpenPrinter should be performed on every remote printer.
4730 * If level is set to 4 (officially WinNT only):
4731 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4732 * Fast: Only the registry is queried to retrieve printer names,
4733 * no connection to the driver is made.
4734 * Returns an array of PRINTER_INFO_4 data structures in the
4735 * lpbPrinters buffer.
4737 * If level is set to 5 (officially WinNT4/Win9x only):
4738 * Fast: Only the registry is queried to retrieve printer names,
4739 * no connection to the driver is made.
4740 * Returns an array of PRINTER_INFO_5 data structures in the
4741 * lpbPrinters buffer.
4743 * If level set to 3 or 6+:
4744 * returns zero (failure!)
4746 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4750 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4751 * - Only levels 2, 4 and 5 are implemented at the moment.
4752 * - 16-bit printer drivers are not enumerated.
4753 * - Returned amount of bytes used/needed does not match the real Windoze
4754 * implementation (as in this implementation, all strings are part
4755 * of the buffer, whereas Win32 keeps them somewhere else)
4756 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4759 * - In a regular Wine installation, no registry settings for printers
4760 * exist, which makes this function return an empty list.
4762 BOOL WINAPI
EnumPrintersW(
4763 DWORD dwType
, /* [in] Types of print objects to enumerate */
4764 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4765 DWORD dwLevel
, /* [in] type of printer info structure */
4766 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4767 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4768 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4769 LPDWORD lpdwReturned
/* [out] number of entries returned */
4772 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4773 lpdwNeeded
, lpdwReturned
);
4776 /******************************************************************
4777 * EnumPrintersA [WINSPOOL.@]
4782 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4783 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4786 UNICODE_STRING pNameU
;
4790 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4791 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4793 pNameW
= asciitounicode(&pNameU
, pName
);
4795 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4796 MS Office need this */
4797 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4799 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4801 RtlFreeUnicodeString(&pNameU
);
4803 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4805 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4809 /*****************************************************************************
4810 * WINSPOOL_GetDriverInfoFromReg [internal]
4812 * Enters the information from the registry into the DRIVER_INFO struct
4815 * zero if the printer driver does not exist in the registry
4816 * (only if Level > 1) otherwise nonzero
4818 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4821 const printenv_t
* env
,
4823 LPBYTE ptr
, /* DRIVER_INFO */
4824 LPBYTE pDriverStrings
, /* strings buffer */
4825 DWORD cbBuf
, /* size of string buffer */
4826 LPDWORD pcbNeeded
) /* space needed for str. */
4830 WCHAR driverdir
[MAX_PATH
];
4832 LPBYTE strPtr
= pDriverStrings
;
4833 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4835 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4836 debugstr_w(DriverName
), env
,
4837 Level
, di
, pDriverStrings
, cbBuf
);
4839 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4841 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4842 if (*pcbNeeded
<= cbBuf
)
4843 strcpyW((LPWSTR
)strPtr
, DriverName
);
4845 /* pName for level 1 has a different offset! */
4847 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4851 /* .cVersion and .pName for level > 1 */
4853 di
->cVersion
= env
->driverversion
;
4854 di
->pName
= (LPWSTR
) strPtr
;
4855 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4858 /* Reserve Space for the largest subdir and a Backslash*/
4859 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4860 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4861 /* Should never Fail */
4864 lstrcatW(driverdir
, env
->versionsubdir
);
4865 lstrcatW(driverdir
, backslashW
);
4867 /* dirlen must not include the terminating zero */
4868 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4870 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4871 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4872 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4877 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4880 if (*pcbNeeded
<= cbBuf
) {
4881 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4882 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4883 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4886 /* .pDriverPath is the Graphics rendering engine.
4887 The full Path is required to avoid a crash in some apps */
4888 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4890 if (*pcbNeeded
<= cbBuf
)
4891 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4893 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4894 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4897 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4898 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4900 if (*pcbNeeded
<= cbBuf
)
4901 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4903 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4904 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4907 /* .pConfigFile is the Driver user Interface */
4908 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4910 if (*pcbNeeded
<= cbBuf
)
4911 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4913 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4914 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4918 RegCloseKey(hkeyDriver
);
4919 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4924 RegCloseKey(hkeyDriver
);
4925 FIXME("level 5: incomplete\n");
4930 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4932 if (*pcbNeeded
<= cbBuf
)
4933 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4935 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4936 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4939 /* .pDependentFiles */
4940 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4942 if (*pcbNeeded
<= cbBuf
)
4943 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4945 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4946 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4948 else if (GetVersion() & 0x80000000) {
4949 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4950 size
= 2 * sizeof(WCHAR
);
4952 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4954 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4955 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4958 /* .pMonitorName is the optional Language Monitor */
4959 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4961 if (*pcbNeeded
<= cbBuf
)
4962 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4964 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4965 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4968 /* .pDefaultDataType */
4969 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
4971 if(*pcbNeeded
<= cbBuf
)
4972 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
4974 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4975 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4979 RegCloseKey(hkeyDriver
);
4980 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4984 /* .pszzPreviousNames */
4985 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
4987 if(*pcbNeeded
<= cbBuf
)
4988 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
4990 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4991 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4995 RegCloseKey(hkeyDriver
);
4996 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5000 /* support is missing, but not important enough for a FIXME */
5001 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
5004 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
5006 if(*pcbNeeded
<= cbBuf
)
5007 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
5009 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
5010 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5014 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
5016 if(*pcbNeeded
<= cbBuf
)
5017 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
5019 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
5020 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5023 /* .pszHardwareID */
5024 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
5026 if(*pcbNeeded
<= cbBuf
)
5027 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
5029 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
5030 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5034 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
5036 if(*pcbNeeded
<= cbBuf
)
5037 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
5039 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
5040 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5044 RegCloseKey(hkeyDriver
);
5048 /* support is missing, but not important enough for a FIXME */
5049 TRACE("level 8: incomplete\n");
5051 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5052 RegCloseKey(hkeyDriver
);
5056 /*****************************************************************************
5057 * GetPrinterDriverW [WINSPOOL.@]
5059 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
5060 DWORD Level
, LPBYTE pDriverInfo
,
5061 DWORD cbBuf
, LPDWORD pcbNeeded
)
5064 WCHAR DriverName
[100];
5065 DWORD ret
, type
, size
, needed
= 0;
5067 HKEY hkeyPrinter
, hkeyDrivers
;
5068 const printenv_t
* env
;
5070 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
5071 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
5074 ZeroMemory(pDriverInfo
, cbBuf
);
5076 if (!(name
= get_opened_printer_name(hPrinter
))) {
5077 SetLastError(ERROR_INVALID_HANDLE
);
5081 if (Level
< 1 || Level
== 7 || Level
> 8) {
5082 SetLastError(ERROR_INVALID_LEVEL
);
5086 env
= validate_envW(pEnvironment
);
5087 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5089 ret
= open_printer_reg_key( name
, &hkeyPrinter
);
5092 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name
) );
5093 SetLastError( ret
);
5097 size
= sizeof(DriverName
);
5099 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
5100 (LPBYTE
)DriverName
, &size
);
5101 RegCloseKey(hkeyPrinter
);
5102 if(ret
!= ERROR_SUCCESS
) {
5103 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
5107 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5109 ERR("Can't create Drivers key\n");
5113 size
= di_sizeof
[Level
];
5114 if ((size
<= cbBuf
) && pDriverInfo
)
5115 ptr
= pDriverInfo
+ size
;
5117 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
5118 env
, Level
, pDriverInfo
, ptr
,
5119 (cbBuf
< size
) ? 0 : cbBuf
- size
,
5121 RegCloseKey(hkeyDrivers
);
5125 RegCloseKey(hkeyDrivers
);
5127 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
5128 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
5129 if(cbBuf
>= size
+ needed
) return TRUE
;
5130 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5134 /*****************************************************************************
5135 * GetPrinterDriverA [WINSPOOL.@]
5137 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
5138 DWORD Level
, LPBYTE pDriverInfo
,
5139 DWORD cbBuf
, LPDWORD pcbNeeded
)
5142 UNICODE_STRING pEnvW
;
5148 ZeroMemory(pDriverInfo
, cbBuf
);
5149 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5152 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
5153 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
5156 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
5158 HeapFree(GetProcessHeap(), 0, buf
);
5160 RtlFreeUnicodeString(&pEnvW
);
5164 /*****************************************************************************
5165 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5167 * Return the PATH for the Printer-Drivers (UNICODE)
5170 * pName [I] Servername (NT only) or NULL (local Computer)
5171 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5172 * Level [I] Structure-Level (must be 1)
5173 * pDriverDirectory [O] PTR to Buffer that receives the Result
5174 * cbBuf [I] Size of Buffer at pDriverDirectory
5175 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5176 * required for pDriverDirectory
5179 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5180 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5181 * if cbBuf is too small
5183 * Native Values returned in pDriverDirectory on Success:
5184 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5185 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5186 *| win9x(Windows 4.0): "%winsysdir%"
5188 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5191 *- Only NULL or "" is supported for pName
5194 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
5195 DWORD Level
, LPBYTE pDriverDirectory
,
5196 DWORD cbBuf
, LPDWORD pcbNeeded
)
5198 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
5199 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5201 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5204 /* (Level != 1) is ignored in win9x */
5205 SetLastError(ERROR_INVALID_LEVEL
);
5208 if (pcbNeeded
== NULL
) {
5209 /* (pcbNeeded == NULL) is ignored in win9x */
5210 SetLastError(RPC_X_NULL_REF_POINTER
);
5214 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
5215 pDriverDirectory
, cbBuf
, pcbNeeded
);
5220 /*****************************************************************************
5221 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5223 * Return the PATH for the Printer-Drivers (ANSI)
5225 * See GetPrinterDriverDirectoryW.
5228 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5231 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
5232 DWORD Level
, LPBYTE pDriverDirectory
,
5233 DWORD cbBuf
, LPDWORD pcbNeeded
)
5235 UNICODE_STRING nameW
, environmentW
;
5238 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
5239 WCHAR
*driverDirectoryW
= NULL
;
5241 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
5242 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5244 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
5246 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
5247 else nameW
.Buffer
= NULL
;
5248 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
5249 else environmentW
.Buffer
= NULL
;
5251 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
5252 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
5255 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
5256 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
5258 *pcbNeeded
= needed
;
5259 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
5261 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
5263 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
5265 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
5266 RtlFreeUnicodeString(&environmentW
);
5267 RtlFreeUnicodeString(&nameW
);
5272 /*****************************************************************************
5273 * AddPrinterDriverA [WINSPOOL.@]
5275 * See AddPrinterDriverW.
5278 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5280 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
5281 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5284 /******************************************************************************
5285 * AddPrinterDriverW (WINSPOOL.@)
5287 * Install a Printer Driver
5290 * pName [I] Servername or NULL (local Computer)
5291 * level [I] Level for the supplied DRIVER_INFO_*W struct
5292 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5299 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5301 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
5302 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5305 /*****************************************************************************
5306 * AddPrintProcessorA [WINSPOOL.@]
5308 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
5309 LPSTR pPrintProcessorName
)
5311 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5312 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
5316 /*****************************************************************************
5317 * AddPrintProcessorW [WINSPOOL.@]
5319 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5320 LPWSTR pPrintProcessorName
)
5322 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5323 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5327 /*****************************************************************************
5328 * AddPrintProvidorA [WINSPOOL.@]
5330 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5332 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5336 /*****************************************************************************
5337 * AddPrintProvidorW [WINSPOOL.@]
5339 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5341 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5345 /*****************************************************************************
5346 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5348 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5349 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5351 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5352 pDevModeOutput
, pDevModeInput
);
5356 /*****************************************************************************
5357 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5359 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5360 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5362 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5363 pDevModeOutput
, pDevModeInput
);
5367 /*****************************************************************************
5368 * PrinterProperties [WINSPOOL.@]
5370 * Displays a dialog to set the properties of the printer.
5373 * nonzero on success or zero on failure
5376 * implemented as stub only
5378 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5379 HANDLE hPrinter
/* [in] handle to printer object */
5381 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5382 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5386 /*****************************************************************************
5387 * EnumJobsA [WINSPOOL.@]
5390 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5391 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5394 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5395 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5397 if(pcbNeeded
) *pcbNeeded
= 0;
5398 if(pcReturned
) *pcReturned
= 0;
5403 /*****************************************************************************
5404 * EnumJobsW [WINSPOOL.@]
5407 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5408 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5411 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5412 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5414 if(pcbNeeded
) *pcbNeeded
= 0;
5415 if(pcReturned
) *pcReturned
= 0;
5419 /*****************************************************************************
5420 * WINSPOOL_EnumPrinterDrivers [internal]
5422 * Delivers information about all printer drivers installed on the
5423 * localhost or a given server
5426 * nonzero on success or zero on failure. If the buffer for the returned
5427 * information is too small the function will return an error
5430 * - only implemented for localhost, foreign hosts will return an error
5432 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5433 DWORD Level
, LPBYTE pDriverInfo
,
5435 DWORD cbBuf
, LPDWORD pcbNeeded
,
5436 LPDWORD pcFound
, DWORD data_offset
)
5440 const printenv_t
* env
;
5442 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5443 debugstr_w(pName
), debugstr_w(pEnvironment
),
5444 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
5446 env
= validate_envW(pEnvironment
);
5447 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5451 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5453 ERR("Can't open Drivers key\n");
5457 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
5458 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5459 RegCloseKey(hkeyDrivers
);
5460 ERR("Can't query Drivers key\n");
5463 TRACE("Found %d Drivers\n", *pcFound
);
5465 /* get size of single struct
5466 * unicode and ascii structure have the same size
5468 size
= di_sizeof
[Level
];
5470 if (data_offset
== 0)
5471 data_offset
= size
* (*pcFound
);
5472 *pcbNeeded
= data_offset
;
5474 for( i
= 0; i
< *pcFound
; i
++) {
5475 WCHAR DriverNameW
[255];
5476 PBYTE table_ptr
= NULL
;
5477 PBYTE data_ptr
= NULL
;
5480 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
5482 ERR("Can't enum key number %d\n", i
);
5483 RegCloseKey(hkeyDrivers
);
5487 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
5488 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
5489 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
5490 data_ptr
= pDriverInfo
+ *pcbNeeded
;
5492 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5493 env
, Level
, table_ptr
, data_ptr
,
5494 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5496 RegCloseKey(hkeyDrivers
);
5500 *pcbNeeded
+= needed
;
5503 RegCloseKey(hkeyDrivers
);
5505 if(cbBuf
< *pcbNeeded
){
5506 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5513 /*****************************************************************************
5514 * EnumPrinterDriversW [WINSPOOL.@]
5516 * see function EnumPrinterDrivers for RETURNS, BUGS
5518 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5519 LPBYTE pDriverInfo
, DWORD cbBuf
,
5520 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5522 static const WCHAR allW
[] = {'a','l','l',0};
5526 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
5528 SetLastError(RPC_X_NULL_REF_POINTER
);
5532 /* check for local drivers */
5533 if((pName
) && (pName
[0])) {
5534 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5535 SetLastError(ERROR_ACCESS_DENIED
);
5539 /* check input parameter */
5540 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5541 SetLastError(ERROR_INVALID_LEVEL
);
5545 if(pDriverInfo
&& cbBuf
> 0)
5546 memset( pDriverInfo
, 0, cbBuf
);
5548 /* Exception: pull all printers */
5549 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
5551 DWORD i
, needed
, bufsize
= cbBuf
;
5552 DWORD total_needed
= 0;
5553 DWORD total_found
= 0;
5556 /* Precompute the overall total; we need this to know
5557 where pointers end and data begins (i.e. data_offset) */
5558 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5561 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5562 NULL
, 0, 0, &needed
, &found
, 0);
5563 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5564 total_needed
+= needed
;
5565 total_found
+= found
;
5568 data_offset
= di_sizeof
[Level
] * total_found
;
5573 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5576 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5577 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
5578 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5580 *pcReturned
+= found
;
5581 *pcbNeeded
= needed
;
5582 data_offset
= needed
;
5583 total_found
+= found
;
5588 /* Normal behavior */
5589 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5590 0, cbBuf
, pcbNeeded
, &found
, 0);
5592 *pcReturned
= found
;
5597 /*****************************************************************************
5598 * EnumPrinterDriversA [WINSPOOL.@]
5600 * see function EnumPrinterDrivers for RETURNS, BUGS
5602 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5603 LPBYTE pDriverInfo
, DWORD cbBuf
,
5604 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5607 UNICODE_STRING pNameW
, pEnvironmentW
;
5608 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5612 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5614 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5615 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5617 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5618 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5620 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5622 HeapFree(GetProcessHeap(), 0, buf
);
5624 RtlFreeUnicodeString(&pNameW
);
5625 RtlFreeUnicodeString(&pEnvironmentW
);
5630 /******************************************************************************
5631 * EnumPortsA (WINSPOOL.@)
5636 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5637 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5640 LPBYTE bufferW
= NULL
;
5641 LPWSTR nameW
= NULL
;
5643 DWORD numentries
= 0;
5646 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5647 cbBuf
, pcbNeeded
, pcReturned
);
5649 /* convert servername to unicode */
5651 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5652 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5653 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5655 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5656 needed
= cbBuf
* sizeof(WCHAR
);
5657 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5658 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5660 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5661 if (pcbNeeded
) needed
= *pcbNeeded
;
5662 /* HeapReAlloc return NULL, when bufferW was NULL */
5663 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5664 HeapAlloc(GetProcessHeap(), 0, needed
);
5666 /* Try again with the large Buffer */
5667 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5669 needed
= pcbNeeded
? *pcbNeeded
: 0;
5670 numentries
= pcReturned
? *pcReturned
: 0;
5673 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5674 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5677 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5678 DWORD entrysize
= 0;
5681 LPPORT_INFO_2W pi2w
;
5682 LPPORT_INFO_2A pi2a
;
5685 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5687 /* First pass: calculate the size for all Entries */
5688 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5689 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5691 while (index
< numentries
) {
5693 needed
+= entrysize
; /* PORT_INFO_?A */
5694 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5696 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5697 NULL
, 0, NULL
, NULL
);
5699 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5700 NULL
, 0, NULL
, NULL
);
5701 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5702 NULL
, 0, NULL
, NULL
);
5704 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5705 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5706 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5709 /* check for errors and quit on failure */
5710 if (cbBuf
< needed
) {
5711 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5715 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5716 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5717 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5718 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5719 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5721 /* Second Pass: Fill the User Buffer (if we have one) */
5722 while ((index
< numentries
) && pPorts
) {
5724 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5725 pi2a
->pPortName
= ptr
;
5726 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5727 ptr
, cbBuf
, NULL
, NULL
);
5731 pi2a
->pMonitorName
= ptr
;
5732 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5733 ptr
, cbBuf
, NULL
, NULL
);
5737 pi2a
->pDescription
= ptr
;
5738 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5739 ptr
, cbBuf
, NULL
, NULL
);
5743 pi2a
->fPortType
= pi2w
->fPortType
;
5744 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5747 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5748 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5749 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5754 if (pcbNeeded
) *pcbNeeded
= needed
;
5755 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5757 HeapFree(GetProcessHeap(), 0, nameW
);
5758 HeapFree(GetProcessHeap(), 0, bufferW
);
5760 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5761 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5767 /******************************************************************************
5768 * EnumPortsW (WINSPOOL.@)
5770 * Enumerate available Ports
5773 * pName [I] Servername or NULL (local Computer)
5774 * Level [I] Structure-Level (1 or 2)
5775 * pPorts [O] PTR to Buffer that receives the Result
5776 * cbBuf [I] Size of Buffer at pPorts
5777 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5778 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5782 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5785 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5788 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5789 cbBuf
, pcbNeeded
, pcReturned
);
5791 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5793 /* Level is not checked in win9x */
5794 if (!Level
|| (Level
> 2)) {
5795 WARN("level (%d) is ignored in win9x\n", Level
);
5796 SetLastError(ERROR_INVALID_LEVEL
);
5799 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5800 SetLastError(RPC_X_NULL_REF_POINTER
);
5804 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5807 /******************************************************************************
5808 * GetDefaultPrinterW (WINSPOOL.@)
5811 * This function must read the value from data 'device' of key
5812 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5814 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5818 WCHAR
*buffer
, *ptr
;
5822 SetLastError(ERROR_INVALID_PARAMETER
);
5826 /* make the buffer big enough for the stuff from the profile/registry,
5827 * the content must fit into the local buffer to compute the correct
5828 * size even if the extern buffer is too small or not given.
5829 * (20 for ,driver,port) */
5831 len
= max(100, (insize
+ 20));
5832 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5834 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5836 SetLastError (ERROR_FILE_NOT_FOUND
);
5840 TRACE("%s\n", debugstr_w(buffer
));
5842 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5844 SetLastError(ERROR_INVALID_NAME
);
5850 *namesize
= strlenW(buffer
) + 1;
5851 if(!name
|| (*namesize
> insize
))
5853 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5857 strcpyW(name
, buffer
);
5860 HeapFree( GetProcessHeap(), 0, buffer
);
5865 /******************************************************************************
5866 * GetDefaultPrinterA (WINSPOOL.@)
5868 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5872 WCHAR
*bufferW
= NULL
;
5876 SetLastError(ERROR_INVALID_PARAMETER
);
5880 if(name
&& *namesize
) {
5882 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5885 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5890 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5894 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5897 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5900 HeapFree( GetProcessHeap(), 0, bufferW
);
5905 /******************************************************************************
5906 * SetDefaultPrinterW (WINSPOOL.204)
5908 * Set the Name of the Default Printer
5911 * pszPrinter [I] Name of the Printer or NULL
5918 * When the Parameter is NULL or points to an Empty String and
5919 * a Default Printer was already present, then this Function changes nothing.
5920 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5921 * the First enumerated local Printer is used.
5924 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5926 WCHAR default_printer
[MAX_PATH
];
5927 LPWSTR buffer
= NULL
;
5933 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5934 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5936 default_printer
[0] = '\0';
5937 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5939 /* if we have a default Printer, do nothing. */
5940 if (GetDefaultPrinterW(default_printer
, &size
))
5944 /* we have no default Printer: search local Printers and use the first */
5945 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
5947 default_printer
[0] = '\0';
5948 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5949 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
5951 pszPrinter
= default_printer
;
5952 TRACE("using %s\n", debugstr_w(pszPrinter
));
5957 if (pszPrinter
== NULL
) {
5958 TRACE("no local printer found\n");
5959 SetLastError(ERROR_FILE_NOT_FOUND
);
5964 /* "pszPrinter" is never empty or NULL here. */
5965 namelen
= lstrlenW(pszPrinter
);
5966 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5967 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5969 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
5970 HeapFree(GetProcessHeap(), 0, buffer
);
5971 SetLastError(ERROR_FILE_NOT_FOUND
);
5975 /* read the devices entry for the printer (driver,port) to build the string for the
5976 default device entry (printer,driver,port) */
5977 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
5978 buffer
[namelen
] = ',';
5979 namelen
++; /* move index to the start of the driver */
5981 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
5982 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
5984 TRACE("set device to %s\n", debugstr_w(buffer
));
5986 if (!WriteProfileStringW(windowsW
, deviceW
, buffer
)) {
5987 TRACE("failed to set the device entry: %d\n", GetLastError());
5988 lres
= ERROR_INVALID_PRINTER_NAME
;
5991 /* remove the next section, when INIFileMapping is implemented */
5994 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
)) {
5995 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (LPBYTE
)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
6002 if (lres
!= ERROR_FILE_NOT_FOUND
)
6003 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
6005 SetLastError(ERROR_INVALID_PRINTER_NAME
);
6009 HeapFree(GetProcessHeap(), 0, buffer
);
6010 return (lres
== ERROR_SUCCESS
);
6013 /******************************************************************************
6014 * SetDefaultPrinterA (WINSPOOL.202)
6016 * See SetDefaultPrinterW.
6019 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
6021 LPWSTR bufferW
= NULL
;
6024 TRACE("(%s)\n", debugstr_a(pszPrinter
));
6026 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
6027 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6028 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
6030 res
= SetDefaultPrinterW(bufferW
);
6031 HeapFree(GetProcessHeap(), 0, bufferW
);
6035 /******************************************************************************
6036 * SetPrinterDataExA (WINSPOOL.@)
6038 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6039 LPCSTR pValueName
, DWORD Type
,
6040 LPBYTE pData
, DWORD cbData
)
6042 HKEY hkeyPrinter
, hkeySubkey
;
6045 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
6046 debugstr_a(pValueName
), Type
, pData
, cbData
);
6048 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6052 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6054 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
6055 RegCloseKey(hkeyPrinter
);
6058 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6059 RegCloseKey(hkeySubkey
);
6060 RegCloseKey(hkeyPrinter
);
6064 /******************************************************************************
6065 * SetPrinterDataExW (WINSPOOL.@)
6067 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6068 LPCWSTR pValueName
, DWORD Type
,
6069 LPBYTE pData
, DWORD cbData
)
6071 HKEY hkeyPrinter
, hkeySubkey
;
6074 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
6075 debugstr_w(pValueName
), Type
, pData
, cbData
);
6077 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6081 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6083 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
6084 RegCloseKey(hkeyPrinter
);
6087 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6088 RegCloseKey(hkeySubkey
);
6089 RegCloseKey(hkeyPrinter
);
6093 /******************************************************************************
6094 * SetPrinterDataA (WINSPOOL.@)
6096 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
6097 LPBYTE pData
, DWORD cbData
)
6099 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
6103 /******************************************************************************
6104 * SetPrinterDataW (WINSPOOL.@)
6106 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
6107 LPBYTE pData
, DWORD cbData
)
6109 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
6113 /******************************************************************************
6114 * GetPrinterDataExA (WINSPOOL.@)
6116 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6117 LPCSTR pValueName
, LPDWORD pType
,
6118 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6120 opened_printer_t
*printer
;
6121 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6124 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
6125 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6127 printer
= get_opened_printer(hPrinter
);
6128 if(!printer
) return ERROR_INVALID_HANDLE
;
6130 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6131 if (ret
) return ret
;
6133 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6135 if (printer
->name
) {
6137 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6139 RegCloseKey(hkeyPrinters
);
6142 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6143 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
6144 RegCloseKey(hkeyPrinter
);
6145 RegCloseKey(hkeyPrinters
);
6150 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6151 0, pType
, pData
, pcbNeeded
);
6153 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6155 RegCloseKey(hkeySubkey
);
6156 RegCloseKey(hkeyPrinter
);
6157 RegCloseKey(hkeyPrinters
);
6159 TRACE("--> %d\n", ret
);
6163 /******************************************************************************
6164 * GetPrinterDataExW (WINSPOOL.@)
6166 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6167 LPCWSTR pValueName
, LPDWORD pType
,
6168 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6170 opened_printer_t
*printer
;
6171 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6174 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
6175 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6177 printer
= get_opened_printer(hPrinter
);
6178 if(!printer
) return ERROR_INVALID_HANDLE
;
6180 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6181 if (ret
) return ret
;
6183 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6185 if (printer
->name
) {
6187 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6189 RegCloseKey(hkeyPrinters
);
6192 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6193 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
6194 RegCloseKey(hkeyPrinter
);
6195 RegCloseKey(hkeyPrinters
);
6200 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6201 0, pType
, pData
, pcbNeeded
);
6203 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6205 RegCloseKey(hkeySubkey
);
6206 RegCloseKey(hkeyPrinter
);
6207 RegCloseKey(hkeyPrinters
);
6209 TRACE("--> %d\n", ret
);
6213 /******************************************************************************
6214 * GetPrinterDataA (WINSPOOL.@)
6216 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
6217 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6219 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
6220 pData
, nSize
, pcbNeeded
);
6223 /******************************************************************************
6224 * GetPrinterDataW (WINSPOOL.@)
6226 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
6227 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6229 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
6230 pData
, nSize
, pcbNeeded
);
6233 /*******************************************************************************
6234 * EnumPrinterDataExW [WINSPOOL.@]
6236 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6237 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6238 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6240 HKEY hkPrinter
, hkSubKey
;
6241 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
6242 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
6247 PPRINTER_ENUM_VALUESW ppev
;
6249 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
6251 if (pKeyName
== NULL
|| *pKeyName
== 0)
6252 return ERROR_INVALID_PARAMETER
;
6254 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
6255 if (ret
!= ERROR_SUCCESS
)
6257 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6262 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
6263 if (ret
!= ERROR_SUCCESS
)
6265 r
= RegCloseKey (hkPrinter
);
6266 if (r
!= ERROR_SUCCESS
)
6267 WARN ("RegCloseKey returned %i\n", r
);
6268 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
6269 debugstr_w (pKeyName
), ret
);
6273 ret
= RegCloseKey (hkPrinter
);
6274 if (ret
!= ERROR_SUCCESS
)
6276 ERR ("RegCloseKey returned %i\n", ret
);
6277 r
= RegCloseKey (hkSubKey
);
6278 if (r
!= ERROR_SUCCESS
)
6279 WARN ("RegCloseKey returned %i\n", r
);
6283 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
6284 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
6285 if (ret
!= ERROR_SUCCESS
)
6287 r
= RegCloseKey (hkSubKey
);
6288 if (r
!= ERROR_SUCCESS
)
6289 WARN ("RegCloseKey returned %i\n", r
);
6290 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
6294 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6295 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
6297 if (cValues
== 0) /* empty key */
6299 r
= RegCloseKey (hkSubKey
);
6300 if (r
!= ERROR_SUCCESS
)
6301 WARN ("RegCloseKey returned %i\n", r
);
6302 *pcbEnumValues
= *pnEnumValues
= 0;
6303 return ERROR_SUCCESS
;
6306 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
6308 hHeap
= GetProcessHeap ();
6311 ERR ("GetProcessHeap failed\n");
6312 r
= RegCloseKey (hkSubKey
);
6313 if (r
!= ERROR_SUCCESS
)
6314 WARN ("RegCloseKey returned %i\n", r
);
6315 return ERROR_OUTOFMEMORY
;
6318 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
6319 if (lpValueName
== NULL
)
6321 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
6322 r
= RegCloseKey (hkSubKey
);
6323 if (r
!= ERROR_SUCCESS
)
6324 WARN ("RegCloseKey returned %i\n", r
);
6325 return ERROR_OUTOFMEMORY
;
6328 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
6329 if (lpValue
== NULL
)
6331 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
6332 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6333 WARN ("HeapFree failed with code %i\n", GetLastError ());
6334 r
= RegCloseKey (hkSubKey
);
6335 if (r
!= ERROR_SUCCESS
)
6336 WARN ("RegCloseKey returned %i\n", r
);
6337 return ERROR_OUTOFMEMORY
;
6340 TRACE ("pass 1: calculating buffer required for all names and values\n");
6342 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6344 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
6346 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6348 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6349 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6350 NULL
, NULL
, lpValue
, &cbValueLen
);
6351 if (ret
!= ERROR_SUCCESS
)
6353 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6354 WARN ("HeapFree failed with code %i\n", GetLastError ());
6355 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6356 WARN ("HeapFree failed with code %i\n", GetLastError ());
6357 r
= RegCloseKey (hkSubKey
);
6358 if (r
!= ERROR_SUCCESS
)
6359 WARN ("RegCloseKey returned %i\n", r
);
6360 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6364 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6365 debugstr_w (lpValueName
), dwIndex
,
6366 cbValueNameLen
+ 1, cbValueLen
);
6368 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6369 cbBufSize
+= cbValueLen
;
6372 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
6374 *pcbEnumValues
= cbBufSize
;
6375 *pnEnumValues
= cValues
;
6377 if (cbEnumValues
< cbBufSize
) /* buffer too small */
6379 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6380 WARN ("HeapFree failed with code %i\n", GetLastError ());
6381 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6382 WARN ("HeapFree failed with code %i\n", GetLastError ());
6383 r
= RegCloseKey (hkSubKey
);
6384 if (r
!= ERROR_SUCCESS
)
6385 WARN ("RegCloseKey returned %i\n", r
);
6386 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
6387 return ERROR_MORE_DATA
;
6390 TRACE ("pass 2: copying all names and values to buffer\n");
6392 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
6393 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6395 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6397 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6398 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6399 NULL
, &dwType
, lpValue
, &cbValueLen
);
6400 if (ret
!= ERROR_SUCCESS
)
6402 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6403 WARN ("HeapFree failed with code %i\n", GetLastError ());
6404 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6405 WARN ("HeapFree failed with code %i\n", GetLastError ());
6406 r
= RegCloseKey (hkSubKey
);
6407 if (r
!= ERROR_SUCCESS
)
6408 WARN ("RegCloseKey returned %i\n", r
);
6409 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6413 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6414 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
6415 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
6416 pEnumValues
+= cbValueNameLen
;
6418 /* return # of *bytes* (including trailing \0), not # of chars */
6419 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
6421 ppev
[dwIndex
].dwType
= dwType
;
6423 memcpy (pEnumValues
, lpValue
, cbValueLen
);
6424 ppev
[dwIndex
].pData
= pEnumValues
;
6425 pEnumValues
+= cbValueLen
;
6427 ppev
[dwIndex
].cbData
= cbValueLen
;
6429 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6430 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
6433 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6435 ret
= GetLastError ();
6436 ERR ("HeapFree failed with code %i\n", ret
);
6437 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6438 WARN ("HeapFree failed with code %i\n", GetLastError ());
6439 r
= RegCloseKey (hkSubKey
);
6440 if (r
!= ERROR_SUCCESS
)
6441 WARN ("RegCloseKey returned %i\n", r
);
6445 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6447 ret
= GetLastError ();
6448 ERR ("HeapFree failed with code %i\n", ret
);
6449 r
= RegCloseKey (hkSubKey
);
6450 if (r
!= ERROR_SUCCESS
)
6451 WARN ("RegCloseKey returned %i\n", r
);
6455 ret
= RegCloseKey (hkSubKey
);
6456 if (ret
!= ERROR_SUCCESS
)
6458 ERR ("RegCloseKey returned %i\n", ret
);
6462 return ERROR_SUCCESS
;
6465 /*******************************************************************************
6466 * EnumPrinterDataExA [WINSPOOL.@]
6468 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6469 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6470 * what Windows 2000 SP1 does.
6473 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6474 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6475 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6479 DWORD ret
, dwIndex
, dwBufSize
;
6483 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6485 if (pKeyName
== NULL
|| *pKeyName
== 0)
6486 return ERROR_INVALID_PARAMETER
;
6488 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6491 ret
= GetLastError ();
6492 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6496 hHeap
= GetProcessHeap ();
6499 ERR ("GetProcessHeap failed\n");
6500 return ERROR_OUTOFMEMORY
;
6503 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6504 if (pKeyNameW
== NULL
)
6506 ERR ("Failed to allocate %i bytes from process heap\n",
6507 (LONG
)(len
* sizeof (WCHAR
)));
6508 return ERROR_OUTOFMEMORY
;
6511 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6513 ret
= GetLastError ();
6514 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6515 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6516 WARN ("HeapFree failed with code %i\n", GetLastError ());
6520 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6521 pcbEnumValues
, pnEnumValues
);
6522 if (ret
!= ERROR_SUCCESS
)
6524 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6525 WARN ("HeapFree failed with code %i\n", GetLastError ());
6526 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6530 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6532 ret
= GetLastError ();
6533 ERR ("HeapFree failed with code %i\n", ret
);
6537 if (*pnEnumValues
== 0) /* empty key */
6538 return ERROR_SUCCESS
;
6541 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6543 PPRINTER_ENUM_VALUESW ppev
=
6544 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6546 if (dwBufSize
< ppev
->cbValueName
)
6547 dwBufSize
= ppev
->cbValueName
;
6549 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6550 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6551 dwBufSize
= ppev
->cbData
;
6554 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6556 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6557 if (pBuffer
== NULL
)
6559 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6560 return ERROR_OUTOFMEMORY
;
6563 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6565 PPRINTER_ENUM_VALUESW ppev
=
6566 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6568 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6569 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6573 ret
= GetLastError ();
6574 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6575 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6576 WARN ("HeapFree failed with code %i\n", GetLastError ());
6580 memcpy (ppev
->pValueName
, pBuffer
, len
);
6582 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6584 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6585 ppev
->dwType
!= REG_MULTI_SZ
)
6588 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6589 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6592 ret
= GetLastError ();
6593 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6594 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6595 WARN ("HeapFree failed with code %i\n", GetLastError ());
6599 memcpy (ppev
->pData
, pBuffer
, len
);
6601 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6602 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6605 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6607 ret
= GetLastError ();
6608 ERR ("HeapFree failed with code %i\n", ret
);
6612 return ERROR_SUCCESS
;
6615 /******************************************************************************
6616 * AbortPrinter (WINSPOOL.@)
6618 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6620 FIXME("(%p), stub!\n", hPrinter
);
6624 /******************************************************************************
6625 * AddPortA (WINSPOOL.@)
6630 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6632 LPWSTR nameW
= NULL
;
6633 LPWSTR monitorW
= NULL
;
6637 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6640 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6641 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6642 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6646 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6647 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6648 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6650 res
= AddPortW(nameW
, hWnd
, monitorW
);
6651 HeapFree(GetProcessHeap(), 0, nameW
);
6652 HeapFree(GetProcessHeap(), 0, monitorW
);
6656 /******************************************************************************
6657 * AddPortW (WINSPOOL.@)
6659 * Add a Port for a specific Monitor
6662 * pName [I] Servername or NULL (local Computer)
6663 * hWnd [I] Handle to parent Window for the Dialog-Box
6664 * pMonitorName [I] Name of the Monitor that manage the Port
6671 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6673 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6675 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6677 if (!pMonitorName
) {
6678 SetLastError(RPC_X_NULL_REF_POINTER
);
6682 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6685 /******************************************************************************
6686 * AddPortExA (WINSPOOL.@)
6691 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6694 PORT_INFO_2A
* pi2A
;
6695 LPWSTR nameW
= NULL
;
6696 LPWSTR monitorW
= NULL
;
6700 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6702 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6703 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6705 if ((level
< 1) || (level
> 2)) {
6706 SetLastError(ERROR_INVALID_LEVEL
);
6711 SetLastError(ERROR_INVALID_PARAMETER
);
6716 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6717 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6718 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6722 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6723 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6724 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6727 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6729 if (pi2A
->pPortName
) {
6730 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6731 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6732 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6736 if (pi2A
->pMonitorName
) {
6737 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6738 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6739 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6742 if (pi2A
->pDescription
) {
6743 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6744 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6745 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6747 pi2W
.fPortType
= pi2A
->fPortType
;
6748 pi2W
.Reserved
= pi2A
->Reserved
;
6751 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6753 HeapFree(GetProcessHeap(), 0, nameW
);
6754 HeapFree(GetProcessHeap(), 0, monitorW
);
6755 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6756 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6757 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6762 /******************************************************************************
6763 * AddPortExW (WINSPOOL.@)
6765 * Add a Port for a specific Monitor, without presenting a user interface
6768 * pName [I] Servername or NULL (local Computer)
6769 * level [I] Structure-Level (1 or 2) for pBuffer
6770 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6771 * pMonitorName [I] Name of the Monitor that manage the Port
6778 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6782 pi2
= (PORT_INFO_2W
*) pBuffer
;
6784 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6785 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6786 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6787 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6789 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6791 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6792 SetLastError(ERROR_INVALID_PARAMETER
);
6796 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6799 /******************************************************************************
6800 * AddPrinterConnectionA (WINSPOOL.@)
6802 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6804 FIXME("%s\n", debugstr_a(pName
));
6808 /******************************************************************************
6809 * AddPrinterConnectionW (WINSPOOL.@)
6811 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6813 FIXME("%s\n", debugstr_w(pName
));
6817 /******************************************************************************
6818 * AddPrinterDriverExW (WINSPOOL.@)
6820 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6823 * pName [I] Servername or NULL (local Computer)
6824 * level [I] Level for the supplied DRIVER_INFO_*W struct
6825 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6826 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6833 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6835 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6837 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6839 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6840 SetLastError(ERROR_INVALID_LEVEL
);
6845 SetLastError(ERROR_INVALID_PARAMETER
);
6849 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6852 /******************************************************************************
6853 * AddPrinterDriverExA (WINSPOOL.@)
6855 * See AddPrinterDriverExW.
6858 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6860 DRIVER_INFO_8A
*diA
;
6862 LPWSTR nameW
= NULL
;
6867 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6869 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6870 ZeroMemory(&diW
, sizeof(diW
));
6872 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6873 SetLastError(ERROR_INVALID_LEVEL
);
6878 SetLastError(ERROR_INVALID_PARAMETER
);
6882 /* convert servername to unicode */
6884 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6885 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6886 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6890 diW
.cVersion
= diA
->cVersion
;
6893 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6894 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6895 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6898 if (diA
->pEnvironment
) {
6899 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6900 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6901 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6904 if (diA
->pDriverPath
) {
6905 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6906 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6907 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6910 if (diA
->pDataFile
) {
6911 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6912 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6913 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6916 if (diA
->pConfigFile
) {
6917 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6918 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6919 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6922 if ((Level
> 2) && diA
->pDependentFiles
) {
6923 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6924 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6925 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6926 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6929 if ((Level
> 2) && diA
->pMonitorName
) {
6930 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6931 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6932 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6935 if ((Level
> 3) && diA
->pDefaultDataType
) {
6936 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6937 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6938 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6941 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6942 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6943 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6944 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6945 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6948 if ((Level
> 5) && diA
->pszMfgName
) {
6949 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6950 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6951 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6954 if ((Level
> 5) && diA
->pszOEMUrl
) {
6955 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6956 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6957 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6960 if ((Level
> 5) && diA
->pszHardwareID
) {
6961 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6962 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6963 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6966 if ((Level
> 5) && diA
->pszProvider
) {
6967 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6968 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6969 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6973 FIXME("level %u is incomplete\n", Level
);
6976 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6977 TRACE("got %u with %u\n", res
, GetLastError());
6978 HeapFree(GetProcessHeap(), 0, nameW
);
6979 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6980 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6981 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6982 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6983 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6984 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6985 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6986 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6987 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6988 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6989 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6990 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6991 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6993 TRACE("=> %u with %u\n", res
, GetLastError());
6997 /******************************************************************************
6998 * ConfigurePortA (WINSPOOL.@)
7000 * See ConfigurePortW.
7003 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
7005 LPWSTR nameW
= NULL
;
7006 LPWSTR portW
= NULL
;
7010 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
7012 /* convert servername to unicode */
7014 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7015 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7016 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7019 /* convert portname to unicode */
7021 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
7022 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7023 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
7026 res
= ConfigurePortW(nameW
, hWnd
, portW
);
7027 HeapFree(GetProcessHeap(), 0, nameW
);
7028 HeapFree(GetProcessHeap(), 0, portW
);
7032 /******************************************************************************
7033 * ConfigurePortW (WINSPOOL.@)
7035 * Display the Configuration-Dialog for a specific Port
7038 * pName [I] Servername or NULL (local Computer)
7039 * hWnd [I] Handle to parent Window for the Dialog-Box
7040 * pPortName [I] Name of the Port, that should be configured
7047 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
7050 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
7052 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7055 SetLastError(RPC_X_NULL_REF_POINTER
);
7059 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
7062 /******************************************************************************
7063 * ConnectToPrinterDlg (WINSPOOL.@)
7065 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
7067 FIXME("%p %x\n", hWnd
, Flags
);
7071 /******************************************************************************
7072 * DeletePrinterConnectionA (WINSPOOL.@)
7074 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
7076 FIXME("%s\n", debugstr_a(pName
));
7080 /******************************************************************************
7081 * DeletePrinterConnectionW (WINSPOOL.@)
7083 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
7085 FIXME("%s\n", debugstr_w(pName
));
7089 /******************************************************************************
7090 * DeletePrinterDriverExW (WINSPOOL.@)
7092 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
7093 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7098 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7099 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
7101 if(pName
&& pName
[0])
7103 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
7104 SetLastError(ERROR_INVALID_PARAMETER
);
7110 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
7111 SetLastError(ERROR_INVALID_PARAMETER
);
7115 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
7119 ERR("Can't open drivers key\n");
7123 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
7126 RegCloseKey(hkey_drivers
);
7131 /******************************************************************************
7132 * DeletePrinterDriverExA (WINSPOOL.@)
7134 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
7135 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7137 UNICODE_STRING NameW
, EnvW
, DriverW
;
7140 asciitounicode(&NameW
, pName
);
7141 asciitounicode(&EnvW
, pEnvironment
);
7142 asciitounicode(&DriverW
, pDriverName
);
7144 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
7146 RtlFreeUnicodeString(&DriverW
);
7147 RtlFreeUnicodeString(&EnvW
);
7148 RtlFreeUnicodeString(&NameW
);
7153 /******************************************************************************
7154 * DeletePrinterDataExW (WINSPOOL.@)
7156 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
7159 FIXME("%p %s %s\n", hPrinter
,
7160 debugstr_w(pKeyName
), debugstr_w(pValueName
));
7161 return ERROR_INVALID_PARAMETER
;
7164 /******************************************************************************
7165 * DeletePrinterDataExA (WINSPOOL.@)
7167 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
7170 FIXME("%p %s %s\n", hPrinter
,
7171 debugstr_a(pKeyName
), debugstr_a(pValueName
));
7172 return ERROR_INVALID_PARAMETER
;
7175 /******************************************************************************
7176 * DeletePrintProcessorA (WINSPOOL.@)
7178 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
7180 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7181 debugstr_a(pPrintProcessorName
));
7185 /******************************************************************************
7186 * DeletePrintProcessorW (WINSPOOL.@)
7188 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
7190 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7191 debugstr_w(pPrintProcessorName
));
7195 /******************************************************************************
7196 * DeletePrintProvidorA (WINSPOOL.@)
7198 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
7200 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7201 debugstr_a(pPrintProviderName
));
7205 /******************************************************************************
7206 * DeletePrintProvidorW (WINSPOOL.@)
7208 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
7210 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7211 debugstr_w(pPrintProviderName
));
7215 /******************************************************************************
7216 * EnumFormsA (WINSPOOL.@)
7218 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7219 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7221 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7222 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7226 /******************************************************************************
7227 * EnumFormsW (WINSPOOL.@)
7229 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7230 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7232 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7233 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7237 /*****************************************************************************
7238 * EnumMonitorsA [WINSPOOL.@]
7240 * See EnumMonitorsW.
7243 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7244 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7247 LPBYTE bufferW
= NULL
;
7248 LPWSTR nameW
= NULL
;
7250 DWORD numentries
= 0;
7253 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
7254 cbBuf
, pcbNeeded
, pcReturned
);
7256 /* convert servername to unicode */
7258 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7259 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7260 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7262 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7263 needed
= cbBuf
* sizeof(WCHAR
);
7264 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7265 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7267 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7268 if (pcbNeeded
) needed
= *pcbNeeded
;
7269 /* HeapReAlloc return NULL, when bufferW was NULL */
7270 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7271 HeapAlloc(GetProcessHeap(), 0, needed
);
7273 /* Try again with the large Buffer */
7274 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7276 numentries
= pcReturned
? *pcReturned
: 0;
7279 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7280 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7283 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7284 DWORD entrysize
= 0;
7287 LPMONITOR_INFO_2W mi2w
;
7288 LPMONITOR_INFO_2A mi2a
;
7290 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7291 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
7293 /* First pass: calculate the size for all Entries */
7294 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7295 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7297 while (index
< numentries
) {
7299 needed
+= entrysize
; /* MONITOR_INFO_?A */
7300 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
7302 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7303 NULL
, 0, NULL
, NULL
);
7305 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7306 NULL
, 0, NULL
, NULL
);
7307 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7308 NULL
, 0, NULL
, NULL
);
7310 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7311 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7312 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7315 /* check for errors and quit on failure */
7316 if (cbBuf
< needed
) {
7317 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7321 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
7322 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
7323 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7324 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7325 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7327 /* Second Pass: Fill the User Buffer (if we have one) */
7328 while ((index
< numentries
) && pMonitors
) {
7330 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7332 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7333 ptr
, cbBuf
, NULL
, NULL
);
7337 mi2a
->pEnvironment
= ptr
;
7338 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7339 ptr
, cbBuf
, NULL
, NULL
);
7343 mi2a
->pDLLName
= ptr
;
7344 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7345 ptr
, cbBuf
, NULL
, NULL
);
7349 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7350 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7351 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7355 if (pcbNeeded
) *pcbNeeded
= needed
;
7356 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7358 HeapFree(GetProcessHeap(), 0, nameW
);
7359 HeapFree(GetProcessHeap(), 0, bufferW
);
7361 TRACE("returning %d with %d (%d byte for %d entries)\n",
7362 (res
), GetLastError(), needed
, numentries
);
7368 /*****************************************************************************
7369 * EnumMonitorsW [WINSPOOL.@]
7371 * Enumerate available Port-Monitors
7374 * pName [I] Servername or NULL (local Computer)
7375 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7376 * pMonitors [O] PTR to Buffer that receives the Result
7377 * cbBuf [I] Size of Buffer at pMonitors
7378 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7379 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7383 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7386 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7387 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7390 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7391 cbBuf
, pcbNeeded
, pcReturned
);
7393 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7395 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
7396 SetLastError(RPC_X_NULL_REF_POINTER
);
7400 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
7403 /******************************************************************************
7404 * SpoolerInit (WINSPOOL.@)
7406 * Initialize the Spooler
7413 * The function fails on windows, when the spooler service is not running
7416 BOOL WINAPI
SpoolerInit(void)
7419 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7423 /******************************************************************************
7424 * XcvDataW (WINSPOOL.@)
7426 * Execute commands in the Printmonitor DLL
7429 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7430 * pszDataName [i] Name of the command to execute
7431 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7432 * cbInputData [i] Size in Bytes of Buffer at pInputData
7433 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7434 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7435 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7436 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7443 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7444 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7446 * Minimal List of commands, that a Printmonitor DLL should support:
7448 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7449 *| "AddPort" : Add a Port
7450 *| "DeletePort": Delete a Port
7452 * Many Printmonitors support additional commands. Examples for localspl.dll:
7453 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7454 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7457 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7458 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7459 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7461 opened_printer_t
*printer
;
7463 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7464 pInputData
, cbInputData
, pOutputData
,
7465 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7467 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7469 printer
= get_opened_printer(hXcv
);
7470 if (!printer
|| (!printer
->backend_printer
)) {
7471 SetLastError(ERROR_INVALID_HANDLE
);
7475 if (!pcbOutputNeeded
) {
7476 SetLastError(ERROR_INVALID_PARAMETER
);
7480 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7481 SetLastError(RPC_X_NULL_REF_POINTER
);
7485 *pcbOutputNeeded
= 0;
7487 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
7488 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7492 /*****************************************************************************
7493 * EnumPrinterDataA [WINSPOOL.@]
7496 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7497 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7498 DWORD cbData
, LPDWORD pcbData
)
7500 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7501 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7502 return ERROR_NO_MORE_ITEMS
;
7505 /*****************************************************************************
7506 * EnumPrinterDataW [WINSPOOL.@]
7509 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7510 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7511 DWORD cbData
, LPDWORD pcbData
)
7513 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7514 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7515 return ERROR_NO_MORE_ITEMS
;
7518 /*****************************************************************************
7519 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7522 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7523 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7524 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7526 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7527 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7528 pcbNeeded
, pcReturned
);
7532 /*****************************************************************************
7533 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7536 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7537 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7538 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7540 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7541 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7542 pcbNeeded
, pcReturned
);
7546 /*****************************************************************************
7547 * EnumPrintProcessorsA [WINSPOOL.@]
7549 * See EnumPrintProcessorsW.
7552 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7553 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7556 LPBYTE bufferW
= NULL
;
7557 LPWSTR nameW
= NULL
;
7560 DWORD numentries
= 0;
7563 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7564 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7566 /* convert names to unicode */
7568 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7569 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7570 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7573 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
7574 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7575 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
7578 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7579 needed
= cbBuf
* sizeof(WCHAR
);
7580 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7581 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7583 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7584 if (pcbNeeded
) needed
= *pcbNeeded
;
7585 /* HeapReAlloc return NULL, when bufferW was NULL */
7586 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7587 HeapAlloc(GetProcessHeap(), 0, needed
);
7589 /* Try again with the large Buffer */
7590 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7592 numentries
= pcReturned
? *pcReturned
: 0;
7596 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7599 PPRINTPROCESSOR_INFO_1W ppiw
;
7600 PPRINTPROCESSOR_INFO_1A ppia
;
7602 /* First pass: calculate the size for all Entries */
7603 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7604 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7606 while (index
< numentries
) {
7608 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7609 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7611 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7612 NULL
, 0, NULL
, NULL
);
7614 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7615 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7618 /* check for errors and quit on failure */
7619 if (cbBuf
< needed
) {
7620 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7625 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7626 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7627 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7628 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7629 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7631 /* Second Pass: Fill the User Buffer (if we have one) */
7632 while ((index
< numentries
) && pPPInfo
) {
7634 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7636 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7637 ptr
, cbBuf
, NULL
, NULL
);
7641 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7642 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7647 if (pcbNeeded
) *pcbNeeded
= needed
;
7648 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7650 HeapFree(GetProcessHeap(), 0, nameW
);
7651 HeapFree(GetProcessHeap(), 0, envW
);
7652 HeapFree(GetProcessHeap(), 0, bufferW
);
7654 TRACE("returning %d with %d (%d byte for %d entries)\n",
7655 (res
), GetLastError(), needed
, numentries
);
7660 /*****************************************************************************
7661 * EnumPrintProcessorsW [WINSPOOL.@]
7663 * Enumerate available Print Processors
7666 * pName [I] Servername or NULL (local Computer)
7667 * pEnvironment [I] Printing-Environment or NULL (Default)
7668 * Level [I] Structure-Level (Only 1 is allowed)
7669 * pPPInfo [O] PTR to Buffer that receives the Result
7670 * cbBuf [I] Size of Buffer at pPPInfo
7671 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7672 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7676 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7679 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7680 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7683 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7684 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7686 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7688 if (!pcbNeeded
|| !pcReturned
) {
7689 SetLastError(RPC_X_NULL_REF_POINTER
);
7693 if (!pPPInfo
&& (cbBuf
> 0)) {
7694 SetLastError(ERROR_INVALID_USER_BUFFER
);
7698 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7699 cbBuf
, pcbNeeded
, pcReturned
);
7702 /*****************************************************************************
7703 * ExtDeviceMode [WINSPOOL.@]
7706 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7707 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7710 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7711 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7712 debugstr_a(pProfile
), fMode
);
7716 /*****************************************************************************
7717 * FindClosePrinterChangeNotification [WINSPOOL.@]
7720 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7722 FIXME("Stub: %p\n", hChange
);
7726 /*****************************************************************************
7727 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7730 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7731 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7733 FIXME("Stub: %p %x %x %p\n",
7734 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7735 return INVALID_HANDLE_VALUE
;
7738 /*****************************************************************************
7739 * FindNextPrinterChangeNotification [WINSPOOL.@]
7742 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7743 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7745 FIXME("Stub: %p %p %p %p\n",
7746 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7750 /*****************************************************************************
7751 * FreePrinterNotifyInfo [WINSPOOL.@]
7754 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7756 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7760 /*****************************************************************************
7763 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7764 * ansi depending on the unicode parameter.
7766 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7776 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7779 memcpy(ptr
, str
, *size
);
7786 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7789 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7796 /*****************************************************************************
7799 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7800 LPDWORD pcbNeeded
, BOOL unicode
)
7802 DWORD size
, left
= cbBuf
;
7803 BOOL space
= (cbBuf
> 0);
7810 ji1
->JobId
= job
->job_id
;
7813 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7814 if(space
&& size
<= left
)
7816 ji1
->pDocument
= (LPWSTR
)ptr
;
7824 if (job
->printer_name
)
7826 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7827 if(space
&& size
<= left
)
7829 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7841 /*****************************************************************************
7844 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7845 LPDWORD pcbNeeded
, BOOL unicode
)
7847 DWORD size
, left
= cbBuf
;
7849 BOOL space
= (cbBuf
> 0);
7851 LPDEVMODEA dmA
= NULL
;
7858 ji2
->JobId
= job
->job_id
;
7861 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7862 if(space
&& size
<= left
)
7864 ji2
->pDocument
= (LPWSTR
)ptr
;
7872 if (job
->printer_name
)
7874 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7875 if(space
&& size
<= left
)
7877 ji2
->pPrinterName
= (LPWSTR
)ptr
;
7890 dmA
= DEVMODEdupWtoA(job
->devmode
);
7891 devmode
= (LPDEVMODEW
) dmA
;
7892 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
7896 devmode
= job
->devmode
;
7897 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
7901 FIXME("Can't convert DEVMODE W to A\n");
7904 /* align DEVMODE to a DWORD boundary */
7905 shift
= (4 - (*pcbNeeded
& 3)) & 3;
7911 memcpy(ptr
, devmode
, size
-shift
);
7912 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
7913 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
7926 /*****************************************************************************
7929 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7930 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7933 DWORD needed
= 0, size
;
7937 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7939 EnterCriticalSection(&printer_handles_cs
);
7940 job
= get_job(hPrinter
, JobId
);
7947 size
= sizeof(JOB_INFO_1W
);
7952 memset(pJob
, 0, size
);
7956 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7961 size
= sizeof(JOB_INFO_2W
);
7966 memset(pJob
, 0, size
);
7970 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7975 size
= sizeof(JOB_INFO_3
);
7979 memset(pJob
, 0, size
);
7988 SetLastError(ERROR_INVALID_LEVEL
);
7992 *pcbNeeded
= needed
;
7994 LeaveCriticalSection(&printer_handles_cs
);
7998 /*****************************************************************************
7999 * GetJobA [WINSPOOL.@]
8002 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8003 DWORD cbBuf
, LPDWORD pcbNeeded
)
8005 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
8008 /*****************************************************************************
8009 * GetJobW [WINSPOOL.@]
8012 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8013 DWORD cbBuf
, LPDWORD pcbNeeded
)
8015 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
8018 /*****************************************************************************
8021 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
8024 char *unixname
, *cmdA
;
8026 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
8032 if(!(unixname
= wine_get_unix_file_name(filename
)))
8035 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
8036 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
8037 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
8039 TRACE("printing with: %s\n", cmdA
);
8041 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
8046 ERR("pipe() failed!\n");
8050 if ((pid
= fork()) == 0)
8056 /* reset signals that we previously set to SIG_IGN */
8057 signal(SIGPIPE
, SIG_DFL
);
8059 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
8064 ERR("fork() failed!\n");
8068 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
8069 write(fds
[1], buf
, no_read
);
8076 wret
= waitpid(pid
, &status
, 0);
8077 } while (wret
< 0 && errno
== EINTR
);
8080 ERR("waitpid() failed!\n");
8083 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
8085 ERR("child process failed! %d\n", status
);
8092 if(file_fd
!= -1) close(file_fd
);
8093 if(fds
[0] != -1) close(fds
[0]);
8094 if(fds
[1] != -1) close(fds
[1]);
8096 HeapFree(GetProcessHeap(), 0, cmdA
);
8097 HeapFree(GetProcessHeap(), 0, unixname
);
8104 /*****************************************************************************
8107 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
8110 const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8113 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
8114 sprintfW(cmd
, fmtW
, printer_name
);
8116 r
= schedule_pipe(cmd
, filename
);
8118 HeapFree(GetProcessHeap(), 0, cmd
);
8122 #ifdef SONAME_LIBCUPS
8123 /*****************************************************************************
8124 * get_cups_jobs_ticket_options
8126 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8127 * The CUPS scheduler only looks for these in Print-File requests, and since
8128 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8131 static int get_cups_job_ticket_options( const char *file
, int num_options
, cups_option_t
**options
)
8133 FILE *fp
= fopen( file
, "r" );
8134 char buf
[257]; /* DSC max of 256 + '\0' */
8135 const char *ps_adobe
= "%!PS-Adobe-";
8136 const char *cups_job
= "%cupsJobTicket:";
8138 if (!fp
) return num_options
;
8139 if (!fgets( buf
, sizeof(buf
), fp
)) goto end
;
8140 if (strncmp( buf
, ps_adobe
, strlen( ps_adobe
) )) goto end
;
8141 while (fgets( buf
, sizeof(buf
), fp
))
8143 if (strncmp( buf
, cups_job
, strlen( cups_job
) )) break;
8144 num_options
= pcupsParseOptions( buf
+ strlen( cups_job
), num_options
, options
);
8153 /*****************************************************************************
8156 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
8158 #ifdef SONAME_LIBCUPS
8161 char *unixname
, *queue
, *unix_doc_title
;
8164 int num_options
= 0, i
;
8165 cups_option_t
*options
= NULL
;
8167 if(!(unixname
= wine_get_unix_file_name(filename
)))
8170 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
8171 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
8172 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
8174 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
8175 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
8176 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
8178 num_options
= get_cups_job_ticket_options( unixname
, num_options
, &options
);
8180 TRACE( "printing via cups with options:\n" );
8181 for (i
= 0; i
< num_options
; i
++)
8182 TRACE( "\t%d: %s = %s\n", i
, options
[i
].name
, options
[i
].value
);
8184 ret
= pcupsPrintFile( queue
, unixname
, unix_doc_title
, num_options
, options
);
8186 pcupsFreeOptions( num_options
, options
);
8188 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
8189 HeapFree(GetProcessHeap(), 0, queue
);
8190 HeapFree(GetProcessHeap(), 0, unixname
);
8196 return schedule_lpr(printer_name
, filename
);
8200 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
8207 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
8211 if(HIWORD(wparam
) == BN_CLICKED
)
8213 if(LOWORD(wparam
) == IDOK
)
8216 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
8219 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
8220 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
8222 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
8224 WCHAR caption
[200], message
[200];
8227 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
8228 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
8229 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
8230 if(mb_ret
== IDCANCEL
)
8232 HeapFree(GetProcessHeap(), 0, filename
);
8236 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
8237 if(hf
== INVALID_HANDLE_VALUE
)
8239 WCHAR caption
[200], message
[200];
8241 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
8242 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
8243 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
8244 HeapFree(GetProcessHeap(), 0, filename
);
8248 DeleteFileW(filename
);
8249 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
8251 EndDialog(hwnd
, IDOK
);
8254 if(LOWORD(wparam
) == IDCANCEL
)
8256 EndDialog(hwnd
, IDCANCEL
);
8265 /*****************************************************************************
8268 static BOOL
get_filename(LPWSTR
*filename
)
8270 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
8271 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
8274 /*****************************************************************************
8277 static BOOL
schedule_file(LPCWSTR filename
)
8279 LPWSTR output
= NULL
;
8281 if(get_filename(&output
))
8284 TRACE("copy to %s\n", debugstr_w(output
));
8285 r
= CopyFileW(filename
, output
, FALSE
);
8286 HeapFree(GetProcessHeap(), 0, output
);
8292 /*****************************************************************************
8295 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
8297 int in_fd
, out_fd
, no_read
;
8300 char *unixname
, *outputA
;
8303 if(!(unixname
= wine_get_unix_file_name(filename
)))
8306 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
8307 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
8308 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
8310 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
8311 in_fd
= open(unixname
, O_RDONLY
);
8312 if(out_fd
== -1 || in_fd
== -1)
8315 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
8316 write(out_fd
, buf
, no_read
);
8320 if(in_fd
!= -1) close(in_fd
);
8321 if(out_fd
!= -1) close(out_fd
);
8322 HeapFree(GetProcessHeap(), 0, outputA
);
8323 HeapFree(GetProcessHeap(), 0, unixname
);
8327 /*****************************************************************************
8328 * ScheduleJob [WINSPOOL.@]
8331 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
8333 opened_printer_t
*printer
;
8335 struct list
*cursor
, *cursor2
;
8337 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
8338 EnterCriticalSection(&printer_handles_cs
);
8339 printer
= get_opened_printer(hPrinter
);
8343 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
8345 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
8348 if(job
->job_id
!= dwJobID
) continue;
8350 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
8351 if(hf
!= INVALID_HANDLE_VALUE
)
8353 PRINTER_INFO_5W
*pi5
= NULL
;
8354 LPWSTR portname
= job
->portname
;
8358 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8359 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8363 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
8364 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
8365 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
8366 portname
= pi5
->pPortName
;
8368 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
8369 debugstr_w(portname
));
8373 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8374 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
8376 DWORD type
, count
= sizeof(output
);
8377 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
8380 if(output
[0] == '|')
8382 ret
= schedule_pipe(output
+ 1, job
->filename
);
8386 ret
= schedule_unixfile(output
, job
->filename
);
8388 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
8390 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
8392 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
8394 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
8396 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
8398 ret
= schedule_file(job
->filename
);
8402 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
8404 HeapFree(GetProcessHeap(), 0, pi5
);
8406 DeleteFileW(job
->filename
);
8408 list_remove(cursor
);
8409 HeapFree(GetProcessHeap(), 0, job
->document_title
);
8410 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
8411 HeapFree(GetProcessHeap(), 0, job
->portname
);
8412 HeapFree(GetProcessHeap(), 0, job
->filename
);
8413 HeapFree(GetProcessHeap(), 0, job
->devmode
);
8414 HeapFree(GetProcessHeap(), 0, job
);
8418 LeaveCriticalSection(&printer_handles_cs
);
8422 /*****************************************************************************
8423 * StartDocDlgA [WINSPOOL.@]
8425 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
8427 UNICODE_STRING usBuffer
;
8430 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
8433 docW
.cbSize
= sizeof(docW
);
8434 if (doc
->lpszDocName
)
8436 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
8437 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
8439 if (doc
->lpszOutput
)
8441 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
8442 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
8444 if (doc
->lpszDatatype
)
8446 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
8447 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
8449 docW
.fwType
= doc
->fwType
;
8451 retW
= StartDocDlgW(hPrinter
, &docW
);
8455 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
8456 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
8457 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
8458 HeapFree(GetProcessHeap(), 0, retW
);
8461 HeapFree(GetProcessHeap(), 0, datatypeW
);
8462 HeapFree(GetProcessHeap(), 0, outputW
);
8463 HeapFree(GetProcessHeap(), 0, docnameW
);
8468 /*****************************************************************************
8469 * StartDocDlgW [WINSPOOL.@]
8471 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8472 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8473 * port is "FILE:". Also returns the full path if passed a relative path.
8475 * The caller should free the returned string from the process heap.
8477 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
8482 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
8484 PRINTER_INFO_5W
*pi5
;
8485 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
8486 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
8488 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
8489 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
8490 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
8492 HeapFree(GetProcessHeap(), 0, pi5
);
8495 HeapFree(GetProcessHeap(), 0, pi5
);
8498 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
8502 if (get_filename(&name
))
8504 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
8506 HeapFree(GetProcessHeap(), 0, name
);
8509 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8510 GetFullPathNameW(name
, len
, ret
, NULL
);
8511 HeapFree(GetProcessHeap(), 0, name
);
8516 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8519 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8520 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8522 attr
= GetFileAttributesW(ret
);
8523 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8525 HeapFree(GetProcessHeap(), 0, ret
);