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 if (!pcupsGetPPD
) return HTTP_NOT_FOUND
;
806 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
809 ppd
= pcupsGetPPD( name
);
811 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd
) );
813 if (!ppd
) return HTTP_NOT_FOUND
;
815 if (rename( ppd
, buffer
) == -1)
817 BOOL res
= copy_file( ppd
, buffer
);
819 if (!res
) return HTTP_NOT_FOUND
;
824 static BOOL
get_cups_ppd( const char *printer_name
, const WCHAR
*ppd
)
827 http_status_t http_status
;
828 char *unix_name
= wine_get_unix_file_name( ppd
);
830 TRACE( "(%s, %s)\n", debugstr_a(printer_name
), debugstr_w(ppd
) );
832 if (!unix_name
) return FALSE
;
834 http_status
= cupsGetPPD3_wrapper( 0, printer_name
, &modtime
,
835 unix_name
, strlen( unix_name
) + 1 );
836 HeapFree( GetProcessHeap(), 0, unix_name
);
838 if (http_status
== HTTP_OK
) return TRUE
;
840 TRACE( "failed to get ppd for printer %s from cups, calling fallback\n", debugstr_a(printer_name
) );
841 return get_fallback_ppd( printer_name
, ppd
);
844 static WCHAR
*get_cups_option( const char *name
, int num_options
, cups_option_t
*options
)
850 value
= pcupsGetOption( name
, num_options
, options
);
851 if (!value
) return NULL
;
853 len
= MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, NULL
, 0 );
854 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
855 if (ret
) MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, ret
, len
);
860 static BOOL
CUPS_LoadPrinters(void)
863 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
866 WCHAR
*port
, *ppd_dir
= NULL
, *ppd
;
867 HKEY hkeyPrinter
, hkeyPrinters
;
869 WCHAR nameW
[MAX_PATH
];
870 HANDLE added_printer
;
872 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
874 TRACE("%s\n", loaderror
);
877 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
879 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
882 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 );
886 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
888 ERR("Can't create Printers key\n");
892 nrofdests
= pcupsGetDests(&dests
);
893 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
894 for (i
=0;i
<nrofdests
;i
++) {
895 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[i
].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
897 port
= HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port
) + lstrlenW(nameW
) * sizeof(WCHAR
));
898 lstrcpyW(port
, CUPS_Port
);
899 lstrcatW(port
, nameW
);
901 TRACE("Printer %d: %s\n", i
, debugstr_w(nameW
));
902 if(RegOpenKeyW(hkeyPrinters
, nameW
, &hkeyPrinter
) == ERROR_SUCCESS
) {
903 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
904 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
906 TRACE("Printer already exists\n");
907 /* overwrite old LPR:* port */
908 RegSetValueExW(hkeyPrinter
, PortW
, 0, REG_SZ
, (LPBYTE
)port
, (lstrlenW(port
) + 1) * sizeof(WCHAR
));
909 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
910 /* flag that the PPD file should be checked for an update */
911 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
912 RegCloseKey(hkeyPrinter
);
914 BOOL added_driver
= FALSE
;
916 if (!ppd_dir
) ppd_dir
= get_ppd_dir();
917 ppd
= get_ppd_filename( ppd_dir
, nameW
);
918 if (get_cups_ppd( dests
[i
].name
, ppd
))
920 added_driver
= add_printer_driver( nameW
, ppd
);
923 HeapFree( GetProcessHeap(), 0, ppd
);
924 if (!added_driver
) continue;
926 memset(&pi2
, 0, sizeof(PRINTER_INFO_2W
));
927 pi2
.pPrinterName
= nameW
;
928 pi2
.pDatatype
= rawW
;
929 pi2
.pPrintProcessor
= WinPrintW
;
930 pi2
.pDriverName
= nameW
;
931 pi2
.pComment
= get_cups_option( "printer-info", dests
[i
].num_options
, dests
[i
].options
);
932 pi2
.pLocation
= get_cups_option( "printer-location", dests
[i
].num_options
, dests
[i
].options
);
933 pi2
.pPortName
= port
;
934 pi2
.pParameters
= emptyStringW
;
935 pi2
.pShareName
= emptyStringW
;
936 pi2
.pSepFile
= emptyStringW
;
938 added_printer
= AddPrinterW( NULL
, 2, (LPBYTE
)&pi2
);
939 if (added_printer
) ClosePrinter( added_printer
);
940 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
941 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW
), GetLastError() );
943 HeapFree( GetProcessHeap(), 0, pi2
.pComment
);
944 HeapFree( GetProcessHeap(), 0, pi2
.pLocation
);
946 HeapFree( GetProcessHeap(), 0, port
);
949 if (dests
[i
].is_default
) {
950 SetDefaultPrinterW(nameW
);
957 RemoveDirectoryW( ppd_dir
);
958 HeapFree( GetProcessHeap(), 0, ppd_dir
);
961 if (hadprinter
&& !haddefault
) {
962 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[0].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
963 SetDefaultPrinterW(nameW
);
965 pcupsFreeDests(nrofdests
, dests
);
966 RegCloseKey(hkeyPrinters
);
972 static char *get_queue_name( HANDLE printer
, BOOL
*cups
)
974 WCHAR
*port
, *name
= NULL
;
975 DWORD err
, needed
, type
;
981 err
= WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
);
982 if (err
) return NULL
;
983 err
= RegQueryValueExW( key
, PortW
, 0, &type
, NULL
, &needed
);
985 port
= HeapAlloc( GetProcessHeap(), 0, needed
);
987 RegQueryValueExW( key
, PortW
, 0, &type
, (BYTE
*)port
, &needed
);
989 if (!strncmpW( port
, CUPS_Port
, sizeof(CUPS_Port
) / sizeof(WCHAR
) -1 ))
991 name
= port
+ sizeof(CUPS_Port
) / sizeof(WCHAR
) - 1;
994 else if (!strncmpW( port
, LPR_Port
, sizeof(LPR_Port
) / sizeof(WCHAR
) -1 ))
995 name
= port
+ sizeof(LPR_Port
) / sizeof(WCHAR
) - 1;
998 needed
= WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, NULL
, 0, NULL
, NULL
);
999 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
1000 if(ret
) WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, ret
, needed
, NULL
, NULL
);
1002 HeapFree( GetProcessHeap(), 0, port
);
1009 static void set_ppd_overrides( HANDLE printer
)
1013 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1015 PMPrintSession session
= NULL
;
1016 PMPageFormat format
= NULL
;
1018 CFStringRef paper_name
;
1021 status
= PMCreateSession( &session
);
1022 if (status
) goto end
;
1024 status
= PMCreatePageFormat( &format
);
1025 if (status
) goto end
;
1027 status
= PMSessionDefaultPageFormat( session
, format
);
1028 if (status
) goto end
;
1030 status
= PMGetPageFormatPaper( format
, &paper
);
1031 if (status
) goto end
;
1033 status
= PMPaperGetPPDPaperName( paper
, &paper_name
);
1034 if (status
) goto end
;
1037 range
.length
= CFStringGetLength( paper_name
);
1038 size
= (range
.length
+ 1) * sizeof(WCHAR
);
1040 wstr
= HeapAlloc( GetProcessHeap(), 0, size
);
1041 CFStringGetCharacters( paper_name
, range
, (UniChar
*)wstr
);
1042 wstr
[range
.length
] = 0;
1045 if (format
) PMRelease( format
);
1046 if (session
) PMRelease( session
);
1049 SetPrinterDataExW( printer
, PPD_Overrides
, DefaultPageSize
, REG_SZ
, (BYTE
*)wstr
, size
);
1050 HeapFree( GetProcessHeap(), 0, wstr
);
1053 static BOOL
update_driver( HANDLE printer
)
1056 const WCHAR
*name
= get_opened_printer_name( printer
);
1057 WCHAR
*ppd_dir
, *ppd
;
1060 if (!name
) return FALSE
;
1061 queue_name
= get_queue_name( printer
, &is_cups
);
1062 if (!queue_name
) return FALSE
;
1064 ppd_dir
= get_ppd_dir();
1065 ppd
= get_ppd_filename( ppd_dir
, name
);
1067 #ifdef SONAME_LIBCUPS
1069 ret
= get_cups_ppd( queue_name
, ppd
);
1072 ret
= get_fallback_ppd( queue_name
, ppd
);
1076 TRACE( "updating driver %s\n", debugstr_w( name
) );
1077 ret
= add_printer_driver( name
, ppd
);
1080 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1081 HeapFree( GetProcessHeap(), 0, ppd
);
1082 HeapFree( GetProcessHeap(), 0, queue_name
);
1084 set_ppd_overrides( printer
);
1086 /* call into the driver to update the devmode */
1087 DocumentPropertiesW( 0, printer
, NULL
, NULL
, NULL
, 0 );
1092 static BOOL
PRINTCAP_ParseEntry( const char *pent
, BOOL isfirst
)
1094 PRINTER_INFO_2A pinfo2a
;
1097 char *e
,*s
,*name
,*prettyname
,*devname
;
1098 BOOL ret
= FALSE
, set_default
= FALSE
;
1099 char *port
= NULL
, *env_default
;
1100 HKEY hkeyPrinter
, hkeyPrinters
= NULL
;
1101 WCHAR devnameW
[MAX_PATH
], *ppd_dir
= NULL
, *ppd
;
1102 HANDLE added_printer
;
1104 while (isspace(*pent
)) pent
++;
1105 r
= strchr(pent
,':');
1107 name_len
= r
- pent
;
1109 name_len
= strlen(pent
);
1110 name
= HeapAlloc(GetProcessHeap(), 0, name_len
+ 1);
1111 memcpy(name
, pent
, name_len
);
1112 name
[name_len
] = '\0';
1118 TRACE("name=%s entry=%s\n",name
, pent
);
1120 if(ispunct(*name
)) { /* a tc entry, not a real printer */
1121 TRACE("skipping tc entry\n");
1125 if(strstr(pent
,":server")) { /* server only version so skip */
1126 TRACE("skipping server entry\n");
1130 /* Determine whether this is a postscript printer. */
1133 env_default
= getenv("PRINTER");
1135 /* Get longest name, usually the one at the right for later display. */
1136 while((s
=strchr(prettyname
,'|'))) {
1139 while(isspace(*--e
)) *e
= '\0';
1140 TRACE("\t%s\n", debugstr_a(prettyname
));
1141 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
1142 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
1145 e
= prettyname
+ strlen(prettyname
);
1146 while(isspace(*--e
)) *e
= '\0';
1147 TRACE("\t%s\n", debugstr_a(prettyname
));
1148 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
1150 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1151 * if it is too long, we use it as comment below. */
1152 devname
= prettyname
;
1153 if (strlen(devname
)>=CCHDEVICENAME
-1)
1155 if (strlen(devname
)>=CCHDEVICENAME
-1) {
1160 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
1161 sprintf(port
,"LPR:%s",name
);
1163 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
1165 ERR("Can't create Printers key\n");
1170 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, sizeof(devnameW
) / sizeof(WCHAR
));
1172 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
1173 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
1174 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1176 TRACE("Printer already exists\n");
1177 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
1178 /* flag that the PPD file should be checked for an update */
1179 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
1180 RegCloseKey(hkeyPrinter
);
1182 static CHAR data_type
[] = "RAW",
1183 print_proc
[] = "WinPrint",
1184 comment
[] = "WINEPS Printer using LPR",
1185 params
[] = "<parameters?>",
1186 share_name
[] = "<share name?>",
1187 sep_file
[] = "<sep file?>";
1188 BOOL added_driver
= FALSE
;
1190 if (!ppd_dir
) ppd_dir
= get_ppd_dir();
1191 ppd
= get_ppd_filename( ppd_dir
, devnameW
);
1192 if (get_fallback_ppd( devname
, ppd
))
1194 added_driver
= add_printer_driver( devnameW
, ppd
);
1197 HeapFree( GetProcessHeap(), 0, ppd
);
1198 if (!added_driver
) goto end
;
1200 memset(&pinfo2a
,0,sizeof(pinfo2a
));
1201 pinfo2a
.pPrinterName
= devname
;
1202 pinfo2a
.pDatatype
= data_type
;
1203 pinfo2a
.pPrintProcessor
= print_proc
;
1204 pinfo2a
.pDriverName
= devname
;
1205 pinfo2a
.pComment
= comment
;
1206 pinfo2a
.pLocation
= prettyname
;
1207 pinfo2a
.pPortName
= port
;
1208 pinfo2a
.pParameters
= params
;
1209 pinfo2a
.pShareName
= share_name
;
1210 pinfo2a
.pSepFile
= sep_file
;
1212 added_printer
= AddPrinterA( NULL
, 2, (LPBYTE
)&pinfo2a
);
1213 if (added_printer
) ClosePrinter( added_printer
);
1214 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
1215 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name
), GetLastError() );
1218 if (isfirst
|| set_default
)
1219 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
1222 if (hkeyPrinters
) RegCloseKey( hkeyPrinters
);
1225 RemoveDirectoryW( ppd_dir
);
1226 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1228 HeapFree(GetProcessHeap(), 0, port
);
1229 HeapFree(GetProcessHeap(), 0, name
);
1234 PRINTCAP_LoadPrinters(void) {
1235 BOOL hadprinter
= FALSE
;
1239 BOOL had_bash
= FALSE
;
1241 f
= fopen("/etc/printcap","r");
1245 while(fgets(buf
,sizeof(buf
),f
)) {
1248 end
=strchr(buf
,'\n');
1252 while(isspace(*start
)) start
++;
1253 if(*start
== '#' || *start
== '\0')
1256 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
1257 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1258 HeapFree(GetProcessHeap(),0,pent
);
1262 if (end
&& *--end
== '\\') {
1269 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
1272 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
1278 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1279 HeapFree(GetProcessHeap(),0,pent
);
1285 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
1288 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
1289 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
1291 return ERROR_FILE_NOT_FOUND
;
1294 static inline DWORD
set_reg_devmode( HKEY key
, const WCHAR
*name
, const DEVMODEW
*dm
)
1296 DEVMODEA
*dmA
= DEVMODEdupWtoA( dm
);
1297 DWORD ret
= ERROR_FILE_NOT_FOUND
;
1299 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1300 and we support these drivers. NT writes DEVMODEW so somehow
1301 we'll need to distinguish between these when we support NT
1306 ret
= RegSetValueExW( key
, name
, 0, REG_BINARY
,
1307 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1308 HeapFree( GetProcessHeap(), 0, dmA
);
1314 /******************************************************************
1315 * get_servername_from_name (internal)
1317 * for an external server, a copy of the serverpart from the full name is returned
1320 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1324 WCHAR buffer
[MAX_PATH
];
1327 if (name
== NULL
) return NULL
;
1328 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1330 server
= strdupW(&name
[2]); /* skip over both backslash */
1331 if (server
== NULL
) return NULL
;
1333 /* strip '\' and the printername */
1334 ptr
= strchrW(server
, '\\');
1335 if (ptr
) ptr
[0] = '\0';
1337 TRACE("found %s\n", debugstr_w(server
));
1339 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1340 if (GetComputerNameW(buffer
, &len
)) {
1341 if (lstrcmpW(buffer
, server
) == 0) {
1342 /* The requested Servername is our computername */
1343 HeapFree(GetProcessHeap(), 0, server
);
1350 /******************************************************************
1351 * get_basename_from_name (internal)
1353 * skip over the serverpart from the full name
1356 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1358 if (name
== NULL
) return NULL
;
1359 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1360 /* skip over the servername and search for the following '\' */
1361 name
= strchrW(&name
[2], '\\');
1362 if ((name
) && (name
[1])) {
1363 /* found a separator ('\') followed by a name:
1364 skip over the separator and return the rest */
1369 /* no basename present (we found only a servername) */
1376 static void free_printer_entry( opened_printer_t
*printer
)
1378 /* the queue is shared, so don't free that here */
1379 HeapFree( GetProcessHeap(), 0, printer
->printername
);
1380 HeapFree( GetProcessHeap(), 0, printer
->name
);
1381 HeapFree( GetProcessHeap(), 0, printer
->devmode
);
1382 HeapFree( GetProcessHeap(), 0, printer
);
1385 /******************************************************************
1386 * get_opened_printer_entry
1387 * Get the first place empty in the opened printer table
1390 * - pDefault is ignored
1392 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1394 UINT_PTR handle
= nb_printer_handles
, i
;
1395 jobqueue_t
*queue
= NULL
;
1396 opened_printer_t
*printer
= NULL
;
1398 LPCWSTR printername
;
1400 if ((backend
== NULL
) && !load_backend()) return NULL
;
1402 servername
= get_servername_from_name(name
);
1404 FIXME("server %s not supported\n", debugstr_w(servername
));
1405 HeapFree(GetProcessHeap(), 0, servername
);
1406 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1410 printername
= get_basename_from_name(name
);
1411 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1413 /* an empty printername is invalid */
1414 if (printername
&& (!printername
[0])) {
1415 SetLastError(ERROR_INVALID_PARAMETER
);
1419 EnterCriticalSection(&printer_handles_cs
);
1421 for (i
= 0; i
< nb_printer_handles
; i
++)
1423 if (!printer_handles
[i
])
1425 if(handle
== nb_printer_handles
)
1430 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1431 queue
= printer_handles
[i
]->queue
;
1435 if (handle
>= nb_printer_handles
)
1437 opened_printer_t
**new_array
;
1438 if (printer_handles
)
1439 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1440 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1442 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1443 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1450 printer_handles
= new_array
;
1451 nb_printer_handles
+= 16;
1454 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1460 /* get a printer handle from the backend */
1461 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
1466 /* clone the base name. This is NULL for the printserver */
1467 printer
->printername
= strdupW(printername
);
1469 /* clone the full name */
1470 printer
->name
= strdupW(name
);
1471 if (name
&& (!printer
->name
)) {
1476 if (pDefault
&& pDefault
->pDevMode
)
1477 printer
->devmode
= dup_devmode( pDefault
->pDevMode
);
1480 printer
->queue
= queue
;
1483 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1484 if (!printer
->queue
) {
1488 list_init(&printer
->queue
->jobs
);
1489 printer
->queue
->ref
= 0;
1491 InterlockedIncrement(&printer
->queue
->ref
);
1493 printer_handles
[handle
] = printer
;
1496 LeaveCriticalSection(&printer_handles_cs
);
1497 if (!handle
&& printer
) {
1498 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1499 free_printer_entry( printer
);
1502 return (HANDLE
)handle
;
1505 static void old_printer_check( BOOL delete_phase
)
1507 PRINTER_INFO_5W
* pi
;
1508 DWORD needed
, type
, num
, delete, i
, size
;
1509 const DWORD one
= 1;
1513 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1514 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return;
1516 pi
= HeapAlloc( GetProcessHeap(), 0, needed
);
1517 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
);
1518 for (i
= 0; i
< num
; i
++)
1520 if (strncmpW( pi
[i
].pPortName
, CUPS_Port
, strlenW(CUPS_Port
) ) &&
1521 strncmpW( pi
[i
].pPortName
, LPR_Port
, strlenW(LPR_Port
) ))
1524 if (open_printer_reg_key( pi
[i
].pPrinterName
, &key
)) continue;
1528 RegSetValueExW( key
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&one
, sizeof(one
) );
1534 size
= sizeof( delete );
1535 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&delete, &size
);
1539 TRACE( "Deleting old printer %s\n", debugstr_w(pi
[i
].pPrinterName
) );
1540 if (OpenPrinterW( pi
[i
].pPrinterName
, &hprn
, NULL
))
1542 DeletePrinter( hprn
);
1543 ClosePrinter( hprn
);
1545 DeletePrinterDriverExW( NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0 );
1549 HeapFree(GetProcessHeap(), 0, pi
);
1552 static const WCHAR winspool_mutex_name
[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1553 'M','U','T','E','X','_','_','\0'};
1554 static HANDLE init_mutex
;
1556 void WINSPOOL_LoadSystemPrinters(void)
1558 HKEY hkey
, hkeyPrinters
;
1559 DWORD needed
, num
, i
;
1560 WCHAR PrinterName
[256];
1563 /* FIXME: The init code should be moved to spoolsv.exe */
1564 init_mutex
= CreateMutexW( NULL
, TRUE
, winspool_mutex_name
);
1567 ERR( "Failed to create mutex\n" );
1570 if (GetLastError() == ERROR_ALREADY_EXISTS
)
1572 WaitForSingleObject( init_mutex
, INFINITE
);
1573 ReleaseMutex( init_mutex
);
1574 TRACE( "Init already done\n" );
1578 /* This ensures that all printer entries have a valid Name value. If causes
1579 problems later if they don't. If one is found to be missed we create one
1580 and set it equal to the name of the key */
1581 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1582 if(RegQueryInfoKeyW(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1583 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1584 for(i
= 0; i
< num
; i
++) {
1585 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1586 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1587 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1588 set_reg_szW(hkey
, NameW
, PrinterName
);
1595 RegCloseKey(hkeyPrinters
);
1598 old_printer_check( FALSE
);
1600 #ifdef SONAME_LIBCUPS
1601 done
= CUPS_LoadPrinters();
1604 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1605 PRINTCAP_LoadPrinters();
1607 old_printer_check( TRUE
);
1609 ReleaseMutex( init_mutex
);
1613 /******************************************************************
1616 * Get the pointer to the specified job.
1617 * Should hold the printer_handles_cs before calling.
1619 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1621 opened_printer_t
*printer
= get_opened_printer(hprn
);
1624 if(!printer
) return NULL
;
1625 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1627 if(job
->job_id
== JobId
)
1633 /***********************************************************
1636 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1639 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1642 Formname
= (dmA
->dmSize
> off_formname
);
1643 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1644 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1645 dmW
->dmDeviceName
, CCHDEVICENAME
);
1647 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1648 dmA
->dmSize
- CCHDEVICENAME
);
1650 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1651 off_formname
- CCHDEVICENAME
);
1652 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1653 dmW
->dmFormName
, CCHFORMNAME
);
1654 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1655 (off_formname
+ CCHFORMNAME
));
1658 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1659 dmA
->dmDriverExtra
);
1663 /******************************************************************
1664 * convert_printerinfo_W_to_A [internal]
1667 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1668 DWORD level
, DWORD outlen
, DWORD numentries
)
1674 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1676 len
= pi_sizeof
[level
] * numentries
;
1677 ptr
= (LPSTR
) out
+ len
;
1680 /* copy the numbers of all PRINTER_INFO_* first */
1681 memcpy(out
, pPrintersW
, len
);
1683 while (id
< numentries
) {
1687 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1688 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1690 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1691 if (piW
->pDescription
) {
1692 piA
->pDescription
= ptr
;
1693 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1694 ptr
, outlen
, NULL
, NULL
);
1700 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1701 ptr
, outlen
, NULL
, NULL
);
1705 if (piW
->pComment
) {
1706 piA
->pComment
= ptr
;
1707 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1708 ptr
, outlen
, NULL
, NULL
);
1717 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1718 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1721 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1722 if (piW
->pServerName
) {
1723 piA
->pServerName
= ptr
;
1724 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1725 ptr
, outlen
, NULL
, NULL
);
1729 if (piW
->pPrinterName
) {
1730 piA
->pPrinterName
= ptr
;
1731 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1732 ptr
, outlen
, NULL
, NULL
);
1736 if (piW
->pShareName
) {
1737 piA
->pShareName
= ptr
;
1738 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1739 ptr
, outlen
, NULL
, NULL
);
1743 if (piW
->pPortName
) {
1744 piA
->pPortName
= ptr
;
1745 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1746 ptr
, outlen
, NULL
, NULL
);
1750 if (piW
->pDriverName
) {
1751 piA
->pDriverName
= ptr
;
1752 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1753 ptr
, outlen
, NULL
, NULL
);
1757 if (piW
->pComment
) {
1758 piA
->pComment
= ptr
;
1759 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1760 ptr
, outlen
, NULL
, NULL
);
1764 if (piW
->pLocation
) {
1765 piA
->pLocation
= ptr
;
1766 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1767 ptr
, outlen
, NULL
, NULL
);
1772 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1774 /* align DEVMODEA to a DWORD boundary */
1775 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1779 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1780 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1781 memcpy(ptr
, dmA
, len
);
1782 HeapFree(GetProcessHeap(), 0, dmA
);
1788 if (piW
->pSepFile
) {
1789 piA
->pSepFile
= ptr
;
1790 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1791 ptr
, outlen
, NULL
, NULL
);
1795 if (piW
->pPrintProcessor
) {
1796 piA
->pPrintProcessor
= ptr
;
1797 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1798 ptr
, outlen
, NULL
, NULL
);
1802 if (piW
->pDatatype
) {
1803 piA
->pDatatype
= ptr
;
1804 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1805 ptr
, outlen
, NULL
, NULL
);
1809 if (piW
->pParameters
) {
1810 piA
->pParameters
= ptr
;
1811 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1812 ptr
, outlen
, NULL
, NULL
);
1816 if (piW
->pSecurityDescriptor
) {
1817 piA
->pSecurityDescriptor
= NULL
;
1818 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1825 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1826 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1828 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1830 if (piW
->pPrinterName
) {
1831 piA
->pPrinterName
= ptr
;
1832 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1833 ptr
, outlen
, NULL
, NULL
);
1837 if (piW
->pServerName
) {
1838 piA
->pServerName
= ptr
;
1839 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1840 ptr
, outlen
, NULL
, NULL
);
1849 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1850 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1852 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1854 if (piW
->pPrinterName
) {
1855 piA
->pPrinterName
= ptr
;
1856 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1857 ptr
, outlen
, NULL
, NULL
);
1861 if (piW
->pPortName
) {
1862 piA
->pPortName
= ptr
;
1863 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1864 ptr
, outlen
, NULL
, NULL
);
1871 case 6: /* 6A and 6W are the same structure */
1876 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1877 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1879 TRACE("(%u) #%u\n", level
, id
);
1880 if (piW
->pszObjectGUID
) {
1881 piA
->pszObjectGUID
= ptr
;
1882 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1883 ptr
, outlen
, NULL
, NULL
);
1893 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1894 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1897 TRACE("(%u) #%u\n", level
, id
);
1898 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1900 /* align DEVMODEA to a DWORD boundary */
1901 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1905 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1906 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1907 memcpy(ptr
, dmA
, len
);
1908 HeapFree(GetProcessHeap(), 0, dmA
);
1918 FIXME("for level %u\n", level
);
1920 pPrintersW
+= pi_sizeof
[level
];
1921 out
+= pi_sizeof
[level
];
1926 /******************************************************************
1927 * convert_driverinfo_W_to_A [internal]
1930 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1931 DWORD level
, DWORD outlen
, DWORD numentries
)
1937 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1939 len
= di_sizeof
[level
] * numentries
;
1940 ptr
= (LPSTR
) out
+ len
;
1943 /* copy the numbers of all PRINTER_INFO_* first */
1944 memcpy(out
, pDriversW
, len
);
1946 #define COPY_STRING(fld) \
1949 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1950 ptr += len; outlen -= len;\
1952 #define COPY_MULTIZ_STRING(fld) \
1953 { LPWSTR p = diW->fld; if (p){ \
1956 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1957 ptr += len; outlen -= len; p += len;\
1959 while(len > 1 && outlen > 0); \
1962 while (id
< numentries
)
1968 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
1969 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
1971 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1978 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
1979 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
1981 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1984 COPY_STRING(pEnvironment
);
1985 COPY_STRING(pDriverPath
);
1986 COPY_STRING(pDataFile
);
1987 COPY_STRING(pConfigFile
);
1992 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
1993 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
1995 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1998 COPY_STRING(pEnvironment
);
1999 COPY_STRING(pDriverPath
);
2000 COPY_STRING(pDataFile
);
2001 COPY_STRING(pConfigFile
);
2002 COPY_STRING(pHelpFile
);
2003 COPY_MULTIZ_STRING(pDependentFiles
);
2004 COPY_STRING(pMonitorName
);
2005 COPY_STRING(pDefaultDataType
);
2010 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
2011 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
2013 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2016 COPY_STRING(pEnvironment
);
2017 COPY_STRING(pDriverPath
);
2018 COPY_STRING(pDataFile
);
2019 COPY_STRING(pConfigFile
);
2020 COPY_STRING(pHelpFile
);
2021 COPY_MULTIZ_STRING(pDependentFiles
);
2022 COPY_STRING(pMonitorName
);
2023 COPY_STRING(pDefaultDataType
);
2024 COPY_MULTIZ_STRING(pszzPreviousNames
);
2029 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
2030 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
2032 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2035 COPY_STRING(pEnvironment
);
2036 COPY_STRING(pDriverPath
);
2037 COPY_STRING(pDataFile
);
2038 COPY_STRING(pConfigFile
);
2043 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
2044 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
2046 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2049 COPY_STRING(pEnvironment
);
2050 COPY_STRING(pDriverPath
);
2051 COPY_STRING(pDataFile
);
2052 COPY_STRING(pConfigFile
);
2053 COPY_STRING(pHelpFile
);
2054 COPY_MULTIZ_STRING(pDependentFiles
);
2055 COPY_STRING(pMonitorName
);
2056 COPY_STRING(pDefaultDataType
);
2057 COPY_MULTIZ_STRING(pszzPreviousNames
);
2058 COPY_STRING(pszMfgName
);
2059 COPY_STRING(pszOEMUrl
);
2060 COPY_STRING(pszHardwareID
);
2061 COPY_STRING(pszProvider
);
2066 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
2067 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
2069 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2072 COPY_STRING(pEnvironment
);
2073 COPY_STRING(pDriverPath
);
2074 COPY_STRING(pDataFile
);
2075 COPY_STRING(pConfigFile
);
2076 COPY_STRING(pHelpFile
);
2077 COPY_MULTIZ_STRING(pDependentFiles
);
2078 COPY_STRING(pMonitorName
);
2079 COPY_STRING(pDefaultDataType
);
2080 COPY_MULTIZ_STRING(pszzPreviousNames
);
2081 COPY_STRING(pszMfgName
);
2082 COPY_STRING(pszOEMUrl
);
2083 COPY_STRING(pszHardwareID
);
2084 COPY_STRING(pszProvider
);
2085 COPY_STRING(pszPrintProcessor
);
2086 COPY_STRING(pszVendorSetup
);
2087 COPY_MULTIZ_STRING(pszzColorProfiles
);
2088 COPY_STRING(pszInfPath
);
2089 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
2095 FIXME("for level %u\n", level
);
2098 pDriversW
+= di_sizeof
[level
];
2099 out
+= di_sizeof
[level
];
2104 #undef COPY_MULTIZ_STRING
2108 /***********************************************************
2111 static void *printer_info_AtoW( const void *data
, DWORD level
)
2114 UNICODE_STRING usBuffer
;
2116 if (!data
) return NULL
;
2118 if (level
< 1 || level
> 9) return NULL
;
2120 ret
= HeapAlloc( GetProcessHeap(), 0, pi_sizeof
[level
] );
2121 if (!ret
) return NULL
;
2123 memcpy( ret
, data
, pi_sizeof
[level
] ); /* copy everything first */
2129 const PRINTER_INFO_2A
*piA
= (const PRINTER_INFO_2A
*)data
;
2130 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)ret
;
2132 piW
->pServerName
= asciitounicode( &usBuffer
, piA
->pServerName
);
2133 piW
->pPrinterName
= asciitounicode( &usBuffer
, piA
->pPrinterName
);
2134 piW
->pShareName
= asciitounicode( &usBuffer
, piA
->pShareName
);
2135 piW
->pPortName
= asciitounicode( &usBuffer
, piA
->pPortName
);
2136 piW
->pDriverName
= asciitounicode( &usBuffer
, piA
->pDriverName
);
2137 piW
->pComment
= asciitounicode( &usBuffer
, piA
->pComment
);
2138 piW
->pLocation
= asciitounicode( &usBuffer
, piA
->pLocation
);
2139 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2140 piW
->pSepFile
= asciitounicode( &usBuffer
, piA
->pSepFile
);
2141 piW
->pPrintProcessor
= asciitounicode( &usBuffer
, piA
->pPrintProcessor
);
2142 piW
->pDatatype
= asciitounicode( &usBuffer
, piA
->pDatatype
);
2143 piW
->pParameters
= asciitounicode( &usBuffer
, piA
->pParameters
);
2150 const PRINTER_INFO_9A
*piA
= (const PRINTER_INFO_9A
*)data
;
2151 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)ret
;
2153 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2158 FIXME( "Unhandled level %d\n", level
);
2159 HeapFree( GetProcessHeap(), 0, ret
);
2166 /***********************************************************
2169 static void free_printer_info( void *data
, DWORD level
)
2177 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)data
;
2179 HeapFree( GetProcessHeap(), 0, piW
->pServerName
);
2180 HeapFree( GetProcessHeap(), 0, piW
->pPrinterName
);
2181 HeapFree( GetProcessHeap(), 0, piW
->pShareName
);
2182 HeapFree( GetProcessHeap(), 0, piW
->pPortName
);
2183 HeapFree( GetProcessHeap(), 0, piW
->pDriverName
);
2184 HeapFree( GetProcessHeap(), 0, piW
->pComment
);
2185 HeapFree( GetProcessHeap(), 0, piW
->pLocation
);
2186 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2187 HeapFree( GetProcessHeap(), 0, piW
->pSepFile
);
2188 HeapFree( GetProcessHeap(), 0, piW
->pPrintProcessor
);
2189 HeapFree( GetProcessHeap(), 0, piW
->pDatatype
);
2190 HeapFree( GetProcessHeap(), 0, piW
->pParameters
);
2197 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)data
;
2199 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2204 FIXME( "Unhandled level %d\n", level
);
2207 HeapFree( GetProcessHeap(), 0, data
);
2211 /******************************************************************
2212 * DeviceCapabilities [WINSPOOL.@]
2213 * DeviceCapabilitiesA [WINSPOOL.@]
2216 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
2217 LPSTR pOutput
, LPDEVMODEA lpdm
)
2221 if (!GDI_CallDeviceCapabilities16
)
2223 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2225 if (!GDI_CallDeviceCapabilities16
) return -1;
2227 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
2229 /* If DC_PAPERSIZE map POINT16s to POINTs */
2230 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
2231 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
2232 POINT
*pt
= (POINT
*)pOutput
;
2234 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
2235 for(i
= 0; i
< ret
; i
++, pt
++)
2240 HeapFree( GetProcessHeap(), 0, tmp
);
2246 /*****************************************************************************
2247 * DeviceCapabilitiesW [WINSPOOL.@]
2249 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2252 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
2253 WORD fwCapability
, LPWSTR pOutput
,
2254 const DEVMODEW
*pDevMode
)
2256 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
2257 LPSTR pDeviceA
= strdupWtoA(pDevice
);
2258 LPSTR pPortA
= strdupWtoA(pPort
);
2261 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
2262 fwCapability
== DC_FILEDEPENDENCIES
||
2263 fwCapability
== DC_PAPERNAMES
)) {
2264 /* These need A -> W translation */
2267 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
2271 switch(fwCapability
) {
2276 case DC_FILEDEPENDENCIES
:
2280 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
2281 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
2283 for(i
= 0; i
< ret
; i
++)
2284 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
2285 pOutput
+ (i
* size
), size
);
2286 HeapFree(GetProcessHeap(), 0, pOutputA
);
2288 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
2289 (LPSTR
)pOutput
, dmA
);
2291 HeapFree(GetProcessHeap(),0,pPortA
);
2292 HeapFree(GetProcessHeap(),0,pDeviceA
);
2293 HeapFree(GetProcessHeap(),0,dmA
);
2297 /******************************************************************
2298 * DocumentPropertiesA [WINSPOOL.@]
2300 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2302 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
2303 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
2304 LPDEVMODEA pDevModeInput
,DWORD fMode
)
2306 LPSTR lpName
= pDeviceName
;
2307 static CHAR port
[] = "LPT1:";
2310 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2311 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
2315 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2317 ERR("no name from hPrinter?\n");
2318 SetLastError(ERROR_INVALID_HANDLE
);
2321 lpName
= strdupWtoA(lpNameW
);
2324 if (!GDI_CallExtDeviceMode16
)
2326 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2328 if (!GDI_CallExtDeviceMode16
) {
2329 ERR("No CallExtDeviceMode16?\n");
2333 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
2334 pDevModeInput
, NULL
, fMode
);
2337 HeapFree(GetProcessHeap(),0,lpName
);
2342 /*****************************************************************************
2343 * DocumentPropertiesW (WINSPOOL.@)
2345 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2347 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
2349 LPDEVMODEW pDevModeOutput
,
2350 LPDEVMODEW pDevModeInput
, DWORD fMode
)
2353 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
2354 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
2355 LPDEVMODEA pDevModeOutputA
= NULL
;
2358 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2359 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
2361 if(pDevModeOutput
) {
2362 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
2363 if(ret
< 0) return ret
;
2364 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
2366 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
2367 pDevModeInputA
, fMode
);
2368 if(pDevModeOutput
) {
2369 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
2370 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
2372 if(fMode
== 0 && ret
> 0)
2373 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2374 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
2375 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
2379 /*****************************************************************************
2380 * IsValidDevmodeA [WINSPOOL.@]
2382 * Validate a DEVMODE structure and fix errors if possible.
2385 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA
*pDevMode
, SIZE_T size
)
2387 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2395 /*****************************************************************************
2396 * IsValidDevmodeW [WINSPOOL.@]
2398 * Validate a DEVMODE structure and fix errors if possible.
2401 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW
*pDevMode
, SIZE_T size
)
2403 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2411 /******************************************************************
2412 * OpenPrinterA [WINSPOOL.@]
2417 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
2418 LPPRINTER_DEFAULTSA pDefault
)
2420 UNICODE_STRING lpPrinterNameW
;
2421 UNICODE_STRING usBuffer
;
2422 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
2423 PWSTR pwstrPrinterNameW
;
2426 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
2429 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
2430 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
2431 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
2432 pDefaultW
= &DefaultW
;
2434 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
2436 RtlFreeUnicodeString(&usBuffer
);
2437 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
2439 RtlFreeUnicodeString(&lpPrinterNameW
);
2443 /******************************************************************
2444 * OpenPrinterW [WINSPOOL.@]
2446 * Open a Printer / Printserver or a Printer-Object
2449 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2450 * phPrinter [O] The resulting Handle is stored here
2451 * pDefault [I] PTR to Default Printer Settings or NULL
2458 * lpPrinterName is one of:
2459 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2460 *| Printer: "PrinterName"
2461 *| Printer-Object: "PrinterName,Job xxx"
2462 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2463 *| XcvPort: "Servername,XcvPort PortName"
2466 *| Printer-Object not supported
2467 *| pDefaults is ignored
2470 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2473 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2476 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2477 SetLastError(ERROR_INVALID_PARAMETER
);
2481 /* Get the unique handle of the printer or Printserver */
2482 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2487 DWORD deleting
= 0, size
= sizeof( deleting
), type
;
2489 WINSPOOL_GetOpenedPrinterRegKey( *phPrinter
, &key
);
2490 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&deleting
, &size
);
2491 WaitForSingleObject( init_mutex
, INFINITE
);
2492 status
= get_dword_from_reg( key
, StatusW
);
2493 set_reg_DWORD( key
, StatusW
, status
& ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
2494 ReleaseMutex( init_mutex
);
2495 if (!deleting
&& (status
& PRINTER_STATUS_DRIVER_UPDATE_NEEDED
))
2496 update_driver( *phPrinter
);
2500 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2501 return (*phPrinter
!= 0);
2504 /******************************************************************
2505 * AddMonitorA [WINSPOOL.@]
2510 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2512 LPWSTR nameW
= NULL
;
2515 LPMONITOR_INFO_2A mi2a
;
2516 MONITOR_INFO_2W mi2w
;
2518 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2519 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2520 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2521 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2522 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2525 SetLastError(ERROR_INVALID_LEVEL
);
2529 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2535 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2536 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2537 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2540 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2542 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2543 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2544 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2546 if (mi2a
->pEnvironment
) {
2547 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2548 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2549 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2551 if (mi2a
->pDLLName
) {
2552 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2553 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2554 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2557 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2559 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2560 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2561 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2563 HeapFree(GetProcessHeap(), 0, nameW
);
2567 /******************************************************************************
2568 * AddMonitorW [WINSPOOL.@]
2570 * Install a Printmonitor
2573 * pName [I] Servername or NULL (local Computer)
2574 * Level [I] Structure-Level (Must be 2)
2575 * pMonitors [I] PTR to MONITOR_INFO_2
2582 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2585 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2587 LPMONITOR_INFO_2W mi2w
;
2589 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2590 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2591 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2592 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2593 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2595 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2598 SetLastError(ERROR_INVALID_LEVEL
);
2602 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2607 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2610 /******************************************************************
2611 * DeletePrinterDriverA [WINSPOOL.@]
2614 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2616 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2619 /******************************************************************
2620 * DeletePrinterDriverW [WINSPOOL.@]
2623 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2625 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2628 /******************************************************************
2629 * DeleteMonitorA [WINSPOOL.@]
2631 * See DeleteMonitorW.
2634 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2636 LPWSTR nameW
= NULL
;
2637 LPWSTR EnvironmentW
= NULL
;
2638 LPWSTR MonitorNameW
= NULL
;
2643 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2644 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2645 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2649 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2650 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2651 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2654 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2655 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2656 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2659 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2661 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2662 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2663 HeapFree(GetProcessHeap(), 0, nameW
);
2667 /******************************************************************
2668 * DeleteMonitorW [WINSPOOL.@]
2670 * Delete a specific Printmonitor from a Printing-Environment
2673 * pName [I] Servername or NULL (local Computer)
2674 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2675 * pMonitorName [I] Name of the Monitor, that should be deleted
2682 * pEnvironment is ignored in Windows for the local Computer.
2685 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2688 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2689 debugstr_w(pMonitorName
));
2691 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2693 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2697 /******************************************************************
2698 * DeletePortA [WINSPOOL.@]
2703 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2705 LPWSTR nameW
= NULL
;
2706 LPWSTR portW
= NULL
;
2710 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2712 /* convert servername to unicode */
2714 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2715 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2716 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2719 /* convert portname to unicode */
2721 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2722 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2723 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2726 res
= DeletePortW(nameW
, hWnd
, portW
);
2727 HeapFree(GetProcessHeap(), 0, nameW
);
2728 HeapFree(GetProcessHeap(), 0, portW
);
2732 /******************************************************************
2733 * DeletePortW [WINSPOOL.@]
2735 * Delete a specific Port
2738 * pName [I] Servername or NULL (local Computer)
2739 * hWnd [I] Handle to parent Window for the Dialog-Box
2740 * pPortName [I] Name of the Port, that should be deleted
2747 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2749 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2751 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2754 SetLastError(RPC_X_NULL_REF_POINTER
);
2758 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2761 /******************************************************************************
2762 * WritePrinter [WINSPOOL.@]
2764 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2766 opened_printer_t
*printer
;
2769 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2771 EnterCriticalSection(&printer_handles_cs
);
2772 printer
= get_opened_printer(hPrinter
);
2775 SetLastError(ERROR_INVALID_HANDLE
);
2781 SetLastError(ERROR_SPL_NO_STARTDOC
);
2785 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2787 LeaveCriticalSection(&printer_handles_cs
);
2791 /*****************************************************************************
2792 * AddFormA [WINSPOOL.@]
2794 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2796 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2800 /*****************************************************************************
2801 * AddFormW [WINSPOOL.@]
2803 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2805 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2809 /*****************************************************************************
2810 * AddJobA [WINSPOOL.@]
2812 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2815 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2819 SetLastError(ERROR_INVALID_LEVEL
);
2823 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2826 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2827 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2828 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2829 if(*pcbNeeded
> cbBuf
) {
2830 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2833 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2834 addjobA
->JobId
= addjobW
->JobId
;
2835 addjobA
->Path
= (char *)(addjobA
+ 1);
2836 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2842 /*****************************************************************************
2843 * AddJobW [WINSPOOL.@]
2845 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2847 opened_printer_t
*printer
;
2850 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2851 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2852 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2854 ADDJOB_INFO_1W
*addjob
;
2856 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2858 EnterCriticalSection(&printer_handles_cs
);
2860 printer
= get_opened_printer(hPrinter
);
2863 SetLastError(ERROR_INVALID_HANDLE
);
2868 SetLastError(ERROR_INVALID_LEVEL
);
2872 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2876 job
->job_id
= InterlockedIncrement(&next_job_id
);
2878 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2879 if(path
[len
- 1] != '\\')
2881 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2882 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2884 len
= strlenW(filename
);
2885 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2886 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2887 job
->portname
= NULL
;
2888 job
->document_title
= strdupW(default_doc_title
);
2889 job
->printer_name
= strdupW(printer
->name
);
2890 job
->devmode
= dup_devmode( printer
->devmode
);
2891 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2893 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2894 if(*pcbNeeded
<= cbBuf
) {
2895 addjob
= (ADDJOB_INFO_1W
*)pData
;
2896 addjob
->JobId
= job
->job_id
;
2897 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2898 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2901 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2904 LeaveCriticalSection(&printer_handles_cs
);
2908 /*****************************************************************************
2909 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2911 * Return the PATH for the Print-Processors
2913 * See GetPrintProcessorDirectoryW.
2917 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2918 DWORD level
, LPBYTE Info
,
2919 DWORD cbBuf
, LPDWORD pcbNeeded
)
2921 LPWSTR serverW
= NULL
;
2926 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2927 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2931 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2932 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2933 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2937 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2938 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2939 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2942 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2943 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2945 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2948 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2949 cbBuf
, NULL
, NULL
) > 0;
2952 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2953 HeapFree(GetProcessHeap(), 0, envW
);
2954 HeapFree(GetProcessHeap(), 0, serverW
);
2958 /*****************************************************************************
2959 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2961 * Return the PATH for the Print-Processors
2964 * server [I] Servername (NT only) or NULL (local Computer)
2965 * env [I] Printing-Environment (see below) or NULL (Default)
2966 * level [I] Structure-Level (must be 1)
2967 * Info [O] PTR to Buffer that receives the Result
2968 * cbBuf [I] Size of Buffer at "Info"
2969 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2970 * required for the Buffer at "Info"
2973 * Success: TRUE and in pcbNeeded the Bytes used in Info
2974 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2975 * if cbBuf is too small
2977 * Native Values returned in Info on Success:
2978 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2979 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2980 *| win9x(Windows 4.0): "%winsysdir%"
2982 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2985 * Only NULL or "" is supported for server
2988 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2989 DWORD level
, LPBYTE Info
,
2990 DWORD cbBuf
, LPDWORD pcbNeeded
)
2993 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
2994 Info
, cbBuf
, pcbNeeded
);
2996 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2999 /* (Level != 1) is ignored in win9x */
3000 SetLastError(ERROR_INVALID_LEVEL
);
3004 if (pcbNeeded
== NULL
) {
3005 /* (pcbNeeded == NULL) is ignored in win9x */
3006 SetLastError(RPC_X_NULL_REF_POINTER
);
3010 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
3013 /*****************************************************************************
3014 * WINSPOOL_OpenDriverReg [internal]
3016 * opens the registry for the printer drivers depending on the given input
3017 * variable pEnvironment
3020 * the opened hkey on success
3023 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
3027 const printenv_t
* env
;
3029 TRACE("(%s)\n", debugstr_w(pEnvironment
));
3031 env
= validate_envW(pEnvironment
);
3032 if (!env
) return NULL
;
3034 buffer
= HeapAlloc( GetProcessHeap(), 0,
3035 (strlenW(DriversW
) + strlenW(env
->envname
) +
3036 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
3038 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
3039 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
3040 HeapFree(GetProcessHeap(), 0, buffer
);
3045 /*****************************************************************************
3046 * set_devices_and_printerports [internal]
3048 * set the [Devices] and [PrinterPorts] entries for a printer.
3051 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
3053 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
3057 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
3059 /* FIXME: the driver must change to "winspool" */
3060 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
3062 lstrcpyW(devline
, driver_nt
);
3063 lstrcatW(devline
, commaW
);
3064 lstrcatW(devline
, pi
->pPortName
);
3066 TRACE("using %s\n", debugstr_w(devline
));
3067 WriteProfileStringW(devicesW
, pi
->pPrinterName
, devline
);
3068 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
3069 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3070 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3074 lstrcatW(devline
, timeout_15_45
);
3075 WriteProfileStringW(PrinterPortsW
, pi
->pPrinterName
, devline
);
3076 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
3077 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3078 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3081 HeapFree(GetProcessHeap(), 0, devline
);
3085 /*****************************************************************************
3086 * AddPrinterW [WINSPOOL.@]
3088 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3090 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
3093 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
3096 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
3099 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
3100 SetLastError(ERROR_INVALID_PARAMETER
);
3104 ERR("Level = %d, unsupported!\n", Level
);
3105 SetLastError(ERROR_INVALID_LEVEL
);
3109 SetLastError(ERROR_INVALID_PARAMETER
);
3112 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3114 ERR("Can't create Printers key\n");
3117 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
3118 if (!RegQueryValueW(hkeyPrinter
, AttributesW
, NULL
, NULL
)) {
3119 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
3120 RegCloseKey(hkeyPrinter
);
3121 RegCloseKey(hkeyPrinters
);
3124 RegCloseKey(hkeyPrinter
);
3126 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
3128 ERR("Can't create Drivers key\n");
3129 RegCloseKey(hkeyPrinters
);
3132 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
3134 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
3135 RegCloseKey(hkeyPrinters
);
3136 RegCloseKey(hkeyDrivers
);
3137 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
3140 RegCloseKey(hkeyDriver
);
3141 RegCloseKey(hkeyDrivers
);
3143 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
3144 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
3145 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
3146 RegCloseKey(hkeyPrinters
);
3150 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
3152 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
3153 SetLastError(ERROR_INVALID_PRINTER_NAME
);
3154 RegCloseKey(hkeyPrinters
);
3158 set_devices_and_printerports(pi
);
3160 set_reg_DWORD(hkeyPrinter
, AttributesW
, pi
->Attributes
);
3161 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
3162 set_reg_DWORD(hkeyPrinter
, Default_PriorityW
, pi
->DefaultPriority
);
3163 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
3164 set_reg_DWORD(hkeyPrinter
, dnsTimeoutW
, 0);
3165 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
3166 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
3167 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
3168 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
3169 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
3170 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
3171 set_reg_DWORD(hkeyPrinter
, PriorityW
, pi
->Priority
);
3172 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
3173 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
3174 set_reg_DWORD(hkeyPrinter
, StartTimeW
, pi
->StartTime
);
3175 set_reg_DWORD(hkeyPrinter
, StatusW
, pi
->Status
);
3176 set_reg_DWORD(hkeyPrinter
, txTimeoutW
, 0);
3177 set_reg_DWORD(hkeyPrinter
, UntilTimeW
, pi
->UntilTime
);
3179 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
3183 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
3184 size
= sizeof(DEVMODEW
);
3190 dm
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3192 if (DocumentPropertiesW(0, 0, pi
->pPrinterName
, dm
, NULL
, DM_OUT_BUFFER
) < 0)
3194 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
3195 HeapFree( GetProcessHeap(), 0, dm
);
3200 /* set devmode to printer name */
3201 lstrcpynW( dm
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
3205 set_reg_devmode( hkeyPrinter
, Default_DevModeW
, dm
);
3206 if (!pi
->pDevMode
) HeapFree( GetProcessHeap(), 0, dm
);
3208 RegCloseKey(hkeyPrinter
);
3209 RegCloseKey(hkeyPrinters
);
3210 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
3211 ERR("OpenPrinter failing\n");
3217 /*****************************************************************************
3218 * AddPrinterA [WINSPOOL.@]
3220 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3222 UNICODE_STRING pNameW
;
3224 PRINTER_INFO_2W
*piW
;
3225 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
3228 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
3230 ERR("Level = %d, unsupported!\n", Level
);
3231 SetLastError(ERROR_INVALID_LEVEL
);
3234 pwstrNameW
= asciitounicode(&pNameW
,pName
);
3235 piW
= printer_info_AtoW( piA
, Level
);
3237 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
3239 free_printer_info( piW
, Level
);
3240 RtlFreeUnicodeString(&pNameW
);
3245 /*****************************************************************************
3246 * ClosePrinter [WINSPOOL.@]
3248 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
3250 UINT_PTR i
= (UINT_PTR
)hPrinter
;
3251 opened_printer_t
*printer
= NULL
;
3254 TRACE("(%p)\n", hPrinter
);
3256 EnterCriticalSection(&printer_handles_cs
);
3258 if ((i
> 0) && (i
<= nb_printer_handles
))
3259 printer
= printer_handles
[i
- 1];
3264 struct list
*cursor
, *cursor2
;
3266 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
3268 if (printer
->backend_printer
) {
3269 backend
->fpClosePrinter(printer
->backend_printer
);
3273 EndDocPrinter(hPrinter
);
3275 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
3277 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
3279 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
3280 ScheduleJob(hPrinter
, job
->job_id
);
3282 HeapFree(GetProcessHeap(), 0, printer
->queue
);
3285 free_printer_entry( printer
);
3286 printer_handles
[i
- 1] = NULL
;
3289 LeaveCriticalSection(&printer_handles_cs
);
3293 /*****************************************************************************
3294 * DeleteFormA [WINSPOOL.@]
3296 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3298 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3302 /*****************************************************************************
3303 * DeleteFormW [WINSPOOL.@]
3305 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3307 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3311 /*****************************************************************************
3312 * DeletePrinter [WINSPOOL.@]
3314 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3316 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3317 HKEY hkeyPrinters
, hkey
;
3318 WCHAR def
[MAX_PATH
];
3319 DWORD size
= sizeof( def
) / sizeof( def
[0] );
3322 SetLastError(ERROR_INVALID_HANDLE
);
3325 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3326 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3327 RegCloseKey(hkeyPrinters
);
3329 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3330 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
3332 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3333 RegDeleteValueW(hkey
, lpNameW
);
3337 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
3338 RegDeleteValueW(hkey
, lpNameW
);
3342 if (GetDefaultPrinterW( def
, &size
) && !strcmpW( def
, lpNameW
))
3344 WriteProfileStringW( windowsW
, deviceW
, NULL
);
3345 if (!RegCreateKeyW( HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
))
3347 RegDeleteValueW( hkey
, deviceW
);
3348 RegCloseKey( hkey
);
3350 SetDefaultPrinterW( NULL
);
3356 /*****************************************************************************
3357 * SetPrinterA [WINSPOOL.@]
3359 BOOL WINAPI
SetPrinterA( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3366 dataW
= printer_info_AtoW( data
, level
);
3367 if (!dataW
) return FALSE
;
3370 ret
= SetPrinterW( printer
, level
, dataW
, command
);
3372 if (dataW
!= data
) free_printer_info( dataW
, level
);
3377 static void set_printer_2( HKEY key
, const PRINTER_INFO_2W
*pi
)
3379 set_reg_szW( key
, NameW
, pi
->pPrinterName
);
3380 set_reg_szW( key
, Share_NameW
, pi
->pShareName
);
3381 set_reg_szW( key
, PortW
, pi
->pPortName
);
3382 set_reg_szW( key
, Printer_DriverW
, pi
->pDriverName
);
3383 set_reg_szW( key
, DescriptionW
, pi
->pComment
);
3384 set_reg_szW( key
, LocationW
, pi
->pLocation
);
3387 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3389 set_reg_szW( key
, Separator_FileW
, pi
->pSepFile
);
3390 set_reg_szW( key
, Print_ProcessorW
, pi
->pPrintProcessor
);
3391 set_reg_szW( key
, DatatypeW
, pi
->pDatatype
);
3392 set_reg_szW( key
, ParametersW
, pi
->pParameters
);
3394 set_reg_DWORD( key
, AttributesW
, pi
->Attributes
);
3395 set_reg_DWORD( key
, PriorityW
, pi
->Priority
);
3396 set_reg_DWORD( key
, Default_PriorityW
, pi
->DefaultPriority
);
3397 set_reg_DWORD( key
, StartTimeW
, pi
->StartTime
);
3398 set_reg_DWORD( key
, UntilTimeW
, pi
->UntilTime
);
3401 static BOOL
set_printer_9( HKEY key
, const PRINTER_INFO_9W
*pi
)
3403 if (!pi
->pDevMode
) return FALSE
;
3405 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3409 /******************************************************************************
3410 * SetPrinterW [WINSPOOL.@]
3412 BOOL WINAPI
SetPrinterW( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3417 TRACE( "(%p, %d, %p, %d)\n", printer
, level
, data
, command
);
3419 if (command
!= 0) FIXME( "Ignoring command %d\n", command
);
3421 if (WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
))
3428 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)data
;
3429 set_printer_2( key
, pi2
);
3436 PRINTER_INFO_9W
*pi
= (PRINTER_INFO_9W
*)data
;
3437 ret
= set_printer_9( key
, pi
);
3442 FIXME( "Unimplemented level %d\n", level
);
3443 SetLastError( ERROR_INVALID_LEVEL
);
3450 /*****************************************************************************
3451 * SetJobA [WINSPOOL.@]
3453 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3454 LPBYTE pJob
, DWORD Command
)
3458 UNICODE_STRING usBuffer
;
3460 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3462 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3463 are all ignored by SetJob, so we don't bother copying them */
3471 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3472 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3474 JobW
= (LPBYTE
)info1W
;
3475 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3476 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3477 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3478 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3479 info1W
->Status
= info1A
->Status
;
3480 info1W
->Priority
= info1A
->Priority
;
3481 info1W
->Position
= info1A
->Position
;
3482 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3487 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3488 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3490 JobW
= (LPBYTE
)info2W
;
3491 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3492 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3493 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3494 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3495 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3496 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3497 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3498 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3499 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3500 info2W
->Status
= info2A
->Status
;
3501 info2W
->Priority
= info2A
->Priority
;
3502 info2W
->Position
= info2A
->Position
;
3503 info2W
->StartTime
= info2A
->StartTime
;
3504 info2W
->UntilTime
= info2A
->UntilTime
;
3505 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3509 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3510 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3513 SetLastError(ERROR_INVALID_LEVEL
);
3517 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3523 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3524 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3525 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3526 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3527 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3532 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3533 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3534 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3535 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3536 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3537 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3538 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3539 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3540 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3544 HeapFree(GetProcessHeap(), 0, JobW
);
3549 /*****************************************************************************
3550 * SetJobW [WINSPOOL.@]
3552 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3553 LPBYTE pJob
, DWORD Command
)
3558 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3559 FIXME("Ignoring everything other than document title\n");
3561 EnterCriticalSection(&printer_handles_cs
);
3562 job
= get_job(hPrinter
, JobId
);
3572 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3573 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3574 job
->document_title
= strdupW(info1
->pDocument
);
3579 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3580 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3581 job
->document_title
= strdupW(info2
->pDocument
);
3582 HeapFree(GetProcessHeap(), 0, job
->devmode
);
3583 job
->devmode
= dup_devmode( info2
->pDevMode
);
3589 SetLastError(ERROR_INVALID_LEVEL
);
3594 LeaveCriticalSection(&printer_handles_cs
);
3598 /*****************************************************************************
3599 * EndDocPrinter [WINSPOOL.@]
3601 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3603 opened_printer_t
*printer
;
3605 TRACE("(%p)\n", hPrinter
);
3607 EnterCriticalSection(&printer_handles_cs
);
3609 printer
= get_opened_printer(hPrinter
);
3612 SetLastError(ERROR_INVALID_HANDLE
);
3618 SetLastError(ERROR_SPL_NO_STARTDOC
);
3622 CloseHandle(printer
->doc
->hf
);
3623 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3624 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3625 printer
->doc
= NULL
;
3628 LeaveCriticalSection(&printer_handles_cs
);
3632 /*****************************************************************************
3633 * EndPagePrinter [WINSPOOL.@]
3635 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3637 FIXME("(%p): stub\n", hPrinter
);
3641 /*****************************************************************************
3642 * StartDocPrinterA [WINSPOOL.@]
3644 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3646 UNICODE_STRING usBuffer
;
3648 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3651 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3652 or one (DOC_INFO_3) extra DWORDs */
3656 doc2W
.JobId
= doc2
->JobId
;
3659 doc2W
.dwMode
= doc2
->dwMode
;
3662 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3663 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3664 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3668 SetLastError(ERROR_INVALID_LEVEL
);
3672 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3674 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3675 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3676 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3681 /*****************************************************************************
3682 * StartDocPrinterW [WINSPOOL.@]
3684 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3686 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3687 opened_printer_t
*printer
;
3688 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3689 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3690 JOB_INFO_1W job_info
;
3691 DWORD needed
, ret
= 0;
3696 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3697 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3698 debugstr_w(doc
->pDatatype
));
3700 if(Level
< 1 || Level
> 3)
3702 SetLastError(ERROR_INVALID_LEVEL
);
3706 EnterCriticalSection(&printer_handles_cs
);
3707 printer
= get_opened_printer(hPrinter
);
3710 SetLastError(ERROR_INVALID_HANDLE
);
3716 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3720 /* Even if we're printing to a file we still add a print job, we'll
3721 just ignore the spool file name */
3723 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3725 ERR("AddJob failed gle %u\n", GetLastError());
3729 /* use pOutputFile only, when it is a real filename */
3730 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3731 filename
= doc
->pOutputFile
;
3733 filename
= addjob
->Path
;
3735 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3736 if(hf
== INVALID_HANDLE_VALUE
)
3739 memset(&job_info
, 0, sizeof(job_info
));
3740 job_info
.pDocument
= doc
->pDocName
;
3741 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3743 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3744 printer
->doc
->hf
= hf
;
3745 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3746 job
= get_job(hPrinter
, ret
);
3747 job
->portname
= strdupW(doc
->pOutputFile
);
3750 LeaveCriticalSection(&printer_handles_cs
);
3755 /*****************************************************************************
3756 * StartPagePrinter [WINSPOOL.@]
3758 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3760 FIXME("(%p): stub\n", hPrinter
);
3764 /*****************************************************************************
3765 * GetFormA [WINSPOOL.@]
3767 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3768 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3770 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3771 Level
,pForm
,cbBuf
,pcbNeeded
);
3775 /*****************************************************************************
3776 * GetFormW [WINSPOOL.@]
3778 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3779 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3781 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3782 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3786 /*****************************************************************************
3787 * SetFormA [WINSPOOL.@]
3789 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3792 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3796 /*****************************************************************************
3797 * SetFormW [WINSPOOL.@]
3799 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3802 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3806 /*****************************************************************************
3807 * ReadPrinter [WINSPOOL.@]
3809 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3810 LPDWORD pNoBytesRead
)
3812 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3816 /*****************************************************************************
3817 * ResetPrinterA [WINSPOOL.@]
3819 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3821 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3825 /*****************************************************************************
3826 * ResetPrinterW [WINSPOOL.@]
3828 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3830 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3834 /*****************************************************************************
3835 * get_filename_from_reg [internal]
3837 * Get ValueName from hkey storing result in out
3838 * when the Value in the registry has only a filename, use driverdir as prefix
3839 * outlen is space left in out
3840 * String is stored either as unicode or ascii
3844 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3845 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3847 WCHAR filename
[MAX_PATH
];
3851 LPWSTR buffer
= filename
;
3855 size
= sizeof(filename
);
3857 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3858 if (ret
== ERROR_MORE_DATA
) {
3859 TRACE("need dynamic buffer: %u\n", size
);
3860 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3862 /* No Memory is bad */
3866 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3869 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3870 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3876 /* do we have a full path ? */
3877 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3878 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3881 /* we must build the full Path */
3883 if ((out
) && (outlen
> dirlen
)) {
3884 lstrcpyW((LPWSTR
)out
, driverdir
);
3892 /* write the filename */
3893 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3894 if ((out
) && (outlen
>= size
)) {
3895 lstrcpyW((LPWSTR
)out
, ptr
);
3902 ptr
+= lstrlenW(ptr
)+1;
3903 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3906 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3908 /* write the multisz-termination */
3909 if (type
== REG_MULTI_SZ
) {
3910 size
= sizeof(WCHAR
);
3913 if (out
&& (outlen
>= size
)) {
3914 memset (out
, 0, size
);
3920 /*****************************************************************************
3921 * WINSPOOL_GetStringFromReg
3923 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3924 * String is stored as unicode.
3926 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3927 DWORD buflen
, DWORD
*needed
)
3929 DWORD sz
= buflen
, type
;
3932 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3933 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3934 WARN("Got ret = %d\n", ret
);
3938 /* add space for terminating '\0' */
3939 sz
+= sizeof(WCHAR
);
3943 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
3948 /*****************************************************************************
3949 * WINSPOOL_GetDefaultDevMode
3951 * Get a default DevMode values for wineps.
3955 static void WINSPOOL_GetDefaultDevMode(
3957 DWORD buflen
, DWORD
*needed
)
3960 static const WCHAR szWwps
[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3962 /* fill default DEVMODE - should be read from ppd... */
3963 ZeroMemory( &dm
, sizeof(dm
) );
3964 memcpy(dm
.dmDeviceName
,szWwps
,sizeof szWwps
);
3965 dm
.dmSpecVersion
= DM_SPECVERSION
;
3966 dm
.dmDriverVersion
= 1;
3967 dm
.dmSize
= sizeof(DEVMODEW
);
3968 dm
.dmDriverExtra
= 0;
3970 DM_ORIENTATION
| DM_PAPERSIZE
|
3971 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3974 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3975 DM_YRESOLUTION
| DM_TTOPTION
;
3977 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3978 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3979 dm
.u1
.s1
.dmPaperLength
= 2970;
3980 dm
.u1
.s1
.dmPaperWidth
= 2100;
3982 dm
.u1
.s1
.dmScale
= 100;
3983 dm
.u1
.s1
.dmCopies
= 1;
3984 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3985 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3988 dm
.dmYResolution
= 300; /* 300dpi */
3989 dm
.dmTTOption
= DMTT_BITMAP
;
3992 /* dm.dmLogPixels */
3993 /* dm.dmBitsPerPel */
3994 /* dm.dmPelsWidth */
3995 /* dm.dmPelsHeight */
3996 /* dm.u2.dmDisplayFlags */
3997 /* dm.dmDisplayFrequency */
3998 /* dm.dmICMMethod */
3999 /* dm.dmICMIntent */
4000 /* dm.dmMediaType */
4001 /* dm.dmDitherType */
4002 /* dm.dmReserved1 */
4003 /* dm.dmReserved2 */
4004 /* dm.dmPanningWidth */
4005 /* dm.dmPanningHeight */
4007 if(buflen
>= sizeof(DEVMODEW
))
4008 memcpy(ptr
, &dm
, sizeof(DEVMODEW
));
4009 *needed
= sizeof(DEVMODEW
);
4012 /*****************************************************************************
4013 * WINSPOOL_GetDevModeFromReg
4015 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4016 * DevMode is stored either as unicode or ascii.
4018 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
4020 DWORD buflen
, DWORD
*needed
)
4022 DWORD sz
= buflen
, type
;
4025 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
4026 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
4027 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
4028 if (sz
< sizeof(DEVMODEA
))
4030 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
4033 /* ensures that dmSize is not erratically bogus if registry is invalid */
4034 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
4035 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
4036 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
4037 if (ptr
&& (buflen
>= sz
)) {
4038 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
4039 memcpy(ptr
, dmW
, sz
);
4040 HeapFree(GetProcessHeap(),0,dmW
);
4046 /*********************************************************************
4047 * WINSPOOL_GetPrinter_1
4049 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4051 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
4052 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4054 DWORD size
, left
= cbBuf
;
4055 BOOL space
= (cbBuf
> 0);
4060 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4061 if(space
&& size
<= left
) {
4062 pi1
->pName
= (LPWSTR
)ptr
;
4070 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4071 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4072 if(space
&& size
<= left
) {
4073 pi1
->pDescription
= (LPWSTR
)ptr
;
4081 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4082 if(space
&& size
<= left
) {
4083 pi1
->pComment
= (LPWSTR
)ptr
;
4091 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
4093 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
4094 memset(pi1
, 0, sizeof(*pi1
));
4098 /*********************************************************************
4099 * WINSPOOL_GetPrinter_2
4101 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4103 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
4104 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4106 DWORD size
, left
= cbBuf
;
4107 BOOL space
= (cbBuf
> 0);
4112 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4113 if(space
&& size
<= left
) {
4114 pi2
->pPrinterName
= (LPWSTR
)ptr
;
4121 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
4122 if(space
&& size
<= left
) {
4123 pi2
->pShareName
= (LPWSTR
)ptr
;
4130 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4131 if(space
&& size
<= left
) {
4132 pi2
->pPortName
= (LPWSTR
)ptr
;
4139 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
4140 if(space
&& size
<= left
) {
4141 pi2
->pDriverName
= (LPWSTR
)ptr
;
4148 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4149 if(space
&& size
<= left
) {
4150 pi2
->pComment
= (LPWSTR
)ptr
;
4157 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
4158 if(space
&& size
<= left
) {
4159 pi2
->pLocation
= (LPWSTR
)ptr
;
4166 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
4167 if(space
&& size
<= left
) {
4168 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4177 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
4178 if(space
&& size
<= left
) {
4179 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4186 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
4187 if(space
&& size
<= left
) {
4188 pi2
->pSepFile
= (LPWSTR
)ptr
;
4195 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
4196 if(space
&& size
<= left
) {
4197 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
4204 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
4205 if(space
&& size
<= left
) {
4206 pi2
->pDatatype
= (LPWSTR
)ptr
;
4213 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
4214 if(space
&& size
<= left
) {
4215 pi2
->pParameters
= (LPWSTR
)ptr
;
4223 pi2
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4224 pi2
->Priority
= get_dword_from_reg( hkeyPrinter
, PriorityW
);
4225 pi2
->DefaultPriority
= get_dword_from_reg( hkeyPrinter
, Default_PriorityW
);
4226 pi2
->StartTime
= get_dword_from_reg( hkeyPrinter
, StartTimeW
);
4227 pi2
->UntilTime
= get_dword_from_reg( hkeyPrinter
, UntilTimeW
);
4230 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
4231 memset(pi2
, 0, sizeof(*pi2
));
4236 /*********************************************************************
4237 * WINSPOOL_GetPrinter_4
4239 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4241 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
4242 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4244 DWORD size
, left
= cbBuf
;
4245 BOOL space
= (cbBuf
> 0);
4250 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4251 if(space
&& size
<= left
) {
4252 pi4
->pPrinterName
= (LPWSTR
)ptr
;
4260 pi4
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4263 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
4264 memset(pi4
, 0, sizeof(*pi4
));
4269 /*********************************************************************
4270 * WINSPOOL_GetPrinter_5
4272 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4274 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
4275 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4277 DWORD size
, left
= cbBuf
;
4278 BOOL space
= (cbBuf
> 0);
4283 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4284 if(space
&& size
<= left
) {
4285 pi5
->pPrinterName
= (LPWSTR
)ptr
;
4292 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4293 if(space
&& size
<= left
) {
4294 pi5
->pPortName
= (LPWSTR
)ptr
;
4302 pi5
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4303 pi5
->DeviceNotSelectedTimeout
= get_dword_from_reg( hkeyPrinter
, dnsTimeoutW
);
4304 pi5
->TransmissionRetryTimeout
= get_dword_from_reg( hkeyPrinter
, txTimeoutW
);
4307 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
4308 memset(pi5
, 0, sizeof(*pi5
));
4313 /*********************************************************************
4314 * WINSPOOL_GetPrinter_7
4316 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4318 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
4319 DWORD cbBuf
, LPDWORD pcbNeeded
)
4321 DWORD size
, left
= cbBuf
;
4322 BOOL space
= (cbBuf
> 0);
4327 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
4330 size
= sizeof(pi7
->pszObjectGUID
);
4332 if (space
&& size
<= left
) {
4333 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
4340 /* We do not have a Directory Service */
4341 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
4344 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
4345 memset(pi7
, 0, sizeof(*pi7
));
4350 /*********************************************************************
4351 * WINSPOOL_GetPrinter_9
4353 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4355 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
4356 DWORD cbBuf
, LPDWORD pcbNeeded
)
4359 BOOL space
= (cbBuf
> 0);
4363 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
4364 if(space
&& size
<= cbBuf
) {
4365 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4372 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
4373 if(space
&& size
<= cbBuf
) {
4374 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4380 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
4381 memset(pi9
, 0, sizeof(*pi9
));
4386 /*****************************************************************************
4387 * GetPrinterW [WINSPOOL.@]
4389 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4390 DWORD cbBuf
, LPDWORD pcbNeeded
)
4392 DWORD size
, needed
= 0, err
;
4397 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4399 err
= WINSPOOL_GetOpenedPrinterRegKey( hPrinter
, &hkeyPrinter
);
4402 SetLastError( err
);
4409 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4411 size
= sizeof(PRINTER_INFO_2W
);
4413 ptr
= pPrinter
+ size
;
4415 memset(pPrinter
, 0, size
);
4420 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
4427 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4429 size
= sizeof(PRINTER_INFO_4W
);
4431 ptr
= pPrinter
+ size
;
4433 memset(pPrinter
, 0, size
);
4438 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
4446 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4448 size
= sizeof(PRINTER_INFO_5W
);
4450 ptr
= pPrinter
+ size
;
4452 memset(pPrinter
, 0, size
);
4458 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
4466 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4468 size
= sizeof(PRINTER_INFO_6
);
4469 if (size
<= cbBuf
) {
4470 /* FIXME: We do not update the status yet */
4471 pi6
->dwStatus
= get_dword_from_reg( hkeyPrinter
, StatusW
);
4483 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4485 size
= sizeof(PRINTER_INFO_7W
);
4486 if (size
<= cbBuf
) {
4487 ptr
= pPrinter
+ size
;
4489 memset(pPrinter
, 0, size
);
4495 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
4502 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4503 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4507 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4509 size
= sizeof(PRINTER_INFO_9W
);
4511 ptr
= pPrinter
+ size
;
4513 memset(pPrinter
, 0, size
);
4519 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
4526 FIXME("Unimplemented level %d\n", Level
);
4527 SetLastError(ERROR_INVALID_LEVEL
);
4528 RegCloseKey(hkeyPrinter
);
4532 RegCloseKey(hkeyPrinter
);
4534 TRACE("returning %d needed = %d\n", ret
, needed
);
4535 if(pcbNeeded
) *pcbNeeded
= needed
;
4537 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4541 /*****************************************************************************
4542 * GetPrinterA [WINSPOOL.@]
4544 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4545 DWORD cbBuf
, LPDWORD pcbNeeded
)
4551 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4553 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
4555 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
4556 HeapFree(GetProcessHeap(), 0, buf
);
4561 /*****************************************************************************
4562 * WINSPOOL_EnumPrintersW
4564 * Implementation of EnumPrintersW
4566 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
4567 DWORD dwLevel
, LPBYTE lpbPrinters
,
4568 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4569 LPDWORD lpdwReturned
)
4572 HKEY hkeyPrinters
, hkeyPrinter
;
4573 WCHAR PrinterName
[255];
4574 DWORD needed
= 0, number
= 0;
4575 DWORD used
, i
, left
;
4579 memset(lpbPrinters
, 0, cbBuf
);
4585 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4586 if(dwType
== PRINTER_ENUM_DEFAULT
)
4589 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4590 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4591 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4593 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4599 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4600 FIXME("dwType = %08x\n", dwType
);
4601 SetLastError(ERROR_INVALID_FLAGS
);
4605 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4607 ERR("Can't create Printers key\n");
4611 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4612 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4613 RegCloseKey(hkeyPrinters
);
4614 ERR("Can't query Printers key\n");
4617 TRACE("Found %d printers\n", number
);
4621 used
= number
* sizeof(PRINTER_INFO_1W
);
4624 used
= number
* sizeof(PRINTER_INFO_2W
);
4627 used
= number
* sizeof(PRINTER_INFO_4W
);
4630 used
= number
* sizeof(PRINTER_INFO_5W
);
4634 SetLastError(ERROR_INVALID_LEVEL
);
4635 RegCloseKey(hkeyPrinters
);
4638 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4640 for(i
= 0; i
< number
; i
++) {
4641 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4643 ERR("Can't enum key number %d\n", i
);
4644 RegCloseKey(hkeyPrinters
);
4647 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4648 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4650 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4651 RegCloseKey(hkeyPrinters
);
4656 buf
= lpbPrinters
+ used
;
4657 left
= cbBuf
- used
;
4665 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4668 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4671 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4674 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4677 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4680 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4683 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4686 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4689 ERR("Shouldn't be here!\n");
4690 RegCloseKey(hkeyPrinter
);
4691 RegCloseKey(hkeyPrinters
);
4694 RegCloseKey(hkeyPrinter
);
4696 RegCloseKey(hkeyPrinters
);
4703 memset(lpbPrinters
, 0, cbBuf
);
4704 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4708 *lpdwReturned
= number
;
4709 SetLastError(ERROR_SUCCESS
);
4714 /******************************************************************
4715 * EnumPrintersW [WINSPOOL.@]
4717 * Enumerates the available printers, print servers and print
4718 * providers, depending on the specified flags, name and level.
4722 * If level is set to 1:
4723 * Returns an array of PRINTER_INFO_1 data structures in the
4724 * lpbPrinters buffer.
4726 * If level is set to 2:
4727 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4728 * Returns an array of PRINTER_INFO_2 data structures in the
4729 * lpbPrinters buffer. Note that according to MSDN also an
4730 * OpenPrinter should be performed on every remote printer.
4732 * If level is set to 4 (officially WinNT only):
4733 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4734 * Fast: Only the registry is queried to retrieve printer names,
4735 * no connection to the driver is made.
4736 * Returns an array of PRINTER_INFO_4 data structures in the
4737 * lpbPrinters buffer.
4739 * If level is set to 5 (officially WinNT4/Win9x only):
4740 * Fast: Only the registry is queried to retrieve printer names,
4741 * no connection to the driver is made.
4742 * Returns an array of PRINTER_INFO_5 data structures in the
4743 * lpbPrinters buffer.
4745 * If level set to 3 or 6+:
4746 * returns zero (failure!)
4748 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4752 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4753 * - Only levels 2, 4 and 5 are implemented at the moment.
4754 * - 16-bit printer drivers are not enumerated.
4755 * - Returned amount of bytes used/needed does not match the real Windoze
4756 * implementation (as in this implementation, all strings are part
4757 * of the buffer, whereas Win32 keeps them somewhere else)
4758 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4761 * - In a regular Wine installation, no registry settings for printers
4762 * exist, which makes this function return an empty list.
4764 BOOL WINAPI
EnumPrintersW(
4765 DWORD dwType
, /* [in] Types of print objects to enumerate */
4766 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4767 DWORD dwLevel
, /* [in] type of printer info structure */
4768 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4769 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4770 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4771 LPDWORD lpdwReturned
/* [out] number of entries returned */
4774 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4775 lpdwNeeded
, lpdwReturned
);
4778 /******************************************************************
4779 * EnumPrintersA [WINSPOOL.@]
4784 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4785 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4788 UNICODE_STRING pNameU
;
4792 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4793 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4795 pNameW
= asciitounicode(&pNameU
, pName
);
4797 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4798 MS Office need this */
4799 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4801 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4803 RtlFreeUnicodeString(&pNameU
);
4805 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4807 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4811 /*****************************************************************************
4812 * WINSPOOL_GetDriverInfoFromReg [internal]
4814 * Enters the information from the registry into the DRIVER_INFO struct
4817 * zero if the printer driver does not exist in the registry
4818 * (only if Level > 1) otherwise nonzero
4820 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4823 const printenv_t
* env
,
4825 LPBYTE ptr
, /* DRIVER_INFO */
4826 LPBYTE pDriverStrings
, /* strings buffer */
4827 DWORD cbBuf
, /* size of string buffer */
4828 LPDWORD pcbNeeded
) /* space needed for str. */
4832 WCHAR driverdir
[MAX_PATH
];
4834 LPBYTE strPtr
= pDriverStrings
;
4835 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4837 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4838 debugstr_w(DriverName
), env
,
4839 Level
, di
, pDriverStrings
, cbBuf
);
4841 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4843 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4844 if (*pcbNeeded
<= cbBuf
)
4845 strcpyW((LPWSTR
)strPtr
, DriverName
);
4847 /* pName for level 1 has a different offset! */
4849 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4853 /* .cVersion and .pName for level > 1 */
4855 di
->cVersion
= env
->driverversion
;
4856 di
->pName
= (LPWSTR
) strPtr
;
4857 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4860 /* Reserve Space for the largest subdir and a Backslash*/
4861 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4862 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4863 /* Should never Fail */
4866 lstrcatW(driverdir
, env
->versionsubdir
);
4867 lstrcatW(driverdir
, backslashW
);
4869 /* dirlen must not include the terminating zero */
4870 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4872 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4873 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4874 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4879 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4882 if (*pcbNeeded
<= cbBuf
) {
4883 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4884 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4885 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4888 /* .pDriverPath is the Graphics rendering engine.
4889 The full Path is required to avoid a crash in some apps */
4890 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4892 if (*pcbNeeded
<= cbBuf
)
4893 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4895 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4896 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4899 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4900 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4902 if (*pcbNeeded
<= cbBuf
)
4903 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4905 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4906 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4909 /* .pConfigFile is the Driver user Interface */
4910 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4912 if (*pcbNeeded
<= cbBuf
)
4913 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4915 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4916 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4920 RegCloseKey(hkeyDriver
);
4921 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4926 RegCloseKey(hkeyDriver
);
4927 FIXME("level 5: incomplete\n");
4932 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4934 if (*pcbNeeded
<= cbBuf
)
4935 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4937 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4938 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4941 /* .pDependentFiles */
4942 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4944 if (*pcbNeeded
<= cbBuf
)
4945 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4947 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4948 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4950 else if (GetVersion() & 0x80000000) {
4951 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4952 size
= 2 * sizeof(WCHAR
);
4954 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4956 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4957 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4960 /* .pMonitorName is the optional Language Monitor */
4961 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4963 if (*pcbNeeded
<= cbBuf
)
4964 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4966 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4967 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4970 /* .pDefaultDataType */
4971 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
4973 if(*pcbNeeded
<= cbBuf
)
4974 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
4976 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4977 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4981 RegCloseKey(hkeyDriver
);
4982 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4986 /* .pszzPreviousNames */
4987 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
4989 if(*pcbNeeded
<= cbBuf
)
4990 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
4992 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4993 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4997 RegCloseKey(hkeyDriver
);
4998 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5002 /* support is missing, but not important enough for a FIXME */
5003 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
5006 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
5008 if(*pcbNeeded
<= cbBuf
)
5009 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
5011 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
5012 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5016 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
5018 if(*pcbNeeded
<= cbBuf
)
5019 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
5021 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
5022 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5025 /* .pszHardwareID */
5026 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
5028 if(*pcbNeeded
<= cbBuf
)
5029 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
5031 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
5032 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5036 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
5038 if(*pcbNeeded
<= cbBuf
)
5039 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
5041 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
5042 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5046 RegCloseKey(hkeyDriver
);
5050 /* support is missing, but not important enough for a FIXME */
5051 TRACE("level 8: incomplete\n");
5053 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5054 RegCloseKey(hkeyDriver
);
5058 /*****************************************************************************
5059 * GetPrinterDriverW [WINSPOOL.@]
5061 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
5062 DWORD Level
, LPBYTE pDriverInfo
,
5063 DWORD cbBuf
, LPDWORD pcbNeeded
)
5066 WCHAR DriverName
[100];
5067 DWORD ret
, type
, size
, needed
= 0;
5069 HKEY hkeyPrinter
, hkeyDrivers
;
5070 const printenv_t
* env
;
5072 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
5073 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
5076 ZeroMemory(pDriverInfo
, cbBuf
);
5078 if (!(name
= get_opened_printer_name(hPrinter
))) {
5079 SetLastError(ERROR_INVALID_HANDLE
);
5083 if (Level
< 1 || Level
== 7 || Level
> 8) {
5084 SetLastError(ERROR_INVALID_LEVEL
);
5088 env
= validate_envW(pEnvironment
);
5089 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5091 ret
= open_printer_reg_key( name
, &hkeyPrinter
);
5094 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name
) );
5095 SetLastError( ret
);
5099 size
= sizeof(DriverName
);
5101 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
5102 (LPBYTE
)DriverName
, &size
);
5103 RegCloseKey(hkeyPrinter
);
5104 if(ret
!= ERROR_SUCCESS
) {
5105 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
5109 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5111 ERR("Can't create Drivers key\n");
5115 size
= di_sizeof
[Level
];
5116 if ((size
<= cbBuf
) && pDriverInfo
)
5117 ptr
= pDriverInfo
+ size
;
5119 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
5120 env
, Level
, pDriverInfo
, ptr
,
5121 (cbBuf
< size
) ? 0 : cbBuf
- size
,
5123 RegCloseKey(hkeyDrivers
);
5127 RegCloseKey(hkeyDrivers
);
5129 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
5130 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
5131 if(cbBuf
>= size
+ needed
) return TRUE
;
5132 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5136 /*****************************************************************************
5137 * GetPrinterDriverA [WINSPOOL.@]
5139 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
5140 DWORD Level
, LPBYTE pDriverInfo
,
5141 DWORD cbBuf
, LPDWORD pcbNeeded
)
5144 UNICODE_STRING pEnvW
;
5150 ZeroMemory(pDriverInfo
, cbBuf
);
5151 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5154 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
5155 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
5158 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
5160 HeapFree(GetProcessHeap(), 0, buf
);
5162 RtlFreeUnicodeString(&pEnvW
);
5166 /*****************************************************************************
5167 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5169 * Return the PATH for the Printer-Drivers (UNICODE)
5172 * pName [I] Servername (NT only) or NULL (local Computer)
5173 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5174 * Level [I] Structure-Level (must be 1)
5175 * pDriverDirectory [O] PTR to Buffer that receives the Result
5176 * cbBuf [I] Size of Buffer at pDriverDirectory
5177 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5178 * required for pDriverDirectory
5181 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5182 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5183 * if cbBuf is too small
5185 * Native Values returned in pDriverDirectory on Success:
5186 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5187 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5188 *| win9x(Windows 4.0): "%winsysdir%"
5190 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5193 *- Only NULL or "" is supported for pName
5196 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
5197 DWORD Level
, LPBYTE pDriverDirectory
,
5198 DWORD cbBuf
, LPDWORD pcbNeeded
)
5200 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
5201 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5203 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5206 /* (Level != 1) is ignored in win9x */
5207 SetLastError(ERROR_INVALID_LEVEL
);
5210 if (pcbNeeded
== NULL
) {
5211 /* (pcbNeeded == NULL) is ignored in win9x */
5212 SetLastError(RPC_X_NULL_REF_POINTER
);
5216 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
5217 pDriverDirectory
, cbBuf
, pcbNeeded
);
5222 /*****************************************************************************
5223 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5225 * Return the PATH for the Printer-Drivers (ANSI)
5227 * See GetPrinterDriverDirectoryW.
5230 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5233 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
5234 DWORD Level
, LPBYTE pDriverDirectory
,
5235 DWORD cbBuf
, LPDWORD pcbNeeded
)
5237 UNICODE_STRING nameW
, environmentW
;
5240 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
5241 WCHAR
*driverDirectoryW
= NULL
;
5243 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
5244 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5246 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
5248 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
5249 else nameW
.Buffer
= NULL
;
5250 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
5251 else environmentW
.Buffer
= NULL
;
5253 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
5254 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
5257 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
5258 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
5260 *pcbNeeded
= needed
;
5261 ret
= needed
<= cbBuf
;
5263 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
5265 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
5267 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
5268 RtlFreeUnicodeString(&environmentW
);
5269 RtlFreeUnicodeString(&nameW
);
5274 /*****************************************************************************
5275 * AddPrinterDriverA [WINSPOOL.@]
5277 * See AddPrinterDriverW.
5280 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5282 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
5283 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5286 /******************************************************************************
5287 * AddPrinterDriverW (WINSPOOL.@)
5289 * Install a Printer Driver
5292 * pName [I] Servername or NULL (local Computer)
5293 * level [I] Level for the supplied DRIVER_INFO_*W struct
5294 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5301 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5303 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
5304 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5307 /*****************************************************************************
5308 * AddPrintProcessorA [WINSPOOL.@]
5310 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
5311 LPSTR pPrintProcessorName
)
5313 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5314 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
5318 /*****************************************************************************
5319 * AddPrintProcessorW [WINSPOOL.@]
5321 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5322 LPWSTR pPrintProcessorName
)
5324 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5325 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5329 /*****************************************************************************
5330 * AddPrintProvidorA [WINSPOOL.@]
5332 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5334 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5338 /*****************************************************************************
5339 * AddPrintProvidorW [WINSPOOL.@]
5341 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5343 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5347 /*****************************************************************************
5348 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5350 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5351 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5353 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5354 pDevModeOutput
, pDevModeInput
);
5358 /*****************************************************************************
5359 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5361 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5362 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5364 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5365 pDevModeOutput
, pDevModeInput
);
5369 /*****************************************************************************
5370 * PrinterProperties [WINSPOOL.@]
5372 * Displays a dialog to set the properties of the printer.
5375 * nonzero on success or zero on failure
5378 * implemented as stub only
5380 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5381 HANDLE hPrinter
/* [in] handle to printer object */
5383 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5384 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5388 /*****************************************************************************
5389 * EnumJobsA [WINSPOOL.@]
5392 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5393 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5396 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5397 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5399 if(pcbNeeded
) *pcbNeeded
= 0;
5400 if(pcReturned
) *pcReturned
= 0;
5405 /*****************************************************************************
5406 * EnumJobsW [WINSPOOL.@]
5409 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5410 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5413 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5414 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5416 if(pcbNeeded
) *pcbNeeded
= 0;
5417 if(pcReturned
) *pcReturned
= 0;
5421 /*****************************************************************************
5422 * WINSPOOL_EnumPrinterDrivers [internal]
5424 * Delivers information about all printer drivers installed on the
5425 * localhost or a given server
5428 * nonzero on success or zero on failure. If the buffer for the returned
5429 * information is too small the function will return an error
5432 * - only implemented for localhost, foreign hosts will return an error
5434 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5435 DWORD Level
, LPBYTE pDriverInfo
,
5437 DWORD cbBuf
, LPDWORD pcbNeeded
,
5438 LPDWORD pcFound
, DWORD data_offset
)
5442 const printenv_t
* env
;
5444 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5445 debugstr_w(pName
), debugstr_w(pEnvironment
),
5446 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
5448 env
= validate_envW(pEnvironment
);
5449 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5453 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5455 ERR("Can't open Drivers key\n");
5459 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
5460 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5461 RegCloseKey(hkeyDrivers
);
5462 ERR("Can't query Drivers key\n");
5465 TRACE("Found %d Drivers\n", *pcFound
);
5467 /* get size of single struct
5468 * unicode and ascii structure have the same size
5470 size
= di_sizeof
[Level
];
5472 if (data_offset
== 0)
5473 data_offset
= size
* (*pcFound
);
5474 *pcbNeeded
= data_offset
;
5476 for( i
= 0; i
< *pcFound
; i
++) {
5477 WCHAR DriverNameW
[255];
5478 PBYTE table_ptr
= NULL
;
5479 PBYTE data_ptr
= NULL
;
5482 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
5484 ERR("Can't enum key number %d\n", i
);
5485 RegCloseKey(hkeyDrivers
);
5489 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
5490 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
5491 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
5492 data_ptr
= pDriverInfo
+ *pcbNeeded
;
5494 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5495 env
, Level
, table_ptr
, data_ptr
,
5496 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5498 RegCloseKey(hkeyDrivers
);
5502 *pcbNeeded
+= needed
;
5505 RegCloseKey(hkeyDrivers
);
5507 if(cbBuf
< *pcbNeeded
){
5508 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5515 /*****************************************************************************
5516 * EnumPrinterDriversW [WINSPOOL.@]
5518 * see function EnumPrinterDrivers for RETURNS, BUGS
5520 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5521 LPBYTE pDriverInfo
, DWORD cbBuf
,
5522 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5524 static const WCHAR allW
[] = {'a','l','l',0};
5528 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
5530 SetLastError(RPC_X_NULL_REF_POINTER
);
5534 /* check for local drivers */
5535 if((pName
) && (pName
[0])) {
5536 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5537 SetLastError(ERROR_ACCESS_DENIED
);
5541 /* check input parameter */
5542 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5543 SetLastError(ERROR_INVALID_LEVEL
);
5547 if(pDriverInfo
&& cbBuf
> 0)
5548 memset( pDriverInfo
, 0, cbBuf
);
5550 /* Exception: pull all printers */
5551 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
5553 DWORD i
, needed
, bufsize
= cbBuf
;
5554 DWORD total_needed
= 0;
5555 DWORD total_found
= 0;
5558 /* Precompute the overall total; we need this to know
5559 where pointers end and data begins (i.e. data_offset) */
5560 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5563 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5564 NULL
, 0, 0, &needed
, &found
, 0);
5565 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5566 total_needed
+= needed
;
5567 total_found
+= found
;
5570 data_offset
= di_sizeof
[Level
] * total_found
;
5575 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5578 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5579 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
5580 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5582 *pcReturned
+= found
;
5583 *pcbNeeded
= needed
;
5584 data_offset
= needed
;
5585 total_found
+= found
;
5590 /* Normal behavior */
5591 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5592 0, cbBuf
, pcbNeeded
, &found
, 0);
5594 *pcReturned
= found
;
5599 /*****************************************************************************
5600 * EnumPrinterDriversA [WINSPOOL.@]
5602 * see function EnumPrinterDrivers for RETURNS, BUGS
5604 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5605 LPBYTE pDriverInfo
, DWORD cbBuf
,
5606 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5609 UNICODE_STRING pNameW
, pEnvironmentW
;
5610 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5614 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5616 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5617 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5619 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5620 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5622 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5624 HeapFree(GetProcessHeap(), 0, buf
);
5626 RtlFreeUnicodeString(&pNameW
);
5627 RtlFreeUnicodeString(&pEnvironmentW
);
5632 /******************************************************************************
5633 * EnumPortsA (WINSPOOL.@)
5638 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5639 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5642 LPBYTE bufferW
= NULL
;
5643 LPWSTR nameW
= NULL
;
5645 DWORD numentries
= 0;
5648 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5649 cbBuf
, pcbNeeded
, pcReturned
);
5651 /* convert servername to unicode */
5653 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5654 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5655 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5657 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5658 needed
= cbBuf
* sizeof(WCHAR
);
5659 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5660 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5662 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5663 if (pcbNeeded
) needed
= *pcbNeeded
;
5664 /* HeapReAlloc return NULL, when bufferW was NULL */
5665 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5666 HeapAlloc(GetProcessHeap(), 0, needed
);
5668 /* Try again with the large Buffer */
5669 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5671 needed
= pcbNeeded
? *pcbNeeded
: 0;
5672 numentries
= pcReturned
? *pcReturned
: 0;
5675 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5676 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5679 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5680 DWORD entrysize
= 0;
5683 LPPORT_INFO_2W pi2w
;
5684 LPPORT_INFO_2A pi2a
;
5687 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5689 /* First pass: calculate the size for all Entries */
5690 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5691 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5693 while (index
< numentries
) {
5695 needed
+= entrysize
; /* PORT_INFO_?A */
5696 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5698 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5699 NULL
, 0, NULL
, NULL
);
5701 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5702 NULL
, 0, NULL
, NULL
);
5703 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5704 NULL
, 0, NULL
, NULL
);
5706 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5707 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5708 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5711 /* check for errors and quit on failure */
5712 if (cbBuf
< needed
) {
5713 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5717 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5718 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5719 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5720 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5721 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5723 /* Second Pass: Fill the User Buffer (if we have one) */
5724 while ((index
< numentries
) && pPorts
) {
5726 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5727 pi2a
->pPortName
= ptr
;
5728 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5729 ptr
, cbBuf
, NULL
, NULL
);
5733 pi2a
->pMonitorName
= ptr
;
5734 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5735 ptr
, cbBuf
, NULL
, NULL
);
5739 pi2a
->pDescription
= ptr
;
5740 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5741 ptr
, cbBuf
, NULL
, NULL
);
5745 pi2a
->fPortType
= pi2w
->fPortType
;
5746 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5749 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5750 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5751 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5756 if (pcbNeeded
) *pcbNeeded
= needed
;
5757 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5759 HeapFree(GetProcessHeap(), 0, nameW
);
5760 HeapFree(GetProcessHeap(), 0, bufferW
);
5762 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5763 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5769 /******************************************************************************
5770 * EnumPortsW (WINSPOOL.@)
5772 * Enumerate available Ports
5775 * pName [I] Servername or NULL (local Computer)
5776 * Level [I] Structure-Level (1 or 2)
5777 * pPorts [O] PTR to Buffer that receives the Result
5778 * cbBuf [I] Size of Buffer at pPorts
5779 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5780 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5784 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5787 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5790 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5791 cbBuf
, pcbNeeded
, pcReturned
);
5793 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5795 /* Level is not checked in win9x */
5796 if (!Level
|| (Level
> 2)) {
5797 WARN("level (%d) is ignored in win9x\n", Level
);
5798 SetLastError(ERROR_INVALID_LEVEL
);
5801 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5802 SetLastError(RPC_X_NULL_REF_POINTER
);
5806 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5809 /******************************************************************************
5810 * GetDefaultPrinterW (WINSPOOL.@)
5813 * This function must read the value from data 'device' of key
5814 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5816 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5820 WCHAR
*buffer
, *ptr
;
5824 SetLastError(ERROR_INVALID_PARAMETER
);
5828 /* make the buffer big enough for the stuff from the profile/registry,
5829 * the content must fit into the local buffer to compute the correct
5830 * size even if the extern buffer is too small or not given.
5831 * (20 for ,driver,port) */
5833 len
= max(100, (insize
+ 20));
5834 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5836 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5838 SetLastError (ERROR_FILE_NOT_FOUND
);
5842 TRACE("%s\n", debugstr_w(buffer
));
5844 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5846 SetLastError(ERROR_INVALID_NAME
);
5852 *namesize
= strlenW(buffer
) + 1;
5853 if(!name
|| (*namesize
> insize
))
5855 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5859 strcpyW(name
, buffer
);
5862 HeapFree( GetProcessHeap(), 0, buffer
);
5867 /******************************************************************************
5868 * GetDefaultPrinterA (WINSPOOL.@)
5870 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5874 WCHAR
*bufferW
= NULL
;
5878 SetLastError(ERROR_INVALID_PARAMETER
);
5882 if(name
&& *namesize
) {
5884 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5887 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5892 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5896 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5899 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5902 HeapFree( GetProcessHeap(), 0, bufferW
);
5907 /******************************************************************************
5908 * SetDefaultPrinterW (WINSPOOL.204)
5910 * Set the Name of the Default Printer
5913 * pszPrinter [I] Name of the Printer or NULL
5920 * When the Parameter is NULL or points to an Empty String and
5921 * a Default Printer was already present, then this Function changes nothing.
5922 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5923 * the First enumerated local Printer is used.
5926 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5928 WCHAR default_printer
[MAX_PATH
];
5929 LPWSTR buffer
= NULL
;
5935 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5936 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5938 default_printer
[0] = '\0';
5939 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5941 /* if we have a default Printer, do nothing. */
5942 if (GetDefaultPrinterW(default_printer
, &size
))
5946 /* we have no default Printer: search local Printers and use the first */
5947 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
5949 default_printer
[0] = '\0';
5950 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5951 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
5953 pszPrinter
= default_printer
;
5954 TRACE("using %s\n", debugstr_w(pszPrinter
));
5959 if (pszPrinter
== NULL
) {
5960 TRACE("no local printer found\n");
5961 SetLastError(ERROR_FILE_NOT_FOUND
);
5966 /* "pszPrinter" is never empty or NULL here. */
5967 namelen
= lstrlenW(pszPrinter
);
5968 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5969 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5971 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
5972 HeapFree(GetProcessHeap(), 0, buffer
);
5973 SetLastError(ERROR_FILE_NOT_FOUND
);
5977 /* read the devices entry for the printer (driver,port) to build the string for the
5978 default device entry (printer,driver,port) */
5979 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
5980 buffer
[namelen
] = ',';
5981 namelen
++; /* move index to the start of the driver */
5983 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
5984 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
5986 TRACE("set device to %s\n", debugstr_w(buffer
));
5988 if (!WriteProfileStringW(windowsW
, deviceW
, buffer
)) {
5989 TRACE("failed to set the device entry: %d\n", GetLastError());
5990 lres
= ERROR_INVALID_PRINTER_NAME
;
5993 /* remove the next section, when INIFileMapping is implemented */
5996 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
)) {
5997 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (LPBYTE
)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
6004 if (lres
!= ERROR_FILE_NOT_FOUND
)
6005 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
6007 SetLastError(ERROR_INVALID_PRINTER_NAME
);
6011 HeapFree(GetProcessHeap(), 0, buffer
);
6012 return (lres
== ERROR_SUCCESS
);
6015 /******************************************************************************
6016 * SetDefaultPrinterA (WINSPOOL.202)
6018 * See SetDefaultPrinterW.
6021 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
6023 LPWSTR bufferW
= NULL
;
6026 TRACE("(%s)\n", debugstr_a(pszPrinter
));
6028 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
6029 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6030 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
6032 res
= SetDefaultPrinterW(bufferW
);
6033 HeapFree(GetProcessHeap(), 0, bufferW
);
6037 /******************************************************************************
6038 * SetPrinterDataExA (WINSPOOL.@)
6040 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6041 LPCSTR pValueName
, DWORD Type
,
6042 LPBYTE pData
, DWORD cbData
)
6044 HKEY hkeyPrinter
, hkeySubkey
;
6047 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
6048 debugstr_a(pValueName
), Type
, pData
, cbData
);
6050 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6054 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6056 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
6057 RegCloseKey(hkeyPrinter
);
6060 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6061 RegCloseKey(hkeySubkey
);
6062 RegCloseKey(hkeyPrinter
);
6066 /******************************************************************************
6067 * SetPrinterDataExW (WINSPOOL.@)
6069 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6070 LPCWSTR pValueName
, DWORD Type
,
6071 LPBYTE pData
, DWORD cbData
)
6073 HKEY hkeyPrinter
, hkeySubkey
;
6076 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
6077 debugstr_w(pValueName
), Type
, pData
, cbData
);
6079 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6083 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6085 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
6086 RegCloseKey(hkeyPrinter
);
6089 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6090 RegCloseKey(hkeySubkey
);
6091 RegCloseKey(hkeyPrinter
);
6095 /******************************************************************************
6096 * SetPrinterDataA (WINSPOOL.@)
6098 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
6099 LPBYTE pData
, DWORD cbData
)
6101 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
6105 /******************************************************************************
6106 * SetPrinterDataW (WINSPOOL.@)
6108 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
6109 LPBYTE pData
, DWORD cbData
)
6111 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
6115 /******************************************************************************
6116 * GetPrinterDataExA (WINSPOOL.@)
6118 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6119 LPCSTR pValueName
, LPDWORD pType
,
6120 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6122 opened_printer_t
*printer
;
6123 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6126 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
6127 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6129 printer
= get_opened_printer(hPrinter
);
6130 if(!printer
) return ERROR_INVALID_HANDLE
;
6132 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6133 if (ret
) return ret
;
6135 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6137 if (printer
->name
) {
6139 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6141 RegCloseKey(hkeyPrinters
);
6144 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6145 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
6146 RegCloseKey(hkeyPrinter
);
6147 RegCloseKey(hkeyPrinters
);
6152 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6153 0, pType
, pData
, pcbNeeded
);
6155 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6157 RegCloseKey(hkeySubkey
);
6158 RegCloseKey(hkeyPrinter
);
6159 RegCloseKey(hkeyPrinters
);
6161 TRACE("--> %d\n", ret
);
6165 /******************************************************************************
6166 * GetPrinterDataExW (WINSPOOL.@)
6168 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6169 LPCWSTR pValueName
, LPDWORD pType
,
6170 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6172 opened_printer_t
*printer
;
6173 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6176 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
6177 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6179 printer
= get_opened_printer(hPrinter
);
6180 if(!printer
) return ERROR_INVALID_HANDLE
;
6182 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6183 if (ret
) return ret
;
6185 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6187 if (printer
->name
) {
6189 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6191 RegCloseKey(hkeyPrinters
);
6194 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6195 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
6196 RegCloseKey(hkeyPrinter
);
6197 RegCloseKey(hkeyPrinters
);
6202 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6203 0, pType
, pData
, pcbNeeded
);
6205 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6207 RegCloseKey(hkeySubkey
);
6208 RegCloseKey(hkeyPrinter
);
6209 RegCloseKey(hkeyPrinters
);
6211 TRACE("--> %d\n", ret
);
6215 /******************************************************************************
6216 * GetPrinterDataA (WINSPOOL.@)
6218 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
6219 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6221 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
6222 pData
, nSize
, pcbNeeded
);
6225 /******************************************************************************
6226 * GetPrinterDataW (WINSPOOL.@)
6228 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
6229 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6231 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
6232 pData
, nSize
, pcbNeeded
);
6235 /*******************************************************************************
6236 * EnumPrinterDataExW [WINSPOOL.@]
6238 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6239 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6240 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6242 HKEY hkPrinter
, hkSubKey
;
6243 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
6244 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
6249 PPRINTER_ENUM_VALUESW ppev
;
6251 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
6253 if (pKeyName
== NULL
|| *pKeyName
== 0)
6254 return ERROR_INVALID_PARAMETER
;
6256 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
6257 if (ret
!= ERROR_SUCCESS
)
6259 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6264 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
6265 if (ret
!= ERROR_SUCCESS
)
6267 r
= RegCloseKey (hkPrinter
);
6268 if (r
!= ERROR_SUCCESS
)
6269 WARN ("RegCloseKey returned %i\n", r
);
6270 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
6271 debugstr_w (pKeyName
), ret
);
6275 ret
= RegCloseKey (hkPrinter
);
6276 if (ret
!= ERROR_SUCCESS
)
6278 ERR ("RegCloseKey returned %i\n", ret
);
6279 r
= RegCloseKey (hkSubKey
);
6280 if (r
!= ERROR_SUCCESS
)
6281 WARN ("RegCloseKey returned %i\n", r
);
6285 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
6286 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
6287 if (ret
!= ERROR_SUCCESS
)
6289 r
= RegCloseKey (hkSubKey
);
6290 if (r
!= ERROR_SUCCESS
)
6291 WARN ("RegCloseKey returned %i\n", r
);
6292 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
6296 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6297 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
6299 if (cValues
== 0) /* empty key */
6301 r
= RegCloseKey (hkSubKey
);
6302 if (r
!= ERROR_SUCCESS
)
6303 WARN ("RegCloseKey returned %i\n", r
);
6304 *pcbEnumValues
= *pnEnumValues
= 0;
6305 return ERROR_SUCCESS
;
6308 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
6310 hHeap
= GetProcessHeap ();
6313 ERR ("GetProcessHeap failed\n");
6314 r
= RegCloseKey (hkSubKey
);
6315 if (r
!= ERROR_SUCCESS
)
6316 WARN ("RegCloseKey returned %i\n", r
);
6317 return ERROR_OUTOFMEMORY
;
6320 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
6321 if (lpValueName
== NULL
)
6323 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
6324 r
= RegCloseKey (hkSubKey
);
6325 if (r
!= ERROR_SUCCESS
)
6326 WARN ("RegCloseKey returned %i\n", r
);
6327 return ERROR_OUTOFMEMORY
;
6330 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
6331 if (lpValue
== NULL
)
6333 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
6334 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6335 WARN ("HeapFree failed with code %i\n", GetLastError ());
6336 r
= RegCloseKey (hkSubKey
);
6337 if (r
!= ERROR_SUCCESS
)
6338 WARN ("RegCloseKey returned %i\n", r
);
6339 return ERROR_OUTOFMEMORY
;
6342 TRACE ("pass 1: calculating buffer required for all names and values\n");
6344 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6346 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
6348 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6350 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6351 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6352 NULL
, NULL
, lpValue
, &cbValueLen
);
6353 if (ret
!= ERROR_SUCCESS
)
6355 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6356 WARN ("HeapFree failed with code %i\n", GetLastError ());
6357 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6358 WARN ("HeapFree failed with code %i\n", GetLastError ());
6359 r
= RegCloseKey (hkSubKey
);
6360 if (r
!= ERROR_SUCCESS
)
6361 WARN ("RegCloseKey returned %i\n", r
);
6362 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6366 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6367 debugstr_w (lpValueName
), dwIndex
,
6368 cbValueNameLen
+ 1, cbValueLen
);
6370 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6371 cbBufSize
+= cbValueLen
;
6374 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
6376 *pcbEnumValues
= cbBufSize
;
6377 *pnEnumValues
= cValues
;
6379 if (cbEnumValues
< cbBufSize
) /* buffer too small */
6381 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6382 WARN ("HeapFree failed with code %i\n", GetLastError ());
6383 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6384 WARN ("HeapFree failed with code %i\n", GetLastError ());
6385 r
= RegCloseKey (hkSubKey
);
6386 if (r
!= ERROR_SUCCESS
)
6387 WARN ("RegCloseKey returned %i\n", r
);
6388 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
6389 return ERROR_MORE_DATA
;
6392 TRACE ("pass 2: copying all names and values to buffer\n");
6394 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
6395 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6397 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6399 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6400 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6401 NULL
, &dwType
, lpValue
, &cbValueLen
);
6402 if (ret
!= ERROR_SUCCESS
)
6404 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6405 WARN ("HeapFree failed with code %i\n", GetLastError ());
6406 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6407 WARN ("HeapFree failed with code %i\n", GetLastError ());
6408 r
= RegCloseKey (hkSubKey
);
6409 if (r
!= ERROR_SUCCESS
)
6410 WARN ("RegCloseKey returned %i\n", r
);
6411 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6415 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6416 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
6417 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
6418 pEnumValues
+= cbValueNameLen
;
6420 /* return # of *bytes* (including trailing \0), not # of chars */
6421 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
6423 ppev
[dwIndex
].dwType
= dwType
;
6425 memcpy (pEnumValues
, lpValue
, cbValueLen
);
6426 ppev
[dwIndex
].pData
= pEnumValues
;
6427 pEnumValues
+= cbValueLen
;
6429 ppev
[dwIndex
].cbData
= cbValueLen
;
6431 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6432 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
6435 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6437 ret
= GetLastError ();
6438 ERR ("HeapFree failed with code %i\n", ret
);
6439 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6440 WARN ("HeapFree failed with code %i\n", GetLastError ());
6441 r
= RegCloseKey (hkSubKey
);
6442 if (r
!= ERROR_SUCCESS
)
6443 WARN ("RegCloseKey returned %i\n", r
);
6447 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6449 ret
= GetLastError ();
6450 ERR ("HeapFree failed with code %i\n", ret
);
6451 r
= RegCloseKey (hkSubKey
);
6452 if (r
!= ERROR_SUCCESS
)
6453 WARN ("RegCloseKey returned %i\n", r
);
6457 ret
= RegCloseKey (hkSubKey
);
6458 if (ret
!= ERROR_SUCCESS
)
6460 ERR ("RegCloseKey returned %i\n", ret
);
6464 return ERROR_SUCCESS
;
6467 /*******************************************************************************
6468 * EnumPrinterDataExA [WINSPOOL.@]
6470 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6471 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6472 * what Windows 2000 SP1 does.
6475 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6476 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6477 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6481 DWORD ret
, dwIndex
, dwBufSize
;
6485 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6487 if (pKeyName
== NULL
|| *pKeyName
== 0)
6488 return ERROR_INVALID_PARAMETER
;
6490 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6493 ret
= GetLastError ();
6494 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6498 hHeap
= GetProcessHeap ();
6501 ERR ("GetProcessHeap failed\n");
6502 return ERROR_OUTOFMEMORY
;
6505 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6506 if (pKeyNameW
== NULL
)
6508 ERR ("Failed to allocate %i bytes from process heap\n",
6509 (LONG
)(len
* sizeof (WCHAR
)));
6510 return ERROR_OUTOFMEMORY
;
6513 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6515 ret
= GetLastError ();
6516 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6517 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6518 WARN ("HeapFree failed with code %i\n", GetLastError ());
6522 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6523 pcbEnumValues
, pnEnumValues
);
6524 if (ret
!= ERROR_SUCCESS
)
6526 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6527 WARN ("HeapFree failed with code %i\n", GetLastError ());
6528 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6532 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6534 ret
= GetLastError ();
6535 ERR ("HeapFree failed with code %i\n", ret
);
6539 if (*pnEnumValues
== 0) /* empty key */
6540 return ERROR_SUCCESS
;
6543 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6545 PPRINTER_ENUM_VALUESW ppev
=
6546 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6548 if (dwBufSize
< ppev
->cbValueName
)
6549 dwBufSize
= ppev
->cbValueName
;
6551 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6552 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6553 dwBufSize
= ppev
->cbData
;
6556 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6558 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6559 if (pBuffer
== NULL
)
6561 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6562 return ERROR_OUTOFMEMORY
;
6565 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6567 PPRINTER_ENUM_VALUESW ppev
=
6568 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6570 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6571 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6575 ret
= GetLastError ();
6576 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6577 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6578 WARN ("HeapFree failed with code %i\n", GetLastError ());
6582 memcpy (ppev
->pValueName
, pBuffer
, len
);
6584 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6586 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6587 ppev
->dwType
!= REG_MULTI_SZ
)
6590 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6591 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6594 ret
= GetLastError ();
6595 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6596 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6597 WARN ("HeapFree failed with code %i\n", GetLastError ());
6601 memcpy (ppev
->pData
, pBuffer
, len
);
6603 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6604 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6607 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6609 ret
= GetLastError ();
6610 ERR ("HeapFree failed with code %i\n", ret
);
6614 return ERROR_SUCCESS
;
6617 /******************************************************************************
6618 * AbortPrinter (WINSPOOL.@)
6620 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6622 FIXME("(%p), stub!\n", hPrinter
);
6626 /******************************************************************************
6627 * AddPortA (WINSPOOL.@)
6632 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6634 LPWSTR nameW
= NULL
;
6635 LPWSTR monitorW
= NULL
;
6639 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6642 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6643 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6644 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6648 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6649 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6650 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6652 res
= AddPortW(nameW
, hWnd
, monitorW
);
6653 HeapFree(GetProcessHeap(), 0, nameW
);
6654 HeapFree(GetProcessHeap(), 0, monitorW
);
6658 /******************************************************************************
6659 * AddPortW (WINSPOOL.@)
6661 * Add a Port for a specific Monitor
6664 * pName [I] Servername or NULL (local Computer)
6665 * hWnd [I] Handle to parent Window for the Dialog-Box
6666 * pMonitorName [I] Name of the Monitor that manage the Port
6673 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6675 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6677 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6679 if (!pMonitorName
) {
6680 SetLastError(RPC_X_NULL_REF_POINTER
);
6684 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6687 /******************************************************************************
6688 * AddPortExA (WINSPOOL.@)
6693 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6696 PORT_INFO_2A
* pi2A
;
6697 LPWSTR nameW
= NULL
;
6698 LPWSTR monitorW
= NULL
;
6702 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6704 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6705 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6707 if ((level
< 1) || (level
> 2)) {
6708 SetLastError(ERROR_INVALID_LEVEL
);
6713 SetLastError(ERROR_INVALID_PARAMETER
);
6718 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6719 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6720 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6724 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6725 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6726 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6729 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6731 if (pi2A
->pPortName
) {
6732 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6733 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6734 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6738 if (pi2A
->pMonitorName
) {
6739 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6740 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6741 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6744 if (pi2A
->pDescription
) {
6745 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6746 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6747 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6749 pi2W
.fPortType
= pi2A
->fPortType
;
6750 pi2W
.Reserved
= pi2A
->Reserved
;
6753 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6755 HeapFree(GetProcessHeap(), 0, nameW
);
6756 HeapFree(GetProcessHeap(), 0, monitorW
);
6757 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6758 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6759 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6764 /******************************************************************************
6765 * AddPortExW (WINSPOOL.@)
6767 * Add a Port for a specific Monitor, without presenting a user interface
6770 * pName [I] Servername or NULL (local Computer)
6771 * level [I] Structure-Level (1 or 2) for pBuffer
6772 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6773 * pMonitorName [I] Name of the Monitor that manage the Port
6780 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6784 pi2
= (PORT_INFO_2W
*) pBuffer
;
6786 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6787 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6788 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6789 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6791 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6793 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6794 SetLastError(ERROR_INVALID_PARAMETER
);
6798 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6801 /******************************************************************************
6802 * AddPrinterConnectionA (WINSPOOL.@)
6804 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6806 FIXME("%s\n", debugstr_a(pName
));
6810 /******************************************************************************
6811 * AddPrinterConnectionW (WINSPOOL.@)
6813 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6815 FIXME("%s\n", debugstr_w(pName
));
6819 /******************************************************************************
6820 * AddPrinterDriverExW (WINSPOOL.@)
6822 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6825 * pName [I] Servername or NULL (local Computer)
6826 * level [I] Level for the supplied DRIVER_INFO_*W struct
6827 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6828 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6835 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6837 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6839 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6841 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6842 SetLastError(ERROR_INVALID_LEVEL
);
6847 SetLastError(ERROR_INVALID_PARAMETER
);
6851 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6854 /******************************************************************************
6855 * AddPrinterDriverExA (WINSPOOL.@)
6857 * See AddPrinterDriverExW.
6860 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6862 DRIVER_INFO_8A
*diA
;
6864 LPWSTR nameW
= NULL
;
6869 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6871 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6872 ZeroMemory(&diW
, sizeof(diW
));
6874 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6875 SetLastError(ERROR_INVALID_LEVEL
);
6880 SetLastError(ERROR_INVALID_PARAMETER
);
6884 /* convert servername to unicode */
6886 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6887 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6888 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6892 diW
.cVersion
= diA
->cVersion
;
6895 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6896 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6897 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6900 if (diA
->pEnvironment
) {
6901 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6902 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6903 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6906 if (diA
->pDriverPath
) {
6907 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6908 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6909 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6912 if (diA
->pDataFile
) {
6913 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6914 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6915 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6918 if (diA
->pConfigFile
) {
6919 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6920 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6921 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6924 if ((Level
> 2) && diA
->pDependentFiles
) {
6925 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6926 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6927 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6928 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6931 if ((Level
> 2) && diA
->pMonitorName
) {
6932 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6933 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6934 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6937 if ((Level
> 3) && diA
->pDefaultDataType
) {
6938 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6939 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6940 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6943 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6944 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6945 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6946 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6947 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6950 if ((Level
> 5) && diA
->pszMfgName
) {
6951 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6952 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6953 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6956 if ((Level
> 5) && diA
->pszOEMUrl
) {
6957 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6958 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6959 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6962 if ((Level
> 5) && diA
->pszHardwareID
) {
6963 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6964 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6965 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6968 if ((Level
> 5) && diA
->pszProvider
) {
6969 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6970 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6971 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6975 FIXME("level %u is incomplete\n", Level
);
6978 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6979 TRACE("got %u with %u\n", res
, GetLastError());
6980 HeapFree(GetProcessHeap(), 0, nameW
);
6981 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6982 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6983 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6984 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6985 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6986 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6987 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6988 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6989 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6990 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6991 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6992 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6993 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6995 TRACE("=> %u with %u\n", res
, GetLastError());
6999 /******************************************************************************
7000 * ConfigurePortA (WINSPOOL.@)
7002 * See ConfigurePortW.
7005 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
7007 LPWSTR nameW
= NULL
;
7008 LPWSTR portW
= NULL
;
7012 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
7014 /* convert servername to unicode */
7016 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7017 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7018 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7021 /* convert portname to unicode */
7023 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
7024 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7025 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
7028 res
= ConfigurePortW(nameW
, hWnd
, portW
);
7029 HeapFree(GetProcessHeap(), 0, nameW
);
7030 HeapFree(GetProcessHeap(), 0, portW
);
7034 /******************************************************************************
7035 * ConfigurePortW (WINSPOOL.@)
7037 * Display the Configuration-Dialog for a specific Port
7040 * pName [I] Servername or NULL (local Computer)
7041 * hWnd [I] Handle to parent Window for the Dialog-Box
7042 * pPortName [I] Name of the Port, that should be configured
7049 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
7052 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
7054 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7057 SetLastError(RPC_X_NULL_REF_POINTER
);
7061 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
7064 /******************************************************************************
7065 * ConnectToPrinterDlg (WINSPOOL.@)
7067 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
7069 FIXME("%p %x\n", hWnd
, Flags
);
7073 /******************************************************************************
7074 * DeletePrinterConnectionA (WINSPOOL.@)
7076 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
7078 FIXME("%s\n", debugstr_a(pName
));
7082 /******************************************************************************
7083 * DeletePrinterConnectionW (WINSPOOL.@)
7085 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
7087 FIXME("%s\n", debugstr_w(pName
));
7091 /******************************************************************************
7092 * DeletePrinterDriverExW (WINSPOOL.@)
7094 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
7095 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7100 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7101 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
7103 if(pName
&& pName
[0])
7105 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
7106 SetLastError(ERROR_INVALID_PARAMETER
);
7112 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
7113 SetLastError(ERROR_INVALID_PARAMETER
);
7117 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
7121 ERR("Can't open drivers key\n");
7125 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
7128 RegCloseKey(hkey_drivers
);
7133 /******************************************************************************
7134 * DeletePrinterDriverExA (WINSPOOL.@)
7136 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
7137 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7139 UNICODE_STRING NameW
, EnvW
, DriverW
;
7142 asciitounicode(&NameW
, pName
);
7143 asciitounicode(&EnvW
, pEnvironment
);
7144 asciitounicode(&DriverW
, pDriverName
);
7146 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
7148 RtlFreeUnicodeString(&DriverW
);
7149 RtlFreeUnicodeString(&EnvW
);
7150 RtlFreeUnicodeString(&NameW
);
7155 /******************************************************************************
7156 * DeletePrinterDataExW (WINSPOOL.@)
7158 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
7161 FIXME("%p %s %s\n", hPrinter
,
7162 debugstr_w(pKeyName
), debugstr_w(pValueName
));
7163 return ERROR_INVALID_PARAMETER
;
7166 /******************************************************************************
7167 * DeletePrinterDataExA (WINSPOOL.@)
7169 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
7172 FIXME("%p %s %s\n", hPrinter
,
7173 debugstr_a(pKeyName
), debugstr_a(pValueName
));
7174 return ERROR_INVALID_PARAMETER
;
7177 /******************************************************************************
7178 * DeletePrintProcessorA (WINSPOOL.@)
7180 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
7182 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7183 debugstr_a(pPrintProcessorName
));
7187 /******************************************************************************
7188 * DeletePrintProcessorW (WINSPOOL.@)
7190 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
7192 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7193 debugstr_w(pPrintProcessorName
));
7197 /******************************************************************************
7198 * DeletePrintProvidorA (WINSPOOL.@)
7200 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
7202 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7203 debugstr_a(pPrintProviderName
));
7207 /******************************************************************************
7208 * DeletePrintProvidorW (WINSPOOL.@)
7210 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
7212 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7213 debugstr_w(pPrintProviderName
));
7217 /******************************************************************************
7218 * EnumFormsA (WINSPOOL.@)
7220 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7221 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7223 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7224 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7228 /******************************************************************************
7229 * EnumFormsW (WINSPOOL.@)
7231 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7232 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7234 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7235 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7239 /*****************************************************************************
7240 * EnumMonitorsA [WINSPOOL.@]
7242 * See EnumMonitorsW.
7245 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7246 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7249 LPBYTE bufferW
= NULL
;
7250 LPWSTR nameW
= NULL
;
7252 DWORD numentries
= 0;
7255 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
7256 cbBuf
, pcbNeeded
, pcReturned
);
7258 /* convert servername to unicode */
7260 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7261 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7262 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7264 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7265 needed
= cbBuf
* sizeof(WCHAR
);
7266 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7267 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7269 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7270 if (pcbNeeded
) needed
= *pcbNeeded
;
7271 /* HeapReAlloc return NULL, when bufferW was NULL */
7272 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7273 HeapAlloc(GetProcessHeap(), 0, needed
);
7275 /* Try again with the large Buffer */
7276 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7278 numentries
= pcReturned
? *pcReturned
: 0;
7281 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7282 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7285 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7286 DWORD entrysize
= 0;
7289 LPMONITOR_INFO_2W mi2w
;
7290 LPMONITOR_INFO_2A mi2a
;
7292 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7293 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
7295 /* First pass: calculate the size for all Entries */
7296 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7297 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7299 while (index
< numentries
) {
7301 needed
+= entrysize
; /* MONITOR_INFO_?A */
7302 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
7304 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7305 NULL
, 0, NULL
, NULL
);
7307 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7308 NULL
, 0, NULL
, NULL
);
7309 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7310 NULL
, 0, NULL
, NULL
);
7312 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7313 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7314 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7317 /* check for errors and quit on failure */
7318 if (cbBuf
< needed
) {
7319 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7323 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
7324 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
7325 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7326 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7327 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7329 /* Second Pass: Fill the User Buffer (if we have one) */
7330 while ((index
< numentries
) && pMonitors
) {
7332 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7334 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7335 ptr
, cbBuf
, NULL
, NULL
);
7339 mi2a
->pEnvironment
= ptr
;
7340 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7341 ptr
, cbBuf
, NULL
, NULL
);
7345 mi2a
->pDLLName
= ptr
;
7346 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7347 ptr
, cbBuf
, NULL
, NULL
);
7351 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7352 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7353 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7357 if (pcbNeeded
) *pcbNeeded
= needed
;
7358 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7360 HeapFree(GetProcessHeap(), 0, nameW
);
7361 HeapFree(GetProcessHeap(), 0, bufferW
);
7363 TRACE("returning %d with %d (%d byte for %d entries)\n",
7364 (res
), GetLastError(), needed
, numentries
);
7370 /*****************************************************************************
7371 * EnumMonitorsW [WINSPOOL.@]
7373 * Enumerate available Port-Monitors
7376 * pName [I] Servername or NULL (local Computer)
7377 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7378 * pMonitors [O] PTR to Buffer that receives the Result
7379 * cbBuf [I] Size of Buffer at pMonitors
7380 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7381 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7385 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7388 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7389 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7392 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7393 cbBuf
, pcbNeeded
, pcReturned
);
7395 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7397 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
7398 SetLastError(RPC_X_NULL_REF_POINTER
);
7402 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
7405 /******************************************************************************
7406 * SpoolerInit (WINSPOOL.@)
7408 * Initialize the Spooler
7415 * The function fails on windows, when the spooler service is not running
7418 BOOL WINAPI
SpoolerInit(void)
7421 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7425 /******************************************************************************
7426 * XcvDataW (WINSPOOL.@)
7428 * Execute commands in the Printmonitor DLL
7431 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7432 * pszDataName [i] Name of the command to execute
7433 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7434 * cbInputData [i] Size in Bytes of Buffer at pInputData
7435 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7436 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7437 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7438 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7445 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7446 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7448 * Minimal List of commands, that a Printmonitor DLL should support:
7450 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7451 *| "AddPort" : Add a Port
7452 *| "DeletePort": Delete a Port
7454 * Many Printmonitors support additional commands. Examples for localspl.dll:
7455 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7456 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7459 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7460 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7461 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7463 opened_printer_t
*printer
;
7465 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7466 pInputData
, cbInputData
, pOutputData
,
7467 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7469 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7471 printer
= get_opened_printer(hXcv
);
7472 if (!printer
|| (!printer
->backend_printer
)) {
7473 SetLastError(ERROR_INVALID_HANDLE
);
7477 if (!pcbOutputNeeded
) {
7478 SetLastError(ERROR_INVALID_PARAMETER
);
7482 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7483 SetLastError(RPC_X_NULL_REF_POINTER
);
7487 *pcbOutputNeeded
= 0;
7489 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
7490 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7494 /*****************************************************************************
7495 * EnumPrinterDataA [WINSPOOL.@]
7498 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7499 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7500 DWORD cbData
, LPDWORD pcbData
)
7502 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7503 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7504 return ERROR_NO_MORE_ITEMS
;
7507 /*****************************************************************************
7508 * EnumPrinterDataW [WINSPOOL.@]
7511 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7512 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7513 DWORD cbData
, LPDWORD pcbData
)
7515 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7516 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7517 return ERROR_NO_MORE_ITEMS
;
7520 /*****************************************************************************
7521 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7524 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7525 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7526 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7528 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7529 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7530 pcbNeeded
, pcReturned
);
7534 /*****************************************************************************
7535 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7538 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7539 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7540 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7542 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7543 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7544 pcbNeeded
, pcReturned
);
7548 /*****************************************************************************
7549 * EnumPrintProcessorsA [WINSPOOL.@]
7551 * See EnumPrintProcessorsW.
7554 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7555 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7558 LPBYTE bufferW
= NULL
;
7559 LPWSTR nameW
= NULL
;
7562 DWORD numentries
= 0;
7565 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7566 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7568 /* convert names to unicode */
7570 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7571 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7572 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7575 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
7576 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7577 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
7580 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7581 needed
= cbBuf
* sizeof(WCHAR
);
7582 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7583 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7585 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7586 if (pcbNeeded
) needed
= *pcbNeeded
;
7587 /* HeapReAlloc return NULL, when bufferW was NULL */
7588 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7589 HeapAlloc(GetProcessHeap(), 0, needed
);
7591 /* Try again with the large Buffer */
7592 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7594 numentries
= pcReturned
? *pcReturned
: 0;
7598 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7601 PPRINTPROCESSOR_INFO_1W ppiw
;
7602 PPRINTPROCESSOR_INFO_1A ppia
;
7604 /* First pass: calculate the size for all Entries */
7605 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7606 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7608 while (index
< numentries
) {
7610 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7611 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7613 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7614 NULL
, 0, NULL
, NULL
);
7616 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7617 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7620 /* check for errors and quit on failure */
7621 if (cbBuf
< needed
) {
7622 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7627 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7628 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7629 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7630 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7631 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7633 /* Second Pass: Fill the User Buffer (if we have one) */
7634 while ((index
< numentries
) && pPPInfo
) {
7636 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7638 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7639 ptr
, cbBuf
, NULL
, NULL
);
7643 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7644 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7649 if (pcbNeeded
) *pcbNeeded
= needed
;
7650 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7652 HeapFree(GetProcessHeap(), 0, nameW
);
7653 HeapFree(GetProcessHeap(), 0, envW
);
7654 HeapFree(GetProcessHeap(), 0, bufferW
);
7656 TRACE("returning %d with %d (%d byte for %d entries)\n",
7657 (res
), GetLastError(), needed
, numentries
);
7662 /*****************************************************************************
7663 * EnumPrintProcessorsW [WINSPOOL.@]
7665 * Enumerate available Print Processors
7668 * pName [I] Servername or NULL (local Computer)
7669 * pEnvironment [I] Printing-Environment or NULL (Default)
7670 * Level [I] Structure-Level (Only 1 is allowed)
7671 * pPPInfo [O] PTR to Buffer that receives the Result
7672 * cbBuf [I] Size of Buffer at pPPInfo
7673 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7674 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7678 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7681 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7682 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7685 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7686 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7688 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7690 if (!pcbNeeded
|| !pcReturned
) {
7691 SetLastError(RPC_X_NULL_REF_POINTER
);
7695 if (!pPPInfo
&& (cbBuf
> 0)) {
7696 SetLastError(ERROR_INVALID_USER_BUFFER
);
7700 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7701 cbBuf
, pcbNeeded
, pcReturned
);
7704 /*****************************************************************************
7705 * ExtDeviceMode [WINSPOOL.@]
7708 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7709 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7712 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7713 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7714 debugstr_a(pProfile
), fMode
);
7718 /*****************************************************************************
7719 * FindClosePrinterChangeNotification [WINSPOOL.@]
7722 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7724 FIXME("Stub: %p\n", hChange
);
7728 /*****************************************************************************
7729 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7732 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7733 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7735 FIXME("Stub: %p %x %x %p\n",
7736 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7737 return INVALID_HANDLE_VALUE
;
7740 /*****************************************************************************
7741 * FindNextPrinterChangeNotification [WINSPOOL.@]
7744 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7745 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7747 FIXME("Stub: %p %p %p %p\n",
7748 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7752 /*****************************************************************************
7753 * FreePrinterNotifyInfo [WINSPOOL.@]
7756 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7758 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7762 /*****************************************************************************
7765 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7766 * ansi depending on the unicode parameter.
7768 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7778 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7781 memcpy(ptr
, str
, *size
);
7788 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7791 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7798 /*****************************************************************************
7801 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7802 LPDWORD pcbNeeded
, BOOL unicode
)
7804 DWORD size
, left
= cbBuf
;
7805 BOOL space
= (cbBuf
> 0);
7812 ji1
->JobId
= job
->job_id
;
7815 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7816 if(space
&& size
<= left
)
7818 ji1
->pDocument
= (LPWSTR
)ptr
;
7826 if (job
->printer_name
)
7828 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7829 if(space
&& size
<= left
)
7831 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7843 /*****************************************************************************
7846 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7847 LPDWORD pcbNeeded
, BOOL unicode
)
7849 DWORD size
, left
= cbBuf
;
7851 BOOL space
= (cbBuf
> 0);
7853 LPDEVMODEA dmA
= NULL
;
7860 ji2
->JobId
= job
->job_id
;
7863 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7864 if(space
&& size
<= left
)
7866 ji2
->pDocument
= (LPWSTR
)ptr
;
7874 if (job
->printer_name
)
7876 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7877 if(space
&& size
<= left
)
7879 ji2
->pPrinterName
= (LPWSTR
)ptr
;
7892 dmA
= DEVMODEdupWtoA(job
->devmode
);
7893 devmode
= (LPDEVMODEW
) dmA
;
7894 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
7898 devmode
= job
->devmode
;
7899 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
7903 FIXME("Can't convert DEVMODE W to A\n");
7906 /* align DEVMODE to a DWORD boundary */
7907 shift
= (4 - (*pcbNeeded
& 3)) & 3;
7913 memcpy(ptr
, devmode
, size
-shift
);
7914 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
7915 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
7928 /*****************************************************************************
7931 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7932 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7935 DWORD needed
= 0, size
;
7939 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7941 EnterCriticalSection(&printer_handles_cs
);
7942 job
= get_job(hPrinter
, JobId
);
7949 size
= sizeof(JOB_INFO_1W
);
7954 memset(pJob
, 0, size
);
7958 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7963 size
= sizeof(JOB_INFO_2W
);
7968 memset(pJob
, 0, size
);
7972 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7977 size
= sizeof(JOB_INFO_3
);
7981 memset(pJob
, 0, size
);
7990 SetLastError(ERROR_INVALID_LEVEL
);
7994 *pcbNeeded
= needed
;
7996 LeaveCriticalSection(&printer_handles_cs
);
8000 /*****************************************************************************
8001 * GetJobA [WINSPOOL.@]
8004 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8005 DWORD cbBuf
, LPDWORD pcbNeeded
)
8007 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
8010 /*****************************************************************************
8011 * GetJobW [WINSPOOL.@]
8014 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8015 DWORD cbBuf
, LPDWORD pcbNeeded
)
8017 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
8020 /*****************************************************************************
8023 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
8026 char *unixname
, *cmdA
;
8028 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
8034 if(!(unixname
= wine_get_unix_file_name(filename
)))
8037 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
8038 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
8039 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
8041 TRACE("printing with: %s\n", cmdA
);
8043 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
8048 ERR("pipe() failed!\n");
8052 if ((pid
= fork()) == 0)
8058 /* reset signals that we previously set to SIG_IGN */
8059 signal(SIGPIPE
, SIG_DFL
);
8061 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
8066 ERR("fork() failed!\n");
8070 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
8071 write(fds
[1], buf
, no_read
);
8078 wret
= waitpid(pid
, &status
, 0);
8079 } while (wret
< 0 && errno
== EINTR
);
8082 ERR("waitpid() failed!\n");
8085 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
8087 ERR("child process failed! %d\n", status
);
8094 if(file_fd
!= -1) close(file_fd
);
8095 if(fds
[0] != -1) close(fds
[0]);
8096 if(fds
[1] != -1) close(fds
[1]);
8098 HeapFree(GetProcessHeap(), 0, cmdA
);
8099 HeapFree(GetProcessHeap(), 0, unixname
);
8106 /*****************************************************************************
8109 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
8112 const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8115 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
8116 sprintfW(cmd
, fmtW
, printer_name
);
8118 r
= schedule_pipe(cmd
, filename
);
8120 HeapFree(GetProcessHeap(), 0, cmd
);
8124 #ifdef SONAME_LIBCUPS
8125 /*****************************************************************************
8126 * get_cups_jobs_ticket_options
8128 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8129 * The CUPS scheduler only looks for these in Print-File requests, and since
8130 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8133 static int get_cups_job_ticket_options( const char *file
, int num_options
, cups_option_t
**options
)
8135 FILE *fp
= fopen( file
, "r" );
8136 char buf
[257]; /* DSC max of 256 + '\0' */
8137 const char *ps_adobe
= "%!PS-Adobe-";
8138 const char *cups_job
= "%cupsJobTicket:";
8140 if (!fp
) return num_options
;
8141 if (!fgets( buf
, sizeof(buf
), fp
)) goto end
;
8142 if (strncmp( buf
, ps_adobe
, strlen( ps_adobe
) )) goto end
;
8143 while (fgets( buf
, sizeof(buf
), fp
))
8145 if (strncmp( buf
, cups_job
, strlen( cups_job
) )) break;
8146 num_options
= pcupsParseOptions( buf
+ strlen( cups_job
), num_options
, options
);
8155 /*****************************************************************************
8158 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
8160 #ifdef SONAME_LIBCUPS
8163 char *unixname
, *queue
, *unix_doc_title
;
8166 int num_options
= 0, i
;
8167 cups_option_t
*options
= NULL
;
8169 if(!(unixname
= wine_get_unix_file_name(filename
)))
8172 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
8173 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
8174 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
8176 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
8177 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
8178 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
8180 num_options
= get_cups_job_ticket_options( unixname
, num_options
, &options
);
8182 TRACE( "printing via cups with options:\n" );
8183 for (i
= 0; i
< num_options
; i
++)
8184 TRACE( "\t%d: %s = %s\n", i
, options
[i
].name
, options
[i
].value
);
8186 ret
= pcupsPrintFile( queue
, unixname
, unix_doc_title
, num_options
, options
);
8188 pcupsFreeOptions( num_options
, options
);
8190 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
8191 HeapFree(GetProcessHeap(), 0, queue
);
8192 HeapFree(GetProcessHeap(), 0, unixname
);
8198 return schedule_lpr(printer_name
, filename
);
8202 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
8209 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
8213 if(HIWORD(wparam
) == BN_CLICKED
)
8215 if(LOWORD(wparam
) == IDOK
)
8218 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
8221 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
8222 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
8224 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
8226 WCHAR caption
[200], message
[200];
8229 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
8230 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
8231 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
8232 if(mb_ret
== IDCANCEL
)
8234 HeapFree(GetProcessHeap(), 0, filename
);
8238 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
8239 if(hf
== INVALID_HANDLE_VALUE
)
8241 WCHAR caption
[200], message
[200];
8243 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
8244 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
8245 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
8246 HeapFree(GetProcessHeap(), 0, filename
);
8250 DeleteFileW(filename
);
8251 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
8253 EndDialog(hwnd
, IDOK
);
8256 if(LOWORD(wparam
) == IDCANCEL
)
8258 EndDialog(hwnd
, IDCANCEL
);
8267 /*****************************************************************************
8270 static BOOL
get_filename(LPWSTR
*filename
)
8272 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
8273 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
8276 /*****************************************************************************
8279 static BOOL
schedule_file(LPCWSTR filename
)
8281 LPWSTR output
= NULL
;
8283 if(get_filename(&output
))
8286 TRACE("copy to %s\n", debugstr_w(output
));
8287 r
= CopyFileW(filename
, output
, FALSE
);
8288 HeapFree(GetProcessHeap(), 0, output
);
8294 /*****************************************************************************
8297 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
8299 int in_fd
, out_fd
, no_read
;
8302 char *unixname
, *outputA
;
8305 if(!(unixname
= wine_get_unix_file_name(filename
)))
8308 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
8309 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
8310 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
8312 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
8313 in_fd
= open(unixname
, O_RDONLY
);
8314 if(out_fd
== -1 || in_fd
== -1)
8317 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
8318 write(out_fd
, buf
, no_read
);
8322 if(in_fd
!= -1) close(in_fd
);
8323 if(out_fd
!= -1) close(out_fd
);
8324 HeapFree(GetProcessHeap(), 0, outputA
);
8325 HeapFree(GetProcessHeap(), 0, unixname
);
8329 /*****************************************************************************
8330 * ScheduleJob [WINSPOOL.@]
8333 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
8335 opened_printer_t
*printer
;
8337 struct list
*cursor
, *cursor2
;
8339 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
8340 EnterCriticalSection(&printer_handles_cs
);
8341 printer
= get_opened_printer(hPrinter
);
8345 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
8347 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
8350 if(job
->job_id
!= dwJobID
) continue;
8352 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
8353 if(hf
!= INVALID_HANDLE_VALUE
)
8355 PRINTER_INFO_5W
*pi5
= NULL
;
8356 LPWSTR portname
= job
->portname
;
8360 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8361 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8365 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
8366 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
8367 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
8368 portname
= pi5
->pPortName
;
8370 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
8371 debugstr_w(portname
));
8375 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8376 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
8378 DWORD type
, count
= sizeof(output
);
8379 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
8382 if(output
[0] == '|')
8384 ret
= schedule_pipe(output
+ 1, job
->filename
);
8388 ret
= schedule_unixfile(output
, job
->filename
);
8390 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
8392 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
8394 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
8396 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
8398 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
8400 ret
= schedule_file(job
->filename
);
8404 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
8406 HeapFree(GetProcessHeap(), 0, pi5
);
8408 DeleteFileW(job
->filename
);
8410 list_remove(cursor
);
8411 HeapFree(GetProcessHeap(), 0, job
->document_title
);
8412 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
8413 HeapFree(GetProcessHeap(), 0, job
->portname
);
8414 HeapFree(GetProcessHeap(), 0, job
->filename
);
8415 HeapFree(GetProcessHeap(), 0, job
->devmode
);
8416 HeapFree(GetProcessHeap(), 0, job
);
8420 LeaveCriticalSection(&printer_handles_cs
);
8424 /*****************************************************************************
8425 * StartDocDlgA [WINSPOOL.@]
8427 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
8429 UNICODE_STRING usBuffer
;
8432 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
8435 docW
.cbSize
= sizeof(docW
);
8436 if (doc
->lpszDocName
)
8438 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
8439 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
8441 if (doc
->lpszOutput
)
8443 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
8444 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
8446 if (doc
->lpszDatatype
)
8448 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
8449 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
8451 docW
.fwType
= doc
->fwType
;
8453 retW
= StartDocDlgW(hPrinter
, &docW
);
8457 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
8458 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
8459 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
8460 HeapFree(GetProcessHeap(), 0, retW
);
8463 HeapFree(GetProcessHeap(), 0, datatypeW
);
8464 HeapFree(GetProcessHeap(), 0, outputW
);
8465 HeapFree(GetProcessHeap(), 0, docnameW
);
8470 /*****************************************************************************
8471 * StartDocDlgW [WINSPOOL.@]
8473 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8474 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8475 * port is "FILE:". Also returns the full path if passed a relative path.
8477 * The caller should free the returned string from the process heap.
8479 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
8484 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
8486 PRINTER_INFO_5W
*pi5
;
8487 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
8488 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
8490 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
8491 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
8492 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
8494 HeapFree(GetProcessHeap(), 0, pi5
);
8497 HeapFree(GetProcessHeap(), 0, pi5
);
8500 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
8504 if (get_filename(&name
))
8506 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
8508 HeapFree(GetProcessHeap(), 0, name
);
8511 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8512 GetFullPathNameW(name
, len
, ret
, NULL
);
8513 HeapFree(GetProcessHeap(), 0, name
);
8518 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8521 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8522 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8524 attr
= GetFileAttributesW(ret
);
8525 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8527 HeapFree(GetProcessHeap(), 0, ret
);