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>
47 #ifdef HAVE_CUPS_PPD_H
48 # include <cups/ppd.h>
51 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
52 #define GetCurrentProcess GetCurrentProcess_Mac
53 #define GetCurrentThread GetCurrentThread_Mac
54 #define LoadResource LoadResource_Mac
55 #define AnimatePalette AnimatePalette_Mac
56 #define EqualRgn EqualRgn_Mac
57 #define FillRgn FillRgn_Mac
58 #define FrameRgn FrameRgn_Mac
59 #define GetPixel GetPixel_Mac
60 #define InvertRgn InvertRgn_Mac
61 #define LineTo LineTo_Mac
62 #define OffsetRgn OffsetRgn_Mac
63 #define PaintRgn PaintRgn_Mac
64 #define Polygon Polygon_Mac
65 #define ResizePalette ResizePalette_Mac
66 #define SetRectRgn SetRectRgn_Mac
67 #define EqualRect EqualRect_Mac
68 #define FillRect FillRect_Mac
69 #define FrameRect FrameRect_Mac
70 #define GetCursor GetCursor_Mac
71 #define InvertRect InvertRect_Mac
72 #define OffsetRect OffsetRect_Mac
73 #define PtInRect PtInRect_Mac
74 #define SetCursor SetCursor_Mac
75 #define SetRect SetRect_Mac
76 #define ShowCursor ShowCursor_Mac
77 #define UnionRect UnionRect_Mac
78 #include <ApplicationServices/ApplicationServices.h>
79 #undef GetCurrentProcess
80 #undef GetCurrentThread
108 #include "wine/library.h"
112 #include "winerror.h"
115 #include "winspool.h"
116 #include "winternl.h"
117 #include "wine/windef16.h"
118 #include "wine/unicode.h"
119 #include "wine/debug.h"
120 #include "wine/list.h"
123 #include "ddk/winsplp.h"
126 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
128 /* ############################### */
130 static CRITICAL_SECTION printer_handles_cs
;
131 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
133 0, 0, &printer_handles_cs
,
134 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
135 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
137 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
139 /* ############################### */
154 HANDLE backend_printer
;
165 WCHAR
*document_title
;
175 LPCWSTR versionregpath
;
176 LPCWSTR versionsubdir
;
179 /* ############################### */
181 static opened_printer_t
**printer_handles
;
182 static UINT nb_printer_handles
;
183 static LONG next_job_id
= 1;
185 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
186 WORD fwCapability
, LPSTR lpszOutput
,
188 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
189 LPSTR lpszDevice
, LPSTR lpszPort
,
190 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
193 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
194 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
195 'c','o','n','t','r','o','l','\\',
196 'P','r','i','n','t','\\',
197 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
198 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
200 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
201 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
202 'C','o','n','t','r','o','l','\\',
203 'P','r','i','n','t','\\',
204 'P','r','i','n','t','e','r','s',0};
206 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
207 'M','i','c','r','o','s','o','f','t','\\',
208 'W','i','n','d','o','w','s',' ','N','T','\\',
209 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
210 'W','i','n','d','o','w','s',0};
212 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
213 'M','i','c','r','o','s','o','f','t','\\',
214 'W','i','n','d','o','w','s',' ','N','T','\\',
215 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
216 'D','e','v','i','c','e','s',0};
218 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
219 'M','i','c','r','o','s','o','f','t','\\',
220 'W','i','n','d','o','w','s',' ','N','T','\\',
221 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
222 'P','r','i','n','t','e','r','P','o','r','t','s',0};
224 static WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
225 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
226 static WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
227 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
228 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
229 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
230 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
231 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
232 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
233 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
235 static const WCHAR AttributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0};
236 static const WCHAR backslashW
[] = {'\\',0};
237 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
238 'i','o','n',' ','F','i','l','e',0};
239 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
240 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
241 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
242 static const WCHAR Default_PriorityW
[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
243 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
244 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
245 static const WCHAR dnsTimeoutW
[] = {'d','n','s','T','i','m','e','o','u','t',0};
246 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
247 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
248 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
249 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
250 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
251 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
252 static const WCHAR NameW
[] = {'N','a','m','e',0};
253 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
254 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
255 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
256 static const WCHAR PortW
[] = {'P','o','r','t',0};
257 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
258 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
259 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
260 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
261 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
262 static const WCHAR PriorityW
[] = {'P','r','i','o','r','i','t','y',0};
263 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
264 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
265 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
266 static const WCHAR StartTimeW
[] = {'S','t','a','r','t','T','i','m','e',0};
267 static const WCHAR StatusW
[] = {'S','t','a','t','u','s',0};
268 static const WCHAR txTimeoutW
[] = {'t','x','T','i','m','e','o','u','t',0};
269 static const WCHAR UntilTimeW
[] = {'U','n','t','i','l','T','i','m','e',0};
270 static WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
271 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
272 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
273 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
274 static WCHAR rawW
[] = {'R','A','W',0};
275 static WCHAR driver_9x
[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
276 static WCHAR driver_nt
[] = {'w','i','n','e','p','s','.','d','r','v',0};
277 static const WCHAR timeout_15_45
[] = {',','1','5',',','4','5',0};
278 static const WCHAR commaW
[] = {',',0};
279 static WCHAR emptyStringW
[] = {0};
281 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
283 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
284 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
285 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
287 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
288 'D','o','c','u','m','e','n','t',0};
290 static const WCHAR PPD_Overrides
[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
291 static const WCHAR DefaultPageSize
[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
293 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
294 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
295 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
296 0, sizeof(DRIVER_INFO_8W
)};
299 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
300 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
301 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
302 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
303 sizeof(PRINTER_INFO_9W
)};
305 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
306 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
307 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
309 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
311 /******************************************************************
312 * validate the user-supplied printing-environment [internal]
315 * env [I] PTR to Environment-String or NULL
319 * Success: PTR to printenv_t
322 * An empty string is handled the same way as NULL.
323 * SetLastError(ERROR_INVALID_ENVIRONMENT) is called on Failure
327 static const printenv_t
* validate_envW(LPCWSTR env
)
329 const printenv_t
*result
= NULL
;
332 TRACE("testing %s\n", debugstr_w(env
));
335 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
337 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
339 result
= all_printenv
[i
];
344 if (result
== NULL
) {
345 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
346 SetLastError(ERROR_INVALID_ENVIRONMENT
);
348 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
352 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
354 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
360 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
361 if passed a NULL string. This returns NULLs to the result.
363 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
367 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
368 return usBufferPtr
->Buffer
;
370 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
374 static LPWSTR
strdupW(LPCWSTR p
)
380 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
381 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
386 static LPSTR
strdupWtoA( LPCWSTR str
)
391 if (!str
) return NULL
;
392 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
393 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
394 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
398 static DEVMODEW
*dup_devmode( const DEVMODEW
*dm
)
402 if (!dm
) return NULL
;
403 ret
= HeapAlloc( GetProcessHeap(), 0, dm
->dmSize
+ dm
->dmDriverExtra
);
404 if (ret
) memcpy( ret
, dm
, dm
->dmSize
+ dm
->dmDriverExtra
);
408 /***********************************************************
410 * Creates an ansi copy of supplied devmode
412 static DEVMODEA
*DEVMODEdupWtoA( const DEVMODEW
*dmW
)
417 if (!dmW
) return NULL
;
418 size
= dmW
->dmSize
- CCHDEVICENAME
-
419 ((dmW
->dmSize
> FIELD_OFFSET( DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
421 dmA
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
422 if (!dmA
) return NULL
;
424 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmDeviceName
, -1,
425 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
427 if (FIELD_OFFSET( DEVMODEW
, dmFormName
) >= dmW
->dmSize
)
429 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
430 dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
434 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
435 FIELD_OFFSET( DEVMODEW
, dmFormName
) - FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
436 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmFormName
, -1,
437 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
439 memcpy( &dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmLogPixels
) );
443 memcpy( (char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
448 /******************************************************************
449 * verify, that the filename is a local file
452 static inline BOOL
is_local_file(LPWSTR name
)
454 return (name
[0] && (name
[1] == ':') && (name
[2] == '\\'));
457 /* ################################ */
459 static int multi_sz_lenA(const char *str
)
461 const char *ptr
= str
;
465 ptr
+= lstrlenA(ptr
) + 1;
468 return ptr
- str
+ 1;
471 /*****************************************************************************
474 * Return DWORD associated with name from hkey.
476 static DWORD
get_dword_from_reg( HKEY hkey
, const WCHAR
*name
)
478 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
481 ret
= RegQueryValueExW( hkey
, name
, 0, &type
, (LPBYTE
)&value
, &sz
);
483 if (ret
!= ERROR_SUCCESS
)
485 WARN( "Got ret = %d on name %s\n", ret
, debugstr_w(name
) );
488 if (type
!= REG_DWORD
)
490 ERR( "Got type %d\n", type
);
496 static inline DWORD
set_reg_DWORD( HKEY hkey
, const WCHAR
*keyname
, const DWORD value
)
498 return RegSetValueExW( hkey
, keyname
, 0, REG_DWORD
, (const BYTE
*)&value
, sizeof(value
) );
501 /******************************************************************
503 * Get the pointer to the opened printer referred by the handle
505 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
507 UINT_PTR idx
= (UINT_PTR
)hprn
;
508 opened_printer_t
*ret
= NULL
;
510 EnterCriticalSection(&printer_handles_cs
);
512 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
513 ret
= printer_handles
[idx
- 1];
515 LeaveCriticalSection(&printer_handles_cs
);
519 /******************************************************************
520 * get_opened_printer_name
521 * Get the pointer to the opened printer name referred by the handle
523 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
525 opened_printer_t
*printer
= get_opened_printer(hprn
);
526 if(!printer
) return NULL
;
527 return printer
->name
;
530 static DWORD
open_printer_reg_key( const WCHAR
*name
, HKEY
*key
)
536 err
= RegCreateKeyW( HKEY_LOCAL_MACHINE
, PrintersW
, &printers
);
539 err
= RegOpenKeyW( printers
, name
, key
);
540 if (err
) err
= ERROR_INVALID_PRINTER_NAME
;
541 RegCloseKey( printers
);
545 /******************************************************************
546 * WINSPOOL_GetOpenedPrinterRegKey
549 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
551 LPCWSTR name
= get_opened_printer_name(hPrinter
);
553 if(!name
) return ERROR_INVALID_HANDLE
;
554 return open_printer_reg_key( name
, phkey
);
558 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
561 /* If forcing, or no profile string entry for device yet, set the entry
563 * The always change entry if not WINEPS yet is discussable.
566 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
568 !strstr(qbuf
,"WINEPS.DRV")
570 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
573 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
574 WriteProfileStringA("windows","device",buf
);
575 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
576 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
579 HeapFree(GetProcessHeap(),0,buf
);
583 static BOOL
add_printer_driver(const WCHAR
*name
, WCHAR
*ppd
)
587 ZeroMemory(&di3
, sizeof(DRIVER_INFO_3W
));
589 di3
.pName
= (WCHAR
*)name
;
590 di3
.pEnvironment
= envname_x86W
;
591 di3
.pDriverPath
= driver_nt
;
593 di3
.pConfigFile
= driver_nt
;
594 di3
.pDefaultDataType
= rawW
;
596 if (AddPrinterDriverExW( NULL
, 3, (LPBYTE
)&di3
, APD_COPY_NEW_FILES
| APD_COPY_FROM_DIRECTORY
) ||
597 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
600 di3
.pEnvironment
= envname_win40W
;
601 di3
.pDriverPath
= driver_9x
;
602 di3
.pConfigFile
= driver_9x
;
603 if (AddPrinterDriverExW( NULL
, 3, (LPBYTE
)&di3
, APD_COPY_NEW_FILES
| APD_COPY_FROM_DIRECTORY
) ||
604 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
609 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3
.pDriverPath
), debugstr_w(di3
.pEnvironment
));
613 static inline char *expand_env_string( char *str
, DWORD type
)
615 if (type
== REG_EXPAND_SZ
)
618 DWORD needed
= ExpandEnvironmentStringsA( str
, NULL
, 0 );
619 tmp
= HeapAlloc( GetProcessHeap(), 0, needed
);
622 ExpandEnvironmentStringsA( str
, tmp
, needed
);
623 HeapFree( GetProcessHeap(), 0, str
);
630 static char *get_fallback_ppd_name( const char *printer_name
)
632 static const WCHAR ppds_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
633 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
638 if (RegOpenKeyW( HKEY_CURRENT_USER
, ppds_key
, &hkey
) == ERROR_SUCCESS
)
640 const char *value_name
= NULL
;
642 if (RegQueryValueExA( hkey
, printer_name
, 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
643 value_name
= printer_name
;
644 else if (RegQueryValueExA( hkey
, "generic", 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
645 value_name
= "generic";
649 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
650 if (!ret
) return NULL
;
651 RegQueryValueExA( hkey
, value_name
, 0, &type
, (BYTE
*)ret
, &needed
);
654 if (ret
) return expand_env_string( ret
, type
);
659 static BOOL
copy_file( const char *src
, const char *dst
)
661 int fds
[2] = {-1, -1}, num
;
665 fds
[0] = open( src
, O_RDONLY
);
666 fds
[1] = open( dst
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666 );
667 if (fds
[0] == -1 || fds
[1] == -1) goto fail
;
669 while ((num
= read( fds
[0], buf
, sizeof(buf
) )) != 0)
671 if (num
== -1) goto fail
;
672 if (write( fds
[1], buf
, num
) != num
) goto fail
;
677 if (fds
[1] != -1) close( fds
[1] );
678 if (fds
[0] != -1) close( fds
[0] );
682 static BOOL
get_internal_fallback_ppd( const WCHAR
*ppd
)
684 static const WCHAR typeW
[] = {'P','P','D','F','I','L','E',0};
690 HRSRC res
= FindResourceW( WINSPOOL_hInstance
, MAKEINTRESOURCEW(1), typeW
);
692 if (!res
|| !(ptr
= LoadResource( WINSPOOL_hInstance
, res
))) return FALSE
;
693 size
= SizeofResource( WINSPOOL_hInstance
, res
);
694 end
= memchr( ptr
, 0, size
); /* resource file may contain additional nulls */
695 if (end
) size
= end
- ptr
;
696 file
= CreateFileW( ppd
, GENERIC_WRITE
, FILE_SHARE_READ
, NULL
, CREATE_ALWAYS
, 0, 0 );
697 if (file
== INVALID_HANDLE_VALUE
) return FALSE
;
698 ret
= WriteFile( file
, ptr
, size
, &written
, NULL
) && written
== size
;
700 if (ret
) TRACE( "using internal fallback for %s\n", debugstr_w( ppd
));
701 else DeleteFileW( ppd
);
705 static BOOL
get_fallback_ppd( const char *printer_name
, const WCHAR
*ppd
)
707 char *dst
, *src
= get_fallback_ppd_name( printer_name
);
710 if (!src
) return get_internal_fallback_ppd( ppd
);
712 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name
), debugstr_w(ppd
), debugstr_a(src
) );
714 if (!(dst
= wine_get_unix_file_name( ppd
))) goto fail
;
716 if (symlink( src
, dst
) == -1)
717 if (errno
!= ENOSYS
|| !copy_file( src
, dst
))
722 HeapFree( GetProcessHeap(), 0, dst
);
723 HeapFree( GetProcessHeap(), 0, src
);
727 static WCHAR
*get_ppd_filename( const WCHAR
*dir
, const WCHAR
*file_name
)
729 static const WCHAR dot_ppd
[] = {'.','p','p','d',0};
730 int len
= (strlenW( dir
) + strlenW( file_name
)) * sizeof(WCHAR
) + sizeof(dot_ppd
);
731 WCHAR
*ppd
= HeapAlloc( GetProcessHeap(), 0, len
);
733 if (!ppd
) return NULL
;
735 strcatW( ppd
, file_name
);
736 strcatW( ppd
, dot_ppd
);
741 static WCHAR
*get_ppd_dir( void )
743 static const WCHAR wine_ppds
[] = {'w','i','n','e','_','p','p','d','s','\\',0};
745 WCHAR
*dir
, tmp_path
[MAX_PATH
];
748 len
= GetTempPathW( sizeof(tmp_path
) / sizeof(tmp_path
[0]), tmp_path
);
749 if (!len
) return NULL
;
750 dir
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) + sizeof(wine_ppds
) ) ;
751 if (!dir
) return NULL
;
753 memcpy( dir
, tmp_path
, len
* sizeof(WCHAR
) );
754 memcpy( dir
+ len
, wine_ppds
, sizeof(wine_ppds
) );
755 res
= CreateDirectoryW( dir
, NULL
);
756 if (!res
&& GetLastError() != ERROR_ALREADY_EXISTS
)
758 HeapFree( GetProcessHeap(), 0, dir
);
761 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir
) );
765 static void unlink_ppd( const WCHAR
*ppd
)
767 char *unix_name
= wine_get_unix_file_name( ppd
);
769 HeapFree( GetProcessHeap(), 0, unix_name
);
772 #ifdef SONAME_LIBCUPS
774 static void *cupshandle
;
777 DO_FUNC(cupsAddOption); \
778 DO_FUNC(cupsFreeDests); \
779 DO_FUNC(cupsFreeOptions); \
780 DO_FUNC(cupsGetDests); \
781 DO_FUNC(cupsGetOption); \
782 DO_FUNC(cupsGetPPD); \
783 DO_FUNC(cupsParseOptions); \
784 DO_FUNC(cupsPrintFile)
785 #define CUPS_OPT_FUNCS \
786 DO_FUNC(cupsGetNamedDest); \
787 DO_FUNC(cupsGetPPD3); \
788 DO_FUNC(cupsLastErrorString)
790 #define DO_FUNC(f) static typeof(f) *p##f
793 static cups_dest_t
* (*pcupsGetNamedDest
)(http_t
*, const char *, const char *);
794 static http_status_t (*pcupsGetPPD3
)(http_t
*, const char *, time_t *, char *, size_t);
795 static const char * (*pcupsLastErrorString
)(void);
797 static http_status_t
cupsGetPPD3_wrapper( http_t
*http
, const char *name
,
798 time_t *modtime
, char *buffer
,
803 if (pcupsGetPPD3
) return pcupsGetPPD3( http
, name
, modtime
, buffer
, bufsize
);
805 if (!pcupsGetPPD
) return HTTP_NOT_FOUND
;
807 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
810 ppd
= pcupsGetPPD( name
);
812 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd
) );
814 if (!ppd
) return HTTP_NOT_FOUND
;
816 if (rename( ppd
, buffer
) == -1)
818 BOOL res
= copy_file( ppd
, buffer
);
820 if (!res
) return HTTP_NOT_FOUND
;
825 static BOOL
get_cups_ppd( const char *printer_name
, const WCHAR
*ppd
)
828 http_status_t http_status
;
829 char *unix_name
= wine_get_unix_file_name( ppd
);
831 TRACE( "(%s, %s)\n", debugstr_a(printer_name
), debugstr_w(ppd
) );
833 if (!unix_name
) return FALSE
;
835 http_status
= cupsGetPPD3_wrapper( 0, printer_name
, &modtime
,
836 unix_name
, strlen( unix_name
) + 1 );
838 if (http_status
!= HTTP_OK
) unlink( unix_name
);
839 HeapFree( GetProcessHeap(), 0, unix_name
);
841 if (http_status
== HTTP_OK
) return TRUE
;
843 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
844 debugstr_a(printer_name
), http_status
);
845 return get_fallback_ppd( printer_name
, ppd
);
848 static WCHAR
*get_cups_option( const char *name
, int num_options
, cups_option_t
*options
)
854 value
= pcupsGetOption( name
, num_options
, options
);
855 if (!value
) return NULL
;
857 len
= MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, NULL
, 0 );
858 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
859 if (ret
) MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, ret
, len
);
864 static cups_ptype_t
get_cups_printer_type( const cups_dest_t
*dest
)
866 WCHAR
*type
= get_cups_option( "printer-type", dest
->num_options
, dest
->options
), *end
;
867 cups_ptype_t ret
= 0;
871 ret
= (cups_ptype_t
)strtoulW( type
, &end
, 10 );
874 HeapFree( GetProcessHeap(), 0, type
);
878 static void load_cups(void)
880 cupshandle
= wine_dlopen( SONAME_LIBCUPS
, RTLD_NOW
, NULL
, 0 );
881 if (!cupshandle
) return;
883 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
886 p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); \
889 ERR("failed to load symbol %s\n", #x); \
895 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 )
900 static BOOL
CUPS_LoadPrinters(void)
903 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
906 WCHAR
*port
, *ppd_dir
= NULL
, *ppd
;
907 HKEY hkeyPrinter
, hkeyPrinters
;
908 WCHAR nameW
[MAX_PATH
];
909 HANDLE added_printer
;
910 cups_ptype_t printer_type
;
912 if (!cupshandle
) return FALSE
;
914 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
916 ERR("Can't create Printers key\n");
920 nrofdests
= pcupsGetDests(&dests
);
921 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
922 for (i
=0;i
<nrofdests
;i
++) {
923 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[i
].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
924 printer_type
= get_cups_printer_type( dests
+ i
);
926 TRACE( "Printer %d: %s. printer_type %x\n", i
, debugstr_w(nameW
), printer_type
);
928 if (printer_type
& 0x2000000 /* CUPS_PRINTER_SCANNER */)
930 TRACE( "skipping scanner-only device\n" );
934 port
= HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port
) + lstrlenW(nameW
) * sizeof(WCHAR
));
935 lstrcpyW(port
, CUPS_Port
);
936 lstrcatW(port
, nameW
);
938 if(RegOpenKeyW(hkeyPrinters
, nameW
, &hkeyPrinter
) == ERROR_SUCCESS
) {
939 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
940 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
942 TRACE("Printer already exists\n");
943 /* overwrite old LPR:* port */
944 RegSetValueExW(hkeyPrinter
, PortW
, 0, REG_SZ
, (LPBYTE
)port
, (lstrlenW(port
) + 1) * sizeof(WCHAR
));
945 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
946 /* flag that the PPD file should be checked for an update */
947 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
948 RegCloseKey(hkeyPrinter
);
950 BOOL added_driver
= FALSE
;
952 if (!ppd_dir
&& !(ppd_dir
= get_ppd_dir()))
954 HeapFree( GetProcessHeap(), 0, port
);
957 ppd
= get_ppd_filename( ppd_dir
, nameW
);
958 if (get_cups_ppd( dests
[i
].name
, ppd
))
960 added_driver
= add_printer_driver( nameW
, ppd
);
963 HeapFree( GetProcessHeap(), 0, ppd
);
966 HeapFree( GetProcessHeap(), 0, port
);
970 memset(&pi2
, 0, sizeof(PRINTER_INFO_2W
));
971 pi2
.pPrinterName
= nameW
;
972 pi2
.pDatatype
= rawW
;
973 pi2
.pPrintProcessor
= WinPrintW
;
974 pi2
.pDriverName
= nameW
;
975 pi2
.pComment
= get_cups_option( "printer-info", dests
[i
].num_options
, dests
[i
].options
);
976 pi2
.pLocation
= get_cups_option( "printer-location", dests
[i
].num_options
, dests
[i
].options
);
977 pi2
.pPortName
= port
;
978 pi2
.pParameters
= emptyStringW
;
979 pi2
.pShareName
= emptyStringW
;
980 pi2
.pSepFile
= emptyStringW
;
982 added_printer
= AddPrinterW( NULL
, 2, (LPBYTE
)&pi2
);
983 if (added_printer
) ClosePrinter( added_printer
);
984 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
985 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW
), GetLastError() );
987 HeapFree( GetProcessHeap(), 0, pi2
.pComment
);
988 HeapFree( GetProcessHeap(), 0, pi2
.pLocation
);
990 HeapFree( GetProcessHeap(), 0, port
);
993 if (dests
[i
].is_default
) {
994 SetDefaultPrinterW(nameW
);
1001 RemoveDirectoryW( ppd_dir
);
1002 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1005 if (hadprinter
&& !haddefault
) {
1006 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[0].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
1007 SetDefaultPrinterW(nameW
);
1009 pcupsFreeDests(nrofdests
, dests
);
1010 RegCloseKey(hkeyPrinters
);
1016 static char *get_queue_name( HANDLE printer
, BOOL
*cups
)
1018 WCHAR
*port
, *name
= NULL
;
1019 DWORD err
, needed
, type
;
1025 err
= WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
);
1026 if (err
) return NULL
;
1027 err
= RegQueryValueExW( key
, PortW
, 0, &type
, NULL
, &needed
);
1029 port
= HeapAlloc( GetProcessHeap(), 0, needed
);
1030 if (!port
) goto end
;
1031 RegQueryValueExW( key
, PortW
, 0, &type
, (BYTE
*)port
, &needed
);
1033 if (!strncmpW( port
, CUPS_Port
, sizeof(CUPS_Port
) / sizeof(WCHAR
) -1 ))
1035 name
= port
+ sizeof(CUPS_Port
) / sizeof(WCHAR
) - 1;
1038 else if (!strncmpW( port
, LPR_Port
, sizeof(LPR_Port
) / sizeof(WCHAR
) -1 ))
1039 name
= port
+ sizeof(LPR_Port
) / sizeof(WCHAR
) - 1;
1042 needed
= WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, NULL
, 0, NULL
, NULL
);
1043 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
1044 if(ret
) WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, ret
, needed
, NULL
, NULL
);
1046 HeapFree( GetProcessHeap(), 0, port
);
1053 static void set_ppd_overrides( HANDLE printer
)
1057 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1059 PMPrintSession session
= NULL
;
1060 PMPageFormat format
= NULL
;
1062 CFStringRef paper_name
;
1065 status
= PMCreateSession( &session
);
1066 if (status
) goto end
;
1068 status
= PMCreatePageFormat( &format
);
1069 if (status
) goto end
;
1071 status
= PMSessionDefaultPageFormat( session
, format
);
1072 if (status
) goto end
;
1074 status
= PMGetPageFormatPaper( format
, &paper
);
1075 if (status
) goto end
;
1077 status
= PMPaperGetPPDPaperName( paper
, &paper_name
);
1078 if (status
) goto end
;
1081 range
.length
= CFStringGetLength( paper_name
);
1082 size
= (range
.length
+ 1) * sizeof(WCHAR
);
1084 wstr
= HeapAlloc( GetProcessHeap(), 0, size
);
1085 CFStringGetCharacters( paper_name
, range
, (UniChar
*)wstr
);
1086 wstr
[range
.length
] = 0;
1089 if (format
) PMRelease( format
);
1090 if (session
) PMRelease( session
);
1093 SetPrinterDataExW( printer
, PPD_Overrides
, DefaultPageSize
, REG_SZ
, (BYTE
*)wstr
, size
);
1094 HeapFree( GetProcessHeap(), 0, wstr
);
1097 static BOOL
update_driver( HANDLE printer
)
1100 const WCHAR
*name
= get_opened_printer_name( printer
);
1101 WCHAR
*ppd_dir
, *ppd
;
1104 if (!name
) return FALSE
;
1105 queue_name
= get_queue_name( printer
, &is_cups
);
1106 if (!queue_name
) return FALSE
;
1108 if (!(ppd_dir
= get_ppd_dir()))
1110 HeapFree( GetProcessHeap(), 0, queue_name
);
1113 ppd
= get_ppd_filename( ppd_dir
, name
);
1115 #ifdef SONAME_LIBCUPS
1117 ret
= get_cups_ppd( queue_name
, ppd
);
1120 ret
= get_fallback_ppd( queue_name
, ppd
);
1124 TRACE( "updating driver %s\n", debugstr_w( name
) );
1125 ret
= add_printer_driver( name
, ppd
);
1128 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1129 HeapFree( GetProcessHeap(), 0, ppd
);
1130 HeapFree( GetProcessHeap(), 0, queue_name
);
1132 set_ppd_overrides( printer
);
1134 /* call into the driver to update the devmode */
1135 DocumentPropertiesW( 0, printer
, NULL
, NULL
, NULL
, 0 );
1140 static BOOL
PRINTCAP_ParseEntry( const char *pent
, BOOL isfirst
)
1142 PRINTER_INFO_2A pinfo2a
;
1145 char *e
,*s
,*name
,*prettyname
,*devname
;
1146 BOOL ret
= FALSE
, set_default
= FALSE
;
1147 char *port
= NULL
, *env_default
;
1148 HKEY hkeyPrinter
, hkeyPrinters
= NULL
;
1149 WCHAR devnameW
[MAX_PATH
], *ppd_dir
= NULL
, *ppd
;
1150 HANDLE added_printer
;
1152 while (isspace(*pent
)) pent
++;
1153 r
= strchr(pent
,':');
1155 name_len
= r
- pent
;
1157 name_len
= strlen(pent
);
1158 name
= HeapAlloc(GetProcessHeap(), 0, name_len
+ 1);
1159 memcpy(name
, pent
, name_len
);
1160 name
[name_len
] = '\0';
1166 TRACE("name=%s entry=%s\n",name
, pent
);
1168 if(ispunct(*name
)) { /* a tc entry, not a real printer */
1169 TRACE("skipping tc entry\n");
1173 if(strstr(pent
,":server")) { /* server only version so skip */
1174 TRACE("skipping server entry\n");
1178 /* Determine whether this is a postscript printer. */
1181 env_default
= getenv("PRINTER");
1183 /* Get longest name, usually the one at the right for later display. */
1184 while((s
=strchr(prettyname
,'|'))) {
1187 while(isspace(*--e
)) *e
= '\0';
1188 TRACE("\t%s\n", debugstr_a(prettyname
));
1189 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
1190 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
1193 e
= prettyname
+ strlen(prettyname
);
1194 while(isspace(*--e
)) *e
= '\0';
1195 TRACE("\t%s\n", debugstr_a(prettyname
));
1196 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
1198 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1199 * if it is too long, we use it as comment below. */
1200 devname
= prettyname
;
1201 if (strlen(devname
)>=CCHDEVICENAME
-1)
1203 if (strlen(devname
)>=CCHDEVICENAME
-1) {
1208 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
1209 sprintf(port
,"LPR:%s",name
);
1211 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
1213 ERR("Can't create Printers key\n");
1218 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, sizeof(devnameW
) / sizeof(WCHAR
));
1220 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
1221 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
1222 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1224 TRACE("Printer already exists\n");
1225 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
1226 /* flag that the PPD file should be checked for an update */
1227 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
1228 RegCloseKey(hkeyPrinter
);
1230 static CHAR data_type
[] = "RAW",
1231 print_proc
[] = "WinPrint",
1232 comment
[] = "WINEPS Printer using LPR",
1233 params
[] = "<parameters?>",
1234 share_name
[] = "<share name?>",
1235 sep_file
[] = "<sep file?>";
1236 BOOL added_driver
= FALSE
;
1238 if (!ppd_dir
&& !(ppd_dir
= get_ppd_dir())) goto end
;
1239 ppd
= get_ppd_filename( ppd_dir
, devnameW
);
1240 if (get_fallback_ppd( devname
, ppd
))
1242 added_driver
= add_printer_driver( devnameW
, ppd
);
1245 HeapFree( GetProcessHeap(), 0, ppd
);
1246 if (!added_driver
) goto end
;
1248 memset(&pinfo2a
,0,sizeof(pinfo2a
));
1249 pinfo2a
.pPrinterName
= devname
;
1250 pinfo2a
.pDatatype
= data_type
;
1251 pinfo2a
.pPrintProcessor
= print_proc
;
1252 pinfo2a
.pDriverName
= devname
;
1253 pinfo2a
.pComment
= comment
;
1254 pinfo2a
.pLocation
= prettyname
;
1255 pinfo2a
.pPortName
= port
;
1256 pinfo2a
.pParameters
= params
;
1257 pinfo2a
.pShareName
= share_name
;
1258 pinfo2a
.pSepFile
= sep_file
;
1260 added_printer
= AddPrinterA( NULL
, 2, (LPBYTE
)&pinfo2a
);
1261 if (added_printer
) ClosePrinter( added_printer
);
1262 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
1263 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name
), GetLastError() );
1266 if (isfirst
|| set_default
)
1267 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
1270 if (hkeyPrinters
) RegCloseKey( hkeyPrinters
);
1273 RemoveDirectoryW( ppd_dir
);
1274 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1276 HeapFree(GetProcessHeap(), 0, port
);
1277 HeapFree(GetProcessHeap(), 0, name
);
1282 PRINTCAP_LoadPrinters(void) {
1283 BOOL hadprinter
= FALSE
;
1287 BOOL had_bash
= FALSE
;
1289 f
= fopen("/etc/printcap","r");
1293 while(fgets(buf
,sizeof(buf
),f
)) {
1296 end
=strchr(buf
,'\n');
1300 while(isspace(*start
)) start
++;
1301 if(*start
== '#' || *start
== '\0')
1304 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
1305 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1306 HeapFree(GetProcessHeap(),0,pent
);
1310 if (end
&& *--end
== '\\') {
1317 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
1320 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
1326 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1327 HeapFree(GetProcessHeap(),0,pent
);
1333 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
1336 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
1337 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
1339 return ERROR_FILE_NOT_FOUND
;
1342 static inline DWORD
set_reg_devmode( HKEY key
, const WCHAR
*name
, const DEVMODEW
*dm
)
1344 DEVMODEA
*dmA
= DEVMODEdupWtoA( dm
);
1345 DWORD ret
= ERROR_FILE_NOT_FOUND
;
1347 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1348 and we support these drivers. NT writes DEVMODEW so somehow
1349 we'll need to distinguish between these when we support NT
1354 ret
= RegSetValueExW( key
, name
, 0, REG_BINARY
,
1355 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1356 HeapFree( GetProcessHeap(), 0, dmA
);
1362 /******************************************************************
1363 * get_servername_from_name (internal)
1365 * for an external server, a copy of the serverpart from the full name is returned
1368 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1372 WCHAR buffer
[MAX_PATH
];
1375 if (name
== NULL
) return NULL
;
1376 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1378 server
= strdupW(&name
[2]); /* skip over both backslash */
1379 if (server
== NULL
) return NULL
;
1381 /* strip '\' and the printername */
1382 ptr
= strchrW(server
, '\\');
1383 if (ptr
) ptr
[0] = '\0';
1385 TRACE("found %s\n", debugstr_w(server
));
1387 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1388 if (GetComputerNameW(buffer
, &len
)) {
1389 if (lstrcmpW(buffer
, server
) == 0) {
1390 /* The requested Servername is our computername */
1391 HeapFree(GetProcessHeap(), 0, server
);
1398 /******************************************************************
1399 * get_basename_from_name (internal)
1401 * skip over the serverpart from the full name
1404 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1406 if (name
== NULL
) return NULL
;
1407 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1408 /* skip over the servername and search for the following '\' */
1409 name
= strchrW(&name
[2], '\\');
1410 if ((name
) && (name
[1])) {
1411 /* found a separator ('\') followed by a name:
1412 skip over the separator and return the rest */
1417 /* no basename present (we found only a servername) */
1424 static void free_printer_entry( opened_printer_t
*printer
)
1426 /* the queue is shared, so don't free that here */
1427 HeapFree( GetProcessHeap(), 0, printer
->printername
);
1428 HeapFree( GetProcessHeap(), 0, printer
->name
);
1429 HeapFree( GetProcessHeap(), 0, printer
->devmode
);
1430 HeapFree( GetProcessHeap(), 0, printer
);
1433 /******************************************************************
1434 * get_opened_printer_entry
1435 * Get the first place empty in the opened printer table
1438 * - pDefault is ignored
1440 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1442 UINT_PTR handle
= nb_printer_handles
, i
;
1443 jobqueue_t
*queue
= NULL
;
1444 opened_printer_t
*printer
= NULL
;
1446 LPCWSTR printername
;
1448 if ((backend
== NULL
) && !load_backend()) return NULL
;
1450 servername
= get_servername_from_name(name
);
1452 FIXME("server %s not supported\n", debugstr_w(servername
));
1453 HeapFree(GetProcessHeap(), 0, servername
);
1454 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1458 printername
= get_basename_from_name(name
);
1459 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1461 /* an empty printername is invalid */
1462 if (printername
&& (!printername
[0])) {
1463 SetLastError(ERROR_INVALID_PARAMETER
);
1467 EnterCriticalSection(&printer_handles_cs
);
1469 for (i
= 0; i
< nb_printer_handles
; i
++)
1471 if (!printer_handles
[i
])
1473 if(handle
== nb_printer_handles
)
1478 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1479 queue
= printer_handles
[i
]->queue
;
1483 if (handle
>= nb_printer_handles
)
1485 opened_printer_t
**new_array
;
1486 if (printer_handles
)
1487 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1488 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1490 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1491 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1498 printer_handles
= new_array
;
1499 nb_printer_handles
+= 16;
1502 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1508 /* get a printer handle from the backend */
1509 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
1514 /* clone the base name. This is NULL for the printserver */
1515 printer
->printername
= strdupW(printername
);
1517 /* clone the full name */
1518 printer
->name
= strdupW(name
);
1519 if (name
&& (!printer
->name
)) {
1524 if (pDefault
&& pDefault
->pDevMode
)
1525 printer
->devmode
= dup_devmode( pDefault
->pDevMode
);
1528 printer
->queue
= queue
;
1531 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1532 if (!printer
->queue
) {
1536 list_init(&printer
->queue
->jobs
);
1537 printer
->queue
->ref
= 0;
1539 InterlockedIncrement(&printer
->queue
->ref
);
1541 printer_handles
[handle
] = printer
;
1544 LeaveCriticalSection(&printer_handles_cs
);
1545 if (!handle
&& printer
) {
1546 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1547 free_printer_entry( printer
);
1550 return (HANDLE
)handle
;
1553 static void old_printer_check( BOOL delete_phase
)
1555 PRINTER_INFO_5W
* pi
;
1556 DWORD needed
, type
, num
, delete, i
, size
;
1557 const DWORD one
= 1;
1561 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1562 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return;
1564 pi
= HeapAlloc( GetProcessHeap(), 0, needed
);
1565 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
);
1566 for (i
= 0; i
< num
; i
++)
1568 if (strncmpW( pi
[i
].pPortName
, CUPS_Port
, strlenW(CUPS_Port
) ) &&
1569 strncmpW( pi
[i
].pPortName
, LPR_Port
, strlenW(LPR_Port
) ))
1572 if (open_printer_reg_key( pi
[i
].pPrinterName
, &key
)) continue;
1576 RegSetValueExW( key
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&one
, sizeof(one
) );
1582 size
= sizeof( delete );
1583 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&delete, &size
);
1587 TRACE( "Deleting old printer %s\n", debugstr_w(pi
[i
].pPrinterName
) );
1588 if (OpenPrinterW( pi
[i
].pPrinterName
, &hprn
, NULL
))
1590 DeletePrinter( hprn
);
1591 ClosePrinter( hprn
);
1593 DeletePrinterDriverExW( NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0 );
1597 HeapFree(GetProcessHeap(), 0, pi
);
1600 static const WCHAR winspool_mutex_name
[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1601 'M','U','T','E','X','_','_','\0'};
1602 static HANDLE init_mutex
;
1604 void WINSPOOL_LoadSystemPrinters(void)
1606 HKEY hkey
, hkeyPrinters
;
1607 DWORD needed
, num
, i
;
1608 WCHAR PrinterName
[256];
1611 #ifdef SONAME_LIBCUPS
1615 /* FIXME: The init code should be moved to spoolsv.exe */
1616 init_mutex
= CreateMutexW( NULL
, TRUE
, winspool_mutex_name
);
1619 ERR( "Failed to create mutex\n" );
1622 if (GetLastError() == ERROR_ALREADY_EXISTS
)
1624 WaitForSingleObject( init_mutex
, INFINITE
);
1625 ReleaseMutex( init_mutex
);
1626 TRACE( "Init already done\n" );
1630 /* This ensures that all printer entries have a valid Name value. If causes
1631 problems later if they don't. If one is found to be missed we create one
1632 and set it equal to the name of the key */
1633 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1634 if(RegQueryInfoKeyW(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1635 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1636 for(i
= 0; i
< num
; i
++) {
1637 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1638 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1639 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1640 set_reg_szW(hkey
, NameW
, PrinterName
);
1647 RegCloseKey(hkeyPrinters
);
1650 old_printer_check( FALSE
);
1652 #ifdef SONAME_LIBCUPS
1653 done
= CUPS_LoadPrinters();
1656 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1657 PRINTCAP_LoadPrinters();
1659 old_printer_check( TRUE
);
1661 ReleaseMutex( init_mutex
);
1665 /******************************************************************
1668 * Get the pointer to the specified job.
1669 * Should hold the printer_handles_cs before calling.
1671 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1673 opened_printer_t
*printer
= get_opened_printer(hprn
);
1676 if(!printer
) return NULL
;
1677 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1679 if(job
->job_id
== JobId
)
1685 /***********************************************************
1688 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1691 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1694 Formname
= (dmA
->dmSize
> off_formname
);
1695 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1696 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1697 dmW
->dmDeviceName
, CCHDEVICENAME
);
1699 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1700 dmA
->dmSize
- CCHDEVICENAME
);
1702 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1703 off_formname
- CCHDEVICENAME
);
1704 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1705 dmW
->dmFormName
, CCHFORMNAME
);
1706 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1707 (off_formname
+ CCHFORMNAME
));
1710 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1711 dmA
->dmDriverExtra
);
1715 /******************************************************************
1716 * convert_printerinfo_W_to_A [internal]
1719 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1720 DWORD level
, DWORD outlen
, DWORD numentries
)
1726 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1728 len
= pi_sizeof
[level
] * numentries
;
1729 ptr
= (LPSTR
) out
+ len
;
1732 /* copy the numbers of all PRINTER_INFO_* first */
1733 memcpy(out
, pPrintersW
, len
);
1735 while (id
< numentries
) {
1739 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1740 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1742 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1743 if (piW
->pDescription
) {
1744 piA
->pDescription
= ptr
;
1745 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1746 ptr
, outlen
, NULL
, NULL
);
1752 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -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
);
1769 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1770 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1773 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1774 if (piW
->pServerName
) {
1775 piA
->pServerName
= ptr
;
1776 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1777 ptr
, outlen
, NULL
, NULL
);
1781 if (piW
->pPrinterName
) {
1782 piA
->pPrinterName
= ptr
;
1783 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1784 ptr
, outlen
, NULL
, NULL
);
1788 if (piW
->pShareName
) {
1789 piA
->pShareName
= ptr
;
1790 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1791 ptr
, outlen
, NULL
, NULL
);
1795 if (piW
->pPortName
) {
1796 piA
->pPortName
= ptr
;
1797 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1798 ptr
, outlen
, NULL
, NULL
);
1802 if (piW
->pDriverName
) {
1803 piA
->pDriverName
= ptr
;
1804 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1805 ptr
, outlen
, NULL
, NULL
);
1809 if (piW
->pComment
) {
1810 piA
->pComment
= ptr
;
1811 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1812 ptr
, outlen
, NULL
, NULL
);
1816 if (piW
->pLocation
) {
1817 piA
->pLocation
= ptr
;
1818 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1819 ptr
, outlen
, NULL
, NULL
);
1824 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1826 /* align DEVMODEA to a DWORD boundary */
1827 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1831 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1832 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1833 memcpy(ptr
, dmA
, len
);
1834 HeapFree(GetProcessHeap(), 0, dmA
);
1840 if (piW
->pSepFile
) {
1841 piA
->pSepFile
= ptr
;
1842 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1843 ptr
, outlen
, NULL
, NULL
);
1847 if (piW
->pPrintProcessor
) {
1848 piA
->pPrintProcessor
= ptr
;
1849 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1850 ptr
, outlen
, NULL
, NULL
);
1854 if (piW
->pDatatype
) {
1855 piA
->pDatatype
= ptr
;
1856 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1857 ptr
, outlen
, NULL
, NULL
);
1861 if (piW
->pParameters
) {
1862 piA
->pParameters
= ptr
;
1863 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1864 ptr
, outlen
, NULL
, NULL
);
1868 if (piW
->pSecurityDescriptor
) {
1869 piA
->pSecurityDescriptor
= NULL
;
1870 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1877 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1878 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1880 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1882 if (piW
->pPrinterName
) {
1883 piA
->pPrinterName
= ptr
;
1884 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1885 ptr
, outlen
, NULL
, NULL
);
1889 if (piW
->pServerName
) {
1890 piA
->pServerName
= ptr
;
1891 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1892 ptr
, outlen
, NULL
, NULL
);
1901 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1902 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1904 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1906 if (piW
->pPrinterName
) {
1907 piA
->pPrinterName
= ptr
;
1908 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1909 ptr
, outlen
, NULL
, NULL
);
1913 if (piW
->pPortName
) {
1914 piA
->pPortName
= ptr
;
1915 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1916 ptr
, outlen
, NULL
, NULL
);
1923 case 6: /* 6A and 6W are the same structure */
1928 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1929 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1931 TRACE("(%u) #%u\n", level
, id
);
1932 if (piW
->pszObjectGUID
) {
1933 piA
->pszObjectGUID
= ptr
;
1934 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1935 ptr
, outlen
, NULL
, NULL
);
1945 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1946 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1949 TRACE("(%u) #%u\n", level
, id
);
1950 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1952 /* align DEVMODEA to a DWORD boundary */
1953 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1957 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1958 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1959 memcpy(ptr
, dmA
, len
);
1960 HeapFree(GetProcessHeap(), 0, dmA
);
1970 FIXME("for level %u\n", level
);
1972 pPrintersW
+= pi_sizeof
[level
];
1973 out
+= pi_sizeof
[level
];
1978 /******************************************************************
1979 * convert_driverinfo_W_to_A [internal]
1982 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1983 DWORD level
, DWORD outlen
, DWORD numentries
)
1989 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1991 len
= di_sizeof
[level
] * numentries
;
1992 ptr
= (LPSTR
) out
+ len
;
1995 /* copy the numbers of all PRINTER_INFO_* first */
1996 memcpy(out
, pDriversW
, len
);
1998 #define COPY_STRING(fld) \
2001 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
2002 ptr += len; outlen -= len;\
2004 #define COPY_MULTIZ_STRING(fld) \
2005 { LPWSTR p = diW->fld; if (p){ \
2008 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2009 ptr += len; outlen -= len; p += len;\
2011 while(len > 1 && outlen > 0); \
2014 while (id
< numentries
)
2020 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
2021 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
2023 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2030 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
2031 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
2033 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2036 COPY_STRING(pEnvironment
);
2037 COPY_STRING(pDriverPath
);
2038 COPY_STRING(pDataFile
);
2039 COPY_STRING(pConfigFile
);
2044 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
2045 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
2047 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2050 COPY_STRING(pEnvironment
);
2051 COPY_STRING(pDriverPath
);
2052 COPY_STRING(pDataFile
);
2053 COPY_STRING(pConfigFile
);
2054 COPY_STRING(pHelpFile
);
2055 COPY_MULTIZ_STRING(pDependentFiles
);
2056 COPY_STRING(pMonitorName
);
2057 COPY_STRING(pDefaultDataType
);
2062 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
2063 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
2065 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2068 COPY_STRING(pEnvironment
);
2069 COPY_STRING(pDriverPath
);
2070 COPY_STRING(pDataFile
);
2071 COPY_STRING(pConfigFile
);
2072 COPY_STRING(pHelpFile
);
2073 COPY_MULTIZ_STRING(pDependentFiles
);
2074 COPY_STRING(pMonitorName
);
2075 COPY_STRING(pDefaultDataType
);
2076 COPY_MULTIZ_STRING(pszzPreviousNames
);
2081 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
2082 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
2084 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2087 COPY_STRING(pEnvironment
);
2088 COPY_STRING(pDriverPath
);
2089 COPY_STRING(pDataFile
);
2090 COPY_STRING(pConfigFile
);
2095 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
2096 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
2098 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2101 COPY_STRING(pEnvironment
);
2102 COPY_STRING(pDriverPath
);
2103 COPY_STRING(pDataFile
);
2104 COPY_STRING(pConfigFile
);
2105 COPY_STRING(pHelpFile
);
2106 COPY_MULTIZ_STRING(pDependentFiles
);
2107 COPY_STRING(pMonitorName
);
2108 COPY_STRING(pDefaultDataType
);
2109 COPY_MULTIZ_STRING(pszzPreviousNames
);
2110 COPY_STRING(pszMfgName
);
2111 COPY_STRING(pszOEMUrl
);
2112 COPY_STRING(pszHardwareID
);
2113 COPY_STRING(pszProvider
);
2118 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
2119 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
2121 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2124 COPY_STRING(pEnvironment
);
2125 COPY_STRING(pDriverPath
);
2126 COPY_STRING(pDataFile
);
2127 COPY_STRING(pConfigFile
);
2128 COPY_STRING(pHelpFile
);
2129 COPY_MULTIZ_STRING(pDependentFiles
);
2130 COPY_STRING(pMonitorName
);
2131 COPY_STRING(pDefaultDataType
);
2132 COPY_MULTIZ_STRING(pszzPreviousNames
);
2133 COPY_STRING(pszMfgName
);
2134 COPY_STRING(pszOEMUrl
);
2135 COPY_STRING(pszHardwareID
);
2136 COPY_STRING(pszProvider
);
2137 COPY_STRING(pszPrintProcessor
);
2138 COPY_STRING(pszVendorSetup
);
2139 COPY_MULTIZ_STRING(pszzColorProfiles
);
2140 COPY_STRING(pszInfPath
);
2141 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
2147 FIXME("for level %u\n", level
);
2150 pDriversW
+= di_sizeof
[level
];
2151 out
+= di_sizeof
[level
];
2156 #undef COPY_MULTIZ_STRING
2160 /***********************************************************
2163 static void *printer_info_AtoW( const void *data
, DWORD level
)
2166 UNICODE_STRING usBuffer
;
2168 if (!data
) return NULL
;
2170 if (level
< 1 || level
> 9) return NULL
;
2172 ret
= HeapAlloc( GetProcessHeap(), 0, pi_sizeof
[level
] );
2173 if (!ret
) return NULL
;
2175 memcpy( ret
, data
, pi_sizeof
[level
] ); /* copy everything first */
2181 const PRINTER_INFO_2A
*piA
= (const PRINTER_INFO_2A
*)data
;
2182 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)ret
;
2184 piW
->pServerName
= asciitounicode( &usBuffer
, piA
->pServerName
);
2185 piW
->pPrinterName
= asciitounicode( &usBuffer
, piA
->pPrinterName
);
2186 piW
->pShareName
= asciitounicode( &usBuffer
, piA
->pShareName
);
2187 piW
->pPortName
= asciitounicode( &usBuffer
, piA
->pPortName
);
2188 piW
->pDriverName
= asciitounicode( &usBuffer
, piA
->pDriverName
);
2189 piW
->pComment
= asciitounicode( &usBuffer
, piA
->pComment
);
2190 piW
->pLocation
= asciitounicode( &usBuffer
, piA
->pLocation
);
2191 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2192 piW
->pSepFile
= asciitounicode( &usBuffer
, piA
->pSepFile
);
2193 piW
->pPrintProcessor
= asciitounicode( &usBuffer
, piA
->pPrintProcessor
);
2194 piW
->pDatatype
= asciitounicode( &usBuffer
, piA
->pDatatype
);
2195 piW
->pParameters
= asciitounicode( &usBuffer
, piA
->pParameters
);
2202 const PRINTER_INFO_9A
*piA
= (const PRINTER_INFO_9A
*)data
;
2203 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)ret
;
2205 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2210 FIXME( "Unhandled level %d\n", level
);
2211 HeapFree( GetProcessHeap(), 0, ret
);
2218 /***********************************************************
2221 static void free_printer_info( void *data
, DWORD level
)
2229 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)data
;
2231 HeapFree( GetProcessHeap(), 0, piW
->pServerName
);
2232 HeapFree( GetProcessHeap(), 0, piW
->pPrinterName
);
2233 HeapFree( GetProcessHeap(), 0, piW
->pShareName
);
2234 HeapFree( GetProcessHeap(), 0, piW
->pPortName
);
2235 HeapFree( GetProcessHeap(), 0, piW
->pDriverName
);
2236 HeapFree( GetProcessHeap(), 0, piW
->pComment
);
2237 HeapFree( GetProcessHeap(), 0, piW
->pLocation
);
2238 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2239 HeapFree( GetProcessHeap(), 0, piW
->pSepFile
);
2240 HeapFree( GetProcessHeap(), 0, piW
->pPrintProcessor
);
2241 HeapFree( GetProcessHeap(), 0, piW
->pDatatype
);
2242 HeapFree( GetProcessHeap(), 0, piW
->pParameters
);
2249 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)data
;
2251 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2256 FIXME( "Unhandled level %d\n", level
);
2259 HeapFree( GetProcessHeap(), 0, data
);
2263 /******************************************************************
2264 * DeviceCapabilities [WINSPOOL.@]
2265 * DeviceCapabilitiesA [WINSPOOL.@]
2268 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
2269 LPSTR pOutput
, LPDEVMODEA lpdm
)
2273 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice
), debugstr_a(pPort
), cap
, pOutput
, lpdm
);
2275 if (!GDI_CallDeviceCapabilities16
)
2277 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2279 if (!GDI_CallDeviceCapabilities16
) return -1;
2281 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
2283 /* If DC_PAPERSIZE map POINT16s to POINTs */
2284 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
2285 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
2286 POINT
*pt
= (POINT
*)pOutput
;
2288 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
2289 for(i
= 0; i
< ret
; i
++, pt
++)
2294 HeapFree( GetProcessHeap(), 0, tmp
);
2300 /*****************************************************************************
2301 * DeviceCapabilitiesW [WINSPOOL.@]
2303 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2306 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
2307 WORD fwCapability
, LPWSTR pOutput
,
2308 const DEVMODEW
*pDevMode
)
2310 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
2311 LPSTR pDeviceA
= strdupWtoA(pDevice
);
2312 LPSTR pPortA
= strdupWtoA(pPort
);
2315 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice
), debugstr_w(pPort
), fwCapability
, pOutput
, pDevMode
);
2317 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
2318 fwCapability
== DC_FILEDEPENDENCIES
||
2319 fwCapability
== DC_PAPERNAMES
)) {
2320 /* These need A -> W translation */
2323 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
2327 switch(fwCapability
) {
2332 case DC_FILEDEPENDENCIES
:
2336 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
2337 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
2339 for(i
= 0; i
< ret
; i
++)
2340 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
2341 pOutput
+ (i
* size
), size
);
2342 HeapFree(GetProcessHeap(), 0, pOutputA
);
2344 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
2345 (LPSTR
)pOutput
, dmA
);
2347 HeapFree(GetProcessHeap(),0,pPortA
);
2348 HeapFree(GetProcessHeap(),0,pDeviceA
);
2349 HeapFree(GetProcessHeap(),0,dmA
);
2353 /******************************************************************
2354 * DocumentPropertiesA [WINSPOOL.@]
2356 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2358 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
2359 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
2360 LPDEVMODEA pDevModeInput
,DWORD fMode
)
2362 LPSTR lpName
= pDeviceName
, dupname
= NULL
;
2363 static CHAR port
[] = "LPT1:";
2366 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2367 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
2370 if(!pDeviceName
|| !*pDeviceName
) {
2371 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2373 ERR("no name from hPrinter?\n");
2374 SetLastError(ERROR_INVALID_HANDLE
);
2377 lpName
= dupname
= strdupWtoA(lpNameW
);
2380 if (!GDI_CallExtDeviceMode16
)
2382 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2384 if (!GDI_CallExtDeviceMode16
) {
2385 ERR("No CallExtDeviceMode16?\n");
2390 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
2391 pDevModeInput
, NULL
, fMode
);
2394 HeapFree(GetProcessHeap(), 0, dupname
);
2399 /*****************************************************************************
2400 * DocumentPropertiesW (WINSPOOL.@)
2402 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2404 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
2406 LPDEVMODEW pDevModeOutput
,
2407 LPDEVMODEW pDevModeInput
, DWORD fMode
)
2410 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
2411 LPDEVMODEA pDevModeInputA
;
2412 LPDEVMODEA pDevModeOutputA
= NULL
;
2415 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2416 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
2418 if(pDevModeOutput
) {
2419 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
2420 if(ret
< 0) return ret
;
2421 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
2423 pDevModeInputA
= (fMode
& DM_IN_BUFFER
) ? DEVMODEdupWtoA(pDevModeInput
) : NULL
;
2424 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
2425 pDevModeInputA
, fMode
);
2426 if(pDevModeOutput
) {
2427 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
2428 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
2430 if(fMode
== 0 && ret
> 0)
2431 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2432 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
2433 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
2437 /*****************************************************************************
2438 * IsValidDevmodeA [WINSPOOL.@]
2440 * Validate a DEVMODE structure and fix errors if possible.
2443 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA
*pDevMode
, SIZE_T size
)
2445 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2453 /*****************************************************************************
2454 * IsValidDevmodeW [WINSPOOL.@]
2456 * Validate a DEVMODE structure and fix errors if possible.
2459 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW
*pDevMode
, SIZE_T size
)
2461 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2469 /******************************************************************
2470 * OpenPrinterA [WINSPOOL.@]
2475 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
2476 LPPRINTER_DEFAULTSA pDefault
)
2478 UNICODE_STRING lpPrinterNameW
;
2479 UNICODE_STRING usBuffer
;
2480 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
2481 PWSTR pwstrPrinterNameW
;
2484 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName
), phPrinter
, pDefault
);
2486 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
2489 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
2490 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
2491 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
2492 pDefaultW
= &DefaultW
;
2494 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
2496 RtlFreeUnicodeString(&usBuffer
);
2497 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
2499 RtlFreeUnicodeString(&lpPrinterNameW
);
2503 /******************************************************************
2504 * OpenPrinterW [WINSPOOL.@]
2506 * Open a Printer / Printserver or a Printer-Object
2509 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2510 * phPrinter [O] The resulting Handle is stored here
2511 * pDefault [I] PTR to Default Printer Settings or NULL
2518 * lpPrinterName is one of:
2519 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2520 *| Printer: "PrinterName"
2521 *| Printer-Object: "PrinterName,Job xxx"
2522 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2523 *| XcvPort: "Servername,XcvPort PortName"
2526 *| Printer-Object not supported
2527 *| pDefaults is ignored
2530 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2534 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2537 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2538 SetLastError(ERROR_INVALID_PARAMETER
);
2542 /* Get the unique handle of the printer or Printserver */
2543 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2545 if (*phPrinter
&& WINSPOOL_GetOpenedPrinterRegKey( *phPrinter
, &key
) == ERROR_SUCCESS
)
2547 DWORD deleting
= 0, size
= sizeof( deleting
), type
;
2549 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&deleting
, &size
);
2550 WaitForSingleObject( init_mutex
, INFINITE
);
2551 status
= get_dword_from_reg( key
, StatusW
);
2552 set_reg_DWORD( key
, StatusW
, status
& ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
2553 ReleaseMutex( init_mutex
);
2554 if (!deleting
&& (status
& PRINTER_STATUS_DRIVER_UPDATE_NEEDED
))
2555 update_driver( *phPrinter
);
2559 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2560 return (*phPrinter
!= 0);
2563 /******************************************************************
2564 * AddMonitorA [WINSPOOL.@]
2569 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2571 LPWSTR nameW
= NULL
;
2574 LPMONITOR_INFO_2A mi2a
;
2575 MONITOR_INFO_2W mi2w
;
2577 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2578 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2579 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2580 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2581 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2584 SetLastError(ERROR_INVALID_LEVEL
);
2588 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2594 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2595 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2596 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2599 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2601 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2602 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2603 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2605 if (mi2a
->pEnvironment
) {
2606 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2607 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2608 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2610 if (mi2a
->pDLLName
) {
2611 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2612 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2613 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2616 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2618 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2619 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2620 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2622 HeapFree(GetProcessHeap(), 0, nameW
);
2626 /******************************************************************************
2627 * AddMonitorW [WINSPOOL.@]
2629 * Install a Printmonitor
2632 * pName [I] Servername or NULL (local Computer)
2633 * Level [I] Structure-Level (Must be 2)
2634 * pMonitors [I] PTR to MONITOR_INFO_2
2641 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2644 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2646 LPMONITOR_INFO_2W mi2w
;
2648 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2649 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2650 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2651 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2652 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2654 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2657 SetLastError(ERROR_INVALID_LEVEL
);
2661 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2666 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2669 /******************************************************************
2670 * DeletePrinterDriverA [WINSPOOL.@]
2673 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2675 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2678 /******************************************************************
2679 * DeletePrinterDriverW [WINSPOOL.@]
2682 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2684 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2687 /******************************************************************
2688 * DeleteMonitorA [WINSPOOL.@]
2690 * See DeleteMonitorW.
2693 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2695 LPWSTR nameW
= NULL
;
2696 LPWSTR EnvironmentW
= NULL
;
2697 LPWSTR MonitorNameW
= NULL
;
2702 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2703 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2704 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2708 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2709 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2710 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2713 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2714 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2715 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2718 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2720 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2721 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2722 HeapFree(GetProcessHeap(), 0, nameW
);
2726 /******************************************************************
2727 * DeleteMonitorW [WINSPOOL.@]
2729 * Delete a specific Printmonitor from a Printing-Environment
2732 * pName [I] Servername or NULL (local Computer)
2733 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2734 * pMonitorName [I] Name of the Monitor, that should be deleted
2741 * pEnvironment is ignored in Windows for the local Computer.
2744 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2747 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2748 debugstr_w(pMonitorName
));
2750 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2752 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2756 /******************************************************************
2757 * DeletePortA [WINSPOOL.@]
2762 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2764 LPWSTR nameW
= NULL
;
2765 LPWSTR portW
= NULL
;
2769 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2771 /* convert servername to unicode */
2773 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2774 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2775 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2778 /* convert portname to unicode */
2780 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2781 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2782 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2785 res
= DeletePortW(nameW
, hWnd
, portW
);
2786 HeapFree(GetProcessHeap(), 0, nameW
);
2787 HeapFree(GetProcessHeap(), 0, portW
);
2791 /******************************************************************
2792 * DeletePortW [WINSPOOL.@]
2794 * Delete a specific Port
2797 * pName [I] Servername or NULL (local Computer)
2798 * hWnd [I] Handle to parent Window for the Dialog-Box
2799 * pPortName [I] Name of the Port, that should be deleted
2806 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2808 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2810 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2813 SetLastError(RPC_X_NULL_REF_POINTER
);
2817 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2820 /******************************************************************************
2821 * WritePrinter [WINSPOOL.@]
2823 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2825 opened_printer_t
*printer
;
2828 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2830 EnterCriticalSection(&printer_handles_cs
);
2831 printer
= get_opened_printer(hPrinter
);
2834 SetLastError(ERROR_INVALID_HANDLE
);
2840 SetLastError(ERROR_SPL_NO_STARTDOC
);
2844 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2846 LeaveCriticalSection(&printer_handles_cs
);
2850 /*****************************************************************************
2851 * AddFormA [WINSPOOL.@]
2853 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2855 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2859 /*****************************************************************************
2860 * AddFormW [WINSPOOL.@]
2862 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2864 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2868 /*****************************************************************************
2869 * AddJobA [WINSPOOL.@]
2871 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2874 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2878 SetLastError(ERROR_INVALID_LEVEL
);
2882 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2885 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2886 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2887 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2888 if(*pcbNeeded
> cbBuf
) {
2889 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2892 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2893 addjobA
->JobId
= addjobW
->JobId
;
2894 addjobA
->Path
= (char *)(addjobA
+ 1);
2895 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2901 /*****************************************************************************
2902 * AddJobW [WINSPOOL.@]
2904 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2906 opened_printer_t
*printer
;
2909 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2910 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2911 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2913 ADDJOB_INFO_1W
*addjob
;
2915 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2917 EnterCriticalSection(&printer_handles_cs
);
2919 printer
= get_opened_printer(hPrinter
);
2922 SetLastError(ERROR_INVALID_HANDLE
);
2927 SetLastError(ERROR_INVALID_LEVEL
);
2931 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2935 job
->job_id
= InterlockedIncrement(&next_job_id
);
2937 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2938 if(path
[len
- 1] != '\\')
2940 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2941 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2943 len
= strlenW(filename
);
2944 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2945 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2946 job
->portname
= NULL
;
2947 job
->document_title
= strdupW(default_doc_title
);
2948 job
->printer_name
= strdupW(printer
->name
);
2949 job
->devmode
= dup_devmode( printer
->devmode
);
2950 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2952 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2953 if(*pcbNeeded
<= cbBuf
) {
2954 addjob
= (ADDJOB_INFO_1W
*)pData
;
2955 addjob
->JobId
= job
->job_id
;
2956 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2957 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2960 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2963 LeaveCriticalSection(&printer_handles_cs
);
2967 /*****************************************************************************
2968 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2970 * Return the PATH for the Print-Processors
2972 * See GetPrintProcessorDirectoryW.
2976 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2977 DWORD level
, LPBYTE Info
,
2978 DWORD cbBuf
, LPDWORD pcbNeeded
)
2980 LPWSTR serverW
= NULL
;
2985 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2986 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2990 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2991 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2992 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2996 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2997 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2998 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
3001 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
3002 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
3004 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
3007 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
3008 cbBuf
, NULL
, NULL
) > 0;
3011 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
3012 HeapFree(GetProcessHeap(), 0, envW
);
3013 HeapFree(GetProcessHeap(), 0, serverW
);
3017 /*****************************************************************************
3018 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3020 * Return the PATH for the Print-Processors
3023 * server [I] Servername (NT only) or NULL (local Computer)
3024 * env [I] Printing-Environment (see below) or NULL (Default)
3025 * level [I] Structure-Level (must be 1)
3026 * Info [O] PTR to Buffer that receives the Result
3027 * cbBuf [I] Size of Buffer at "Info"
3028 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3029 * required for the Buffer at "Info"
3032 * Success: TRUE and in pcbNeeded the Bytes used in Info
3033 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3034 * if cbBuf is too small
3036 * Native Values returned in Info on Success:
3037 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3038 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3039 *| win9x(Windows 4.0): "%winsysdir%"
3041 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3044 * Only NULL or "" is supported for server
3047 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
3048 DWORD level
, LPBYTE Info
,
3049 DWORD cbBuf
, LPDWORD pcbNeeded
)
3052 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
3053 Info
, cbBuf
, pcbNeeded
);
3055 if ((backend
== NULL
) && !load_backend()) return FALSE
;
3058 /* (Level != 1) is ignored in win9x */
3059 SetLastError(ERROR_INVALID_LEVEL
);
3063 if (pcbNeeded
== NULL
) {
3064 /* (pcbNeeded == NULL) is ignored in win9x */
3065 SetLastError(RPC_X_NULL_REF_POINTER
);
3069 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
3072 /*****************************************************************************
3073 * WINSPOOL_OpenDriverReg [internal]
3075 * opens the registry for the printer drivers depending on the given input
3076 * variable pEnvironment
3079 * the opened hkey on success
3082 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
3086 const printenv_t
* env
;
3088 TRACE("(%s)\n", debugstr_w(pEnvironment
));
3090 env
= validate_envW(pEnvironment
);
3091 if (!env
) return NULL
;
3093 buffer
= HeapAlloc( GetProcessHeap(), 0,
3094 (strlenW(DriversW
) + strlenW(env
->envname
) +
3095 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
3097 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
3098 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
3099 HeapFree(GetProcessHeap(), 0, buffer
);
3104 /*****************************************************************************
3105 * set_devices_and_printerports [internal]
3107 * set the [Devices] and [PrinterPorts] entries for a printer.
3110 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
3112 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
3116 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
3118 /* FIXME: the driver must change to "winspool" */
3119 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
3121 lstrcpyW(devline
, driver_nt
);
3122 lstrcatW(devline
, commaW
);
3123 lstrcatW(devline
, pi
->pPortName
);
3125 TRACE("using %s\n", debugstr_w(devline
));
3126 WriteProfileStringW(devicesW
, pi
->pPrinterName
, devline
);
3127 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
3128 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3129 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3133 lstrcatW(devline
, timeout_15_45
);
3134 WriteProfileStringW(PrinterPortsW
, pi
->pPrinterName
, devline
);
3135 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
3136 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3137 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3140 HeapFree(GetProcessHeap(), 0, devline
);
3144 /*****************************************************************************
3145 * AddPrinterW [WINSPOOL.@]
3147 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3149 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
3152 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
3155 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
3157 if(pName
&& *pName
) {
3158 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
3159 SetLastError(ERROR_INVALID_PARAMETER
);
3163 ERR("Level = %d, unsupported!\n", Level
);
3164 SetLastError(ERROR_INVALID_LEVEL
);
3168 SetLastError(ERROR_INVALID_PARAMETER
);
3171 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3173 ERR("Can't create Printers key\n");
3176 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
3177 if (!RegQueryValueW(hkeyPrinter
, AttributesW
, NULL
, NULL
)) {
3178 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
3179 RegCloseKey(hkeyPrinter
);
3180 RegCloseKey(hkeyPrinters
);
3183 RegCloseKey(hkeyPrinter
);
3185 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
3187 ERR("Can't create Drivers key\n");
3188 RegCloseKey(hkeyPrinters
);
3191 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
3193 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
3194 RegCloseKey(hkeyPrinters
);
3195 RegCloseKey(hkeyDrivers
);
3196 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
3199 RegCloseKey(hkeyDriver
);
3200 RegCloseKey(hkeyDrivers
);
3202 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
3203 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
3204 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
3205 RegCloseKey(hkeyPrinters
);
3209 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
3211 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
3212 SetLastError(ERROR_INVALID_PRINTER_NAME
);
3213 RegCloseKey(hkeyPrinters
);
3217 set_devices_and_printerports(pi
);
3219 set_reg_DWORD(hkeyPrinter
, AttributesW
, pi
->Attributes
);
3220 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
3221 set_reg_DWORD(hkeyPrinter
, Default_PriorityW
, pi
->DefaultPriority
);
3222 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
3223 set_reg_DWORD(hkeyPrinter
, dnsTimeoutW
, 0);
3224 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
3225 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
3226 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
3227 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
3228 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
3229 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
3230 set_reg_DWORD(hkeyPrinter
, PriorityW
, pi
->Priority
);
3231 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
3232 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
3233 set_reg_DWORD(hkeyPrinter
, StartTimeW
, pi
->StartTime
);
3234 set_reg_DWORD(hkeyPrinter
, StatusW
, pi
->Status
);
3235 set_reg_DWORD(hkeyPrinter
, txTimeoutW
, 0);
3236 set_reg_DWORD(hkeyPrinter
, UntilTimeW
, pi
->UntilTime
);
3238 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
3242 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
3243 size
= sizeof(DEVMODEW
);
3249 dm
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3251 if (DocumentPropertiesW(0, 0, pi
->pPrinterName
, dm
, NULL
, DM_OUT_BUFFER
) < 0)
3253 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
3254 HeapFree( GetProcessHeap(), 0, dm
);
3259 /* set devmode to printer name */
3260 lstrcpynW( dm
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
3264 set_reg_devmode( hkeyPrinter
, Default_DevModeW
, dm
);
3265 if (!pi
->pDevMode
) HeapFree( GetProcessHeap(), 0, dm
);
3267 RegCloseKey(hkeyPrinter
);
3268 RegCloseKey(hkeyPrinters
);
3269 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
3270 ERR("OpenPrinter failing\n");
3276 /*****************************************************************************
3277 * AddPrinterA [WINSPOOL.@]
3279 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3281 UNICODE_STRING pNameW
;
3283 PRINTER_INFO_2W
*piW
;
3284 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
3287 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
3289 ERR("Level = %d, unsupported!\n", Level
);
3290 SetLastError(ERROR_INVALID_LEVEL
);
3293 pwstrNameW
= asciitounicode(&pNameW
,pName
);
3294 piW
= printer_info_AtoW( piA
, Level
);
3296 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
3298 free_printer_info( piW
, Level
);
3299 RtlFreeUnicodeString(&pNameW
);
3304 /*****************************************************************************
3305 * ClosePrinter [WINSPOOL.@]
3307 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
3309 UINT_PTR i
= (UINT_PTR
)hPrinter
;
3310 opened_printer_t
*printer
= NULL
;
3313 TRACE("(%p)\n", hPrinter
);
3315 EnterCriticalSection(&printer_handles_cs
);
3317 if ((i
> 0) && (i
<= nb_printer_handles
))
3318 printer
= printer_handles
[i
- 1];
3323 struct list
*cursor
, *cursor2
;
3325 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
3327 if (printer
->backend_printer
) {
3328 backend
->fpClosePrinter(printer
->backend_printer
);
3332 EndDocPrinter(hPrinter
);
3334 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
3336 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
3338 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
3339 ScheduleJob(hPrinter
, job
->job_id
);
3341 HeapFree(GetProcessHeap(), 0, printer
->queue
);
3344 free_printer_entry( printer
);
3345 printer_handles
[i
- 1] = NULL
;
3348 LeaveCriticalSection(&printer_handles_cs
);
3352 /*****************************************************************************
3353 * DeleteFormA [WINSPOOL.@]
3355 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3357 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3361 /*****************************************************************************
3362 * DeleteFormW [WINSPOOL.@]
3364 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3366 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3370 /*****************************************************************************
3371 * DeletePrinter [WINSPOOL.@]
3373 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3375 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3376 HKEY hkeyPrinters
, hkey
;
3377 WCHAR def
[MAX_PATH
];
3378 DWORD size
= sizeof( def
) / sizeof( def
[0] );
3381 SetLastError(ERROR_INVALID_HANDLE
);
3384 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3385 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3386 RegCloseKey(hkeyPrinters
);
3388 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3389 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
3391 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3392 RegDeleteValueW(hkey
, lpNameW
);
3396 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
3397 RegDeleteValueW(hkey
, lpNameW
);
3401 if (GetDefaultPrinterW( def
, &size
) && !strcmpW( def
, lpNameW
))
3403 WriteProfileStringW( windowsW
, deviceW
, NULL
);
3404 if (!RegCreateKeyW( HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
))
3406 RegDeleteValueW( hkey
, deviceW
);
3407 RegCloseKey( hkey
);
3409 SetDefaultPrinterW( NULL
);
3415 /*****************************************************************************
3416 * SetPrinterA [WINSPOOL.@]
3418 BOOL WINAPI
SetPrinterA( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3425 dataW
= printer_info_AtoW( data
, level
);
3426 if (!dataW
) return FALSE
;
3429 ret
= SetPrinterW( printer
, level
, dataW
, command
);
3431 if (dataW
!= data
) free_printer_info( dataW
, level
);
3436 static void set_printer_2( HKEY key
, const PRINTER_INFO_2W
*pi
)
3438 set_reg_szW( key
, NameW
, pi
->pPrinterName
);
3439 set_reg_szW( key
, Share_NameW
, pi
->pShareName
);
3440 set_reg_szW( key
, PortW
, pi
->pPortName
);
3441 set_reg_szW( key
, Printer_DriverW
, pi
->pDriverName
);
3442 set_reg_szW( key
, DescriptionW
, pi
->pComment
);
3443 set_reg_szW( key
, LocationW
, pi
->pLocation
);
3446 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3448 set_reg_szW( key
, Separator_FileW
, pi
->pSepFile
);
3449 set_reg_szW( key
, Print_ProcessorW
, pi
->pPrintProcessor
);
3450 set_reg_szW( key
, DatatypeW
, pi
->pDatatype
);
3451 set_reg_szW( key
, ParametersW
, pi
->pParameters
);
3453 set_reg_DWORD( key
, AttributesW
, pi
->Attributes
);
3454 set_reg_DWORD( key
, PriorityW
, pi
->Priority
);
3455 set_reg_DWORD( key
, Default_PriorityW
, pi
->DefaultPriority
);
3456 set_reg_DWORD( key
, StartTimeW
, pi
->StartTime
);
3457 set_reg_DWORD( key
, UntilTimeW
, pi
->UntilTime
);
3460 static BOOL
set_printer_9( HKEY key
, const PRINTER_INFO_9W
*pi
)
3462 if (!pi
->pDevMode
) return FALSE
;
3464 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3468 /******************************************************************************
3469 * SetPrinterW [WINSPOOL.@]
3471 BOOL WINAPI
SetPrinterW( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3476 TRACE( "(%p, %d, %p, %d)\n", printer
, level
, data
, command
);
3478 if (command
!= 0) FIXME( "Ignoring command %d\n", command
);
3480 if (WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
))
3487 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)data
;
3488 set_printer_2( key
, pi2
);
3494 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
3495 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
3499 PRINTER_INFO_9W
*pi
= (PRINTER_INFO_9W
*)data
;
3500 ret
= set_printer_9( key
, pi
);
3505 FIXME( "Unimplemented level %d\n", level
);
3506 SetLastError( ERROR_INVALID_LEVEL
);
3513 /*****************************************************************************
3514 * SetJobA [WINSPOOL.@]
3516 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3517 LPBYTE pJob
, DWORD Command
)
3521 UNICODE_STRING usBuffer
;
3523 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3525 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3526 are all ignored by SetJob, so we don't bother copying them */
3534 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3535 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3537 JobW
= (LPBYTE
)info1W
;
3538 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3539 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3540 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3541 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3542 info1W
->Status
= info1A
->Status
;
3543 info1W
->Priority
= info1A
->Priority
;
3544 info1W
->Position
= info1A
->Position
;
3545 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3550 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3551 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3553 JobW
= (LPBYTE
)info2W
;
3554 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3555 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3556 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3557 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3558 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3559 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3560 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3561 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3562 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3563 info2W
->Status
= info2A
->Status
;
3564 info2W
->Priority
= info2A
->Priority
;
3565 info2W
->Position
= info2A
->Position
;
3566 info2W
->StartTime
= info2A
->StartTime
;
3567 info2W
->UntilTime
= info2A
->UntilTime
;
3568 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3572 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3573 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3576 SetLastError(ERROR_INVALID_LEVEL
);
3580 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3586 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3587 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3588 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3589 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3590 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3595 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3596 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3597 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3598 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3599 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3600 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3601 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3602 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3603 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3607 HeapFree(GetProcessHeap(), 0, JobW
);
3612 /*****************************************************************************
3613 * SetJobW [WINSPOOL.@]
3615 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3616 LPBYTE pJob
, DWORD Command
)
3621 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3622 FIXME("Ignoring everything other than document title\n");
3624 EnterCriticalSection(&printer_handles_cs
);
3625 job
= get_job(hPrinter
, JobId
);
3635 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3636 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3637 job
->document_title
= strdupW(info1
->pDocument
);
3642 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3643 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3644 job
->document_title
= strdupW(info2
->pDocument
);
3645 HeapFree(GetProcessHeap(), 0, job
->devmode
);
3646 job
->devmode
= dup_devmode( info2
->pDevMode
);
3652 SetLastError(ERROR_INVALID_LEVEL
);
3657 LeaveCriticalSection(&printer_handles_cs
);
3661 /*****************************************************************************
3662 * EndDocPrinter [WINSPOOL.@]
3664 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3666 opened_printer_t
*printer
;
3668 TRACE("(%p)\n", hPrinter
);
3670 EnterCriticalSection(&printer_handles_cs
);
3672 printer
= get_opened_printer(hPrinter
);
3675 SetLastError(ERROR_INVALID_HANDLE
);
3681 SetLastError(ERROR_SPL_NO_STARTDOC
);
3685 CloseHandle(printer
->doc
->hf
);
3686 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3687 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3688 printer
->doc
= NULL
;
3691 LeaveCriticalSection(&printer_handles_cs
);
3695 /*****************************************************************************
3696 * EndPagePrinter [WINSPOOL.@]
3698 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3700 FIXME("(%p): stub\n", hPrinter
);
3704 /*****************************************************************************
3705 * StartDocPrinterA [WINSPOOL.@]
3707 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3709 UNICODE_STRING usBuffer
;
3711 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3714 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3715 or one (DOC_INFO_3) extra DWORDs */
3719 doc2W
.JobId
= doc2
->JobId
;
3722 doc2W
.dwMode
= doc2
->dwMode
;
3725 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3726 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3727 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3731 SetLastError(ERROR_INVALID_LEVEL
);
3735 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3737 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3738 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3739 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3744 /*****************************************************************************
3745 * StartDocPrinterW [WINSPOOL.@]
3747 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3749 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3750 opened_printer_t
*printer
;
3751 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3752 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3753 JOB_INFO_1W job_info
;
3754 DWORD needed
, ret
= 0;
3759 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3760 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3761 debugstr_w(doc
->pDatatype
));
3763 if(Level
< 1 || Level
> 3)
3765 SetLastError(ERROR_INVALID_LEVEL
);
3769 EnterCriticalSection(&printer_handles_cs
);
3770 printer
= get_opened_printer(hPrinter
);
3773 SetLastError(ERROR_INVALID_HANDLE
);
3779 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3783 /* Even if we're printing to a file we still add a print job, we'll
3784 just ignore the spool file name */
3786 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3788 ERR("AddJob failed gle %u\n", GetLastError());
3792 /* use pOutputFile only, when it is a real filename */
3793 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3794 filename
= doc
->pOutputFile
;
3796 filename
= addjob
->Path
;
3798 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3799 if(hf
== INVALID_HANDLE_VALUE
)
3802 memset(&job_info
, 0, sizeof(job_info
));
3803 job_info
.pDocument
= doc
->pDocName
;
3804 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3806 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3807 printer
->doc
->hf
= hf
;
3808 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3809 job
= get_job(hPrinter
, ret
);
3810 job
->portname
= strdupW(doc
->pOutputFile
);
3813 LeaveCriticalSection(&printer_handles_cs
);
3818 /*****************************************************************************
3819 * StartPagePrinter [WINSPOOL.@]
3821 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3823 FIXME("(%p): stub\n", hPrinter
);
3827 /*****************************************************************************
3828 * GetFormA [WINSPOOL.@]
3830 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3831 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3833 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3834 Level
,pForm
,cbBuf
,pcbNeeded
);
3838 /*****************************************************************************
3839 * GetFormW [WINSPOOL.@]
3841 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3842 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3844 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3845 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3849 /*****************************************************************************
3850 * SetFormA [WINSPOOL.@]
3852 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3855 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3859 /*****************************************************************************
3860 * SetFormW [WINSPOOL.@]
3862 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3865 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3869 /*****************************************************************************
3870 * ReadPrinter [WINSPOOL.@]
3872 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3873 LPDWORD pNoBytesRead
)
3875 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3879 /*****************************************************************************
3880 * ResetPrinterA [WINSPOOL.@]
3882 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3884 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3888 /*****************************************************************************
3889 * ResetPrinterW [WINSPOOL.@]
3891 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3893 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3897 /*****************************************************************************
3898 * get_filename_from_reg [internal]
3900 * Get ValueName from hkey storing result in out
3901 * when the Value in the registry has only a filename, use driverdir as prefix
3902 * outlen is space left in out
3903 * String is stored either as unicode or ascii
3907 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3908 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3910 WCHAR filename
[MAX_PATH
];
3914 LPWSTR buffer
= filename
;
3918 size
= sizeof(filename
);
3920 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3921 if (ret
== ERROR_MORE_DATA
) {
3922 TRACE("need dynamic buffer: %u\n", size
);
3923 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3925 /* No Memory is bad */
3929 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3932 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3933 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3939 /* do we have a full path ? */
3940 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3941 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3944 /* we must build the full Path */
3946 if ((out
) && (outlen
> dirlen
)) {
3947 lstrcpyW((LPWSTR
)out
, driverdir
);
3955 /* write the filename */
3956 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3957 if ((out
) && (outlen
>= size
)) {
3958 lstrcpyW((LPWSTR
)out
, ptr
);
3965 ptr
+= lstrlenW(ptr
)+1;
3966 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3969 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3971 /* write the multisz-termination */
3972 if (type
== REG_MULTI_SZ
) {
3973 size
= sizeof(WCHAR
);
3976 if (out
&& (outlen
>= size
)) {
3977 memset (out
, 0, size
);
3983 /*****************************************************************************
3984 * WINSPOOL_GetStringFromReg
3986 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3987 * String is stored as unicode.
3989 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3990 DWORD buflen
, DWORD
*needed
)
3992 DWORD sz
= buflen
, type
;
3995 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3996 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3997 WARN("Got ret = %d\n", ret
);
4001 /* add space for terminating '\0' */
4002 sz
+= sizeof(WCHAR
);
4006 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
4011 /*****************************************************************************
4012 * WINSPOOL_GetDefaultDevMode
4014 * Get a default DevMode values for wineps.
4016 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr
, DWORD buflen
, DWORD
*needed
)
4018 static const WCHAR winepsW
[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4020 if (buflen
>= sizeof(DEVMODEW
))
4022 DEVMODEW
*dm
= (DEVMODEW
*)ptr
;
4024 /* the driver will update registry with real values */
4025 memset(dm
, 0, sizeof(*dm
));
4026 dm
->dmSize
= sizeof(*dm
);
4027 lstrcpyW(dm
->dmDeviceName
, winepsW
);
4029 *needed
= sizeof(DEVMODEW
);
4032 /*****************************************************************************
4033 * WINSPOOL_GetDevModeFromReg
4035 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4036 * DevMode is stored either as unicode or ascii.
4038 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
4040 DWORD buflen
, DWORD
*needed
)
4042 DWORD sz
= buflen
, type
;
4045 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
4046 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
4047 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
4048 if (sz
< sizeof(DEVMODEA
))
4050 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
4053 /* ensures that dmSize is not erratically bogus if registry is invalid */
4054 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
4055 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
4056 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
4057 if (ptr
&& (buflen
>= sz
)) {
4058 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
4059 memcpy(ptr
, dmW
, sz
);
4060 HeapFree(GetProcessHeap(),0,dmW
);
4066 /*********************************************************************
4067 * WINSPOOL_GetPrinter_1
4069 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4071 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
4072 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4074 DWORD size
, left
= cbBuf
;
4075 BOOL space
= (cbBuf
> 0);
4080 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4081 if(space
&& size
<= left
) {
4082 pi1
->pName
= (LPWSTR
)ptr
;
4090 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4091 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4092 if(space
&& size
<= left
) {
4093 pi1
->pDescription
= (LPWSTR
)ptr
;
4101 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4102 if(space
&& size
<= left
) {
4103 pi1
->pComment
= (LPWSTR
)ptr
;
4111 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
4113 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
4114 memset(pi1
, 0, sizeof(*pi1
));
4118 /*********************************************************************
4119 * WINSPOOL_GetPrinter_2
4121 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4123 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
4124 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4126 DWORD size
, left
= cbBuf
;
4127 BOOL space
= (cbBuf
> 0);
4132 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4133 if(space
&& size
<= left
) {
4134 pi2
->pPrinterName
= (LPWSTR
)ptr
;
4141 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
4142 if(space
&& size
<= left
) {
4143 pi2
->pShareName
= (LPWSTR
)ptr
;
4150 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4151 if(space
&& size
<= left
) {
4152 pi2
->pPortName
= (LPWSTR
)ptr
;
4159 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
4160 if(space
&& size
<= left
) {
4161 pi2
->pDriverName
= (LPWSTR
)ptr
;
4168 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4169 if(space
&& size
<= left
) {
4170 pi2
->pComment
= (LPWSTR
)ptr
;
4177 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
4178 if(space
&& size
<= left
) {
4179 pi2
->pLocation
= (LPWSTR
)ptr
;
4186 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
4187 if(space
&& size
<= left
) {
4188 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4197 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
4198 if(space
&& size
<= left
) {
4199 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4206 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
4207 if(space
&& size
<= left
) {
4208 pi2
->pSepFile
= (LPWSTR
)ptr
;
4215 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
4216 if(space
&& size
<= left
) {
4217 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
4224 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
4225 if(space
&& size
<= left
) {
4226 pi2
->pDatatype
= (LPWSTR
)ptr
;
4233 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
4234 if(space
&& size
<= left
) {
4235 pi2
->pParameters
= (LPWSTR
)ptr
;
4243 pi2
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4244 pi2
->Priority
= get_dword_from_reg( hkeyPrinter
, PriorityW
);
4245 pi2
->DefaultPriority
= get_dword_from_reg( hkeyPrinter
, Default_PriorityW
);
4246 pi2
->StartTime
= get_dword_from_reg( hkeyPrinter
, StartTimeW
);
4247 pi2
->UntilTime
= get_dword_from_reg( hkeyPrinter
, UntilTimeW
);
4250 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
4251 memset(pi2
, 0, sizeof(*pi2
));
4256 /*********************************************************************
4257 * WINSPOOL_GetPrinter_4
4259 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4261 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
4262 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4264 DWORD size
, left
= cbBuf
;
4265 BOOL space
= (cbBuf
> 0);
4270 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4271 if(space
&& size
<= left
) {
4272 pi4
->pPrinterName
= (LPWSTR
)ptr
;
4280 pi4
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4283 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
4284 memset(pi4
, 0, sizeof(*pi4
));
4289 /*********************************************************************
4290 * WINSPOOL_GetPrinter_5
4292 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4294 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
4295 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4297 DWORD size
, left
= cbBuf
;
4298 BOOL space
= (cbBuf
> 0);
4303 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4304 if(space
&& size
<= left
) {
4305 pi5
->pPrinterName
= (LPWSTR
)ptr
;
4312 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4313 if(space
&& size
<= left
) {
4314 pi5
->pPortName
= (LPWSTR
)ptr
;
4322 pi5
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4323 pi5
->DeviceNotSelectedTimeout
= get_dword_from_reg( hkeyPrinter
, dnsTimeoutW
);
4324 pi5
->TransmissionRetryTimeout
= get_dword_from_reg( hkeyPrinter
, txTimeoutW
);
4327 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
4328 memset(pi5
, 0, sizeof(*pi5
));
4333 /*********************************************************************
4334 * WINSPOOL_GetPrinter_7
4336 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4338 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
4339 DWORD cbBuf
, LPDWORD pcbNeeded
)
4341 DWORD size
, left
= cbBuf
;
4342 BOOL space
= (cbBuf
> 0);
4347 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
4350 size
= sizeof(pi7
->pszObjectGUID
);
4352 if (space
&& size
<= left
) {
4353 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
4360 /* We do not have a Directory Service */
4361 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
4364 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
4365 memset(pi7
, 0, sizeof(*pi7
));
4370 /*********************************************************************
4371 * WINSPOOL_GetPrinter_9
4373 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4375 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
4376 DWORD cbBuf
, LPDWORD pcbNeeded
)
4379 BOOL space
= (cbBuf
> 0);
4383 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
4384 if(space
&& size
<= cbBuf
) {
4385 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4392 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
4393 if(space
&& size
<= cbBuf
) {
4394 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4400 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
4401 memset(pi9
, 0, sizeof(*pi9
));
4406 /*****************************************************************************
4407 * GetPrinterW [WINSPOOL.@]
4409 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4410 DWORD cbBuf
, LPDWORD pcbNeeded
)
4412 DWORD size
, needed
= 0, err
;
4417 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4419 err
= WINSPOOL_GetOpenedPrinterRegKey( hPrinter
, &hkeyPrinter
);
4422 SetLastError( err
);
4429 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4431 size
= sizeof(PRINTER_INFO_2W
);
4433 ptr
= pPrinter
+ size
;
4435 memset(pPrinter
, 0, size
);
4440 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
4447 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4449 size
= sizeof(PRINTER_INFO_4W
);
4451 ptr
= pPrinter
+ size
;
4453 memset(pPrinter
, 0, size
);
4458 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
4466 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4468 size
= sizeof(PRINTER_INFO_5W
);
4470 ptr
= pPrinter
+ size
;
4472 memset(pPrinter
, 0, size
);
4478 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
4486 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4488 size
= sizeof(PRINTER_INFO_6
);
4489 if (size
<= cbBuf
) {
4490 /* FIXME: We do not update the status yet */
4491 pi6
->dwStatus
= get_dword_from_reg( hkeyPrinter
, StatusW
);
4503 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4505 size
= sizeof(PRINTER_INFO_7W
);
4506 if (size
<= cbBuf
) {
4507 ptr
= pPrinter
+ size
;
4509 memset(pPrinter
, 0, size
);
4515 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
4522 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4523 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4527 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4529 size
= sizeof(PRINTER_INFO_9W
);
4531 ptr
= pPrinter
+ size
;
4533 memset(pPrinter
, 0, size
);
4539 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
4546 FIXME("Unimplemented level %d\n", Level
);
4547 SetLastError(ERROR_INVALID_LEVEL
);
4548 RegCloseKey(hkeyPrinter
);
4552 RegCloseKey(hkeyPrinter
);
4554 TRACE("returning %d needed = %d\n", ret
, needed
);
4555 if(pcbNeeded
) *pcbNeeded
= needed
;
4557 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4561 /*****************************************************************************
4562 * GetPrinterA [WINSPOOL.@]
4564 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4565 DWORD cbBuf
, LPDWORD pcbNeeded
)
4571 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4573 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
4575 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
4576 HeapFree(GetProcessHeap(), 0, buf
);
4581 /*****************************************************************************
4582 * WINSPOOL_EnumPrintersW
4584 * Implementation of EnumPrintersW
4586 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
4587 DWORD dwLevel
, LPBYTE lpbPrinters
,
4588 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4589 LPDWORD lpdwReturned
)
4592 HKEY hkeyPrinters
, hkeyPrinter
;
4593 WCHAR PrinterName
[255];
4594 DWORD needed
= 0, number
= 0;
4595 DWORD used
, i
, left
;
4599 memset(lpbPrinters
, 0, cbBuf
);
4605 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4606 if(dwType
== PRINTER_ENUM_DEFAULT
)
4609 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4610 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4611 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4613 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4619 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4620 FIXME("dwType = %08x\n", dwType
);
4621 SetLastError(ERROR_INVALID_FLAGS
);
4625 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4627 ERR("Can't create Printers key\n");
4631 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4632 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4633 RegCloseKey(hkeyPrinters
);
4634 ERR("Can't query Printers key\n");
4637 TRACE("Found %d printers\n", number
);
4641 used
= number
* sizeof(PRINTER_INFO_1W
);
4644 used
= number
* sizeof(PRINTER_INFO_2W
);
4647 used
= number
* sizeof(PRINTER_INFO_4W
);
4650 used
= number
* sizeof(PRINTER_INFO_5W
);
4654 SetLastError(ERROR_INVALID_LEVEL
);
4655 RegCloseKey(hkeyPrinters
);
4658 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4660 for(i
= 0; i
< number
; i
++) {
4661 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4663 ERR("Can't enum key number %d\n", i
);
4664 RegCloseKey(hkeyPrinters
);
4667 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4668 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4670 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4671 RegCloseKey(hkeyPrinters
);
4676 buf
= lpbPrinters
+ used
;
4677 left
= cbBuf
- used
;
4685 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4688 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4691 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4694 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4697 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4700 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4703 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4706 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4709 ERR("Shouldn't be here!\n");
4710 RegCloseKey(hkeyPrinter
);
4711 RegCloseKey(hkeyPrinters
);
4714 RegCloseKey(hkeyPrinter
);
4716 RegCloseKey(hkeyPrinters
);
4723 memset(lpbPrinters
, 0, cbBuf
);
4724 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4728 *lpdwReturned
= number
;
4729 SetLastError(ERROR_SUCCESS
);
4734 /******************************************************************
4735 * EnumPrintersW [WINSPOOL.@]
4737 * Enumerates the available printers, print servers and print
4738 * providers, depending on the specified flags, name and level.
4742 * If level is set to 1:
4743 * Returns an array of PRINTER_INFO_1 data structures in the
4744 * lpbPrinters buffer.
4746 * If level is set to 2:
4747 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4748 * Returns an array of PRINTER_INFO_2 data structures in the
4749 * lpbPrinters buffer. Note that according to MSDN also an
4750 * OpenPrinter should be performed on every remote printer.
4752 * If level is set to 4 (officially WinNT only):
4753 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4754 * Fast: Only the registry is queried to retrieve printer names,
4755 * no connection to the driver is made.
4756 * Returns an array of PRINTER_INFO_4 data structures in the
4757 * lpbPrinters buffer.
4759 * If level is set to 5 (officially WinNT4/Win9x only):
4760 * Fast: Only the registry is queried to retrieve printer names,
4761 * no connection to the driver is made.
4762 * Returns an array of PRINTER_INFO_5 data structures in the
4763 * lpbPrinters buffer.
4765 * If level set to 3 or 6+:
4766 * returns zero (failure!)
4768 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4772 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4773 * - Only levels 2, 4 and 5 are implemented at the moment.
4774 * - 16-bit printer drivers are not enumerated.
4775 * - Returned amount of bytes used/needed does not match the real Windoze
4776 * implementation (as in this implementation, all strings are part
4777 * of the buffer, whereas Win32 keeps them somewhere else)
4778 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4781 * - In a regular Wine installation, no registry settings for printers
4782 * exist, which makes this function return an empty list.
4784 BOOL WINAPI
EnumPrintersW(
4785 DWORD dwType
, /* [in] Types of print objects to enumerate */
4786 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4787 DWORD dwLevel
, /* [in] type of printer info structure */
4788 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4789 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4790 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4791 LPDWORD lpdwReturned
/* [out] number of entries returned */
4794 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4795 lpdwNeeded
, lpdwReturned
);
4798 /******************************************************************
4799 * EnumPrintersA [WINSPOOL.@]
4804 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4805 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4808 UNICODE_STRING pNameU
;
4812 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4813 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4815 pNameW
= asciitounicode(&pNameU
, pName
);
4817 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4818 MS Office need this */
4819 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4821 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4823 RtlFreeUnicodeString(&pNameU
);
4825 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4827 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4831 /*****************************************************************************
4832 * WINSPOOL_GetDriverInfoFromReg [internal]
4834 * Enters the information from the registry into the DRIVER_INFO struct
4837 * zero if the printer driver does not exist in the registry
4838 * (only if Level > 1) otherwise nonzero
4840 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4843 const printenv_t
* env
,
4845 LPBYTE ptr
, /* DRIVER_INFO */
4846 LPBYTE pDriverStrings
, /* strings buffer */
4847 DWORD cbBuf
, /* size of string buffer */
4848 LPDWORD pcbNeeded
) /* space needed for str. */
4852 WCHAR driverdir
[MAX_PATH
];
4854 LPBYTE strPtr
= pDriverStrings
;
4855 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4857 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4858 debugstr_w(DriverName
), env
,
4859 Level
, di
, pDriverStrings
, cbBuf
);
4861 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4863 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4864 if (*pcbNeeded
<= cbBuf
)
4865 strcpyW((LPWSTR
)strPtr
, DriverName
);
4867 /* pName for level 1 has a different offset! */
4869 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4873 /* .cVersion and .pName for level > 1 */
4875 di
->cVersion
= env
->driverversion
;
4876 di
->pName
= (LPWSTR
) strPtr
;
4877 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4880 /* Reserve Space for the largest subdir and a Backslash*/
4881 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4882 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4883 /* Should never Fail */
4886 lstrcatW(driverdir
, env
->versionsubdir
);
4887 lstrcatW(driverdir
, backslashW
);
4889 /* dirlen must not include the terminating zero */
4890 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4892 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4893 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4894 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4899 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4902 if (*pcbNeeded
<= cbBuf
) {
4903 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4904 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4905 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4908 /* .pDriverPath is the Graphics rendering engine.
4909 The full Path is required to avoid a crash in some apps */
4910 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4912 if (*pcbNeeded
<= cbBuf
)
4913 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4915 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4916 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4919 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4920 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4922 if (*pcbNeeded
<= cbBuf
)
4923 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4925 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4926 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4929 /* .pConfigFile is the Driver user Interface */
4930 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4932 if (*pcbNeeded
<= cbBuf
)
4933 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4935 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4936 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4940 RegCloseKey(hkeyDriver
);
4941 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4946 RegCloseKey(hkeyDriver
);
4947 FIXME("level 5: incomplete\n");
4952 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4954 if (*pcbNeeded
<= cbBuf
)
4955 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4957 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4958 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4961 /* .pDependentFiles */
4962 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4964 if (*pcbNeeded
<= cbBuf
)
4965 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4967 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4968 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4970 else if (GetVersion() & 0x80000000) {
4971 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4972 size
= 2 * sizeof(WCHAR
);
4974 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4976 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4977 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4980 /* .pMonitorName is the optional Language Monitor */
4981 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4983 if (*pcbNeeded
<= cbBuf
)
4984 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4986 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4987 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4990 /* .pDefaultDataType */
4991 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
4993 if(*pcbNeeded
<= cbBuf
)
4994 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
4996 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4997 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5001 RegCloseKey(hkeyDriver
);
5002 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5006 /* .pszzPreviousNames */
5007 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
5009 if(*pcbNeeded
<= cbBuf
)
5010 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
5012 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
5013 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5017 RegCloseKey(hkeyDriver
);
5018 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5022 /* support is missing, but not important enough for a FIXME */
5023 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
5026 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
5028 if(*pcbNeeded
<= cbBuf
)
5029 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
5031 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
5032 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5036 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
5038 if(*pcbNeeded
<= cbBuf
)
5039 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
5041 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
5042 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5045 /* .pszHardwareID */
5046 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
5048 if(*pcbNeeded
<= cbBuf
)
5049 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
5051 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
5052 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5056 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
5058 if(*pcbNeeded
<= cbBuf
)
5059 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
5061 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
5062 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5066 RegCloseKey(hkeyDriver
);
5070 /* support is missing, but not important enough for a FIXME */
5071 TRACE("level 8: incomplete\n");
5073 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5074 RegCloseKey(hkeyDriver
);
5078 /*****************************************************************************
5079 * GetPrinterDriverW [WINSPOOL.@]
5081 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
5082 DWORD Level
, LPBYTE pDriverInfo
,
5083 DWORD cbBuf
, LPDWORD pcbNeeded
)
5086 WCHAR DriverName
[100];
5087 DWORD ret
, type
, size
, needed
= 0;
5089 HKEY hkeyPrinter
, hkeyDrivers
;
5090 const printenv_t
* env
;
5092 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
5093 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
5096 ZeroMemory(pDriverInfo
, cbBuf
);
5098 if (!(name
= get_opened_printer_name(hPrinter
))) {
5099 SetLastError(ERROR_INVALID_HANDLE
);
5103 if (Level
< 1 || Level
== 7 || Level
> 8) {
5104 SetLastError(ERROR_INVALID_LEVEL
);
5108 env
= validate_envW(pEnvironment
);
5109 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5111 ret
= open_printer_reg_key( name
, &hkeyPrinter
);
5114 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name
) );
5115 SetLastError( ret
);
5119 size
= sizeof(DriverName
);
5121 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
5122 (LPBYTE
)DriverName
, &size
);
5123 RegCloseKey(hkeyPrinter
);
5124 if(ret
!= ERROR_SUCCESS
) {
5125 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
5129 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5131 ERR("Can't create Drivers key\n");
5135 size
= di_sizeof
[Level
];
5136 if ((size
<= cbBuf
) && pDriverInfo
)
5137 ptr
= pDriverInfo
+ size
;
5139 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
5140 env
, Level
, pDriverInfo
, ptr
,
5141 (cbBuf
< size
) ? 0 : cbBuf
- size
,
5143 RegCloseKey(hkeyDrivers
);
5147 RegCloseKey(hkeyDrivers
);
5149 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
5150 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
5151 if(cbBuf
>= size
+ needed
) return TRUE
;
5152 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5156 /*****************************************************************************
5157 * GetPrinterDriverA [WINSPOOL.@]
5159 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
5160 DWORD Level
, LPBYTE pDriverInfo
,
5161 DWORD cbBuf
, LPDWORD pcbNeeded
)
5164 UNICODE_STRING pEnvW
;
5170 ZeroMemory(pDriverInfo
, cbBuf
);
5171 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5174 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
5175 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
5178 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
5180 HeapFree(GetProcessHeap(), 0, buf
);
5182 RtlFreeUnicodeString(&pEnvW
);
5186 /*****************************************************************************
5187 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5189 * Return the PATH for the Printer-Drivers (UNICODE)
5192 * pName [I] Servername (NT only) or NULL (local Computer)
5193 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5194 * Level [I] Structure-Level (must be 1)
5195 * pDriverDirectory [O] PTR to Buffer that receives the Result
5196 * cbBuf [I] Size of Buffer at pDriverDirectory
5197 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5198 * required for pDriverDirectory
5201 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5202 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5203 * if cbBuf is too small
5205 * Native Values returned in pDriverDirectory on Success:
5206 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5207 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5208 *| win9x(Windows 4.0): "%winsysdir%"
5210 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5213 *- Only NULL or "" is supported for pName
5216 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
5217 DWORD Level
, LPBYTE pDriverDirectory
,
5218 DWORD cbBuf
, LPDWORD pcbNeeded
)
5220 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
5221 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5223 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5226 /* (Level != 1) is ignored in win9x */
5227 SetLastError(ERROR_INVALID_LEVEL
);
5230 if (pcbNeeded
== NULL
) {
5231 /* (pcbNeeded == NULL) is ignored in win9x */
5232 SetLastError(RPC_X_NULL_REF_POINTER
);
5236 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
5237 pDriverDirectory
, cbBuf
, pcbNeeded
);
5242 /*****************************************************************************
5243 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5245 * Return the PATH for the Printer-Drivers (ANSI)
5247 * See GetPrinterDriverDirectoryW.
5250 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5253 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
5254 DWORD Level
, LPBYTE pDriverDirectory
,
5255 DWORD cbBuf
, LPDWORD pcbNeeded
)
5257 UNICODE_STRING nameW
, environmentW
;
5260 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
5261 WCHAR
*driverDirectoryW
= NULL
;
5263 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
5264 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5266 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
5268 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
5269 else nameW
.Buffer
= NULL
;
5270 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
5271 else environmentW
.Buffer
= NULL
;
5273 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
5274 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
5277 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
5278 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
5280 *pcbNeeded
= needed
;
5281 ret
= needed
<= cbBuf
;
5283 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
5285 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
5287 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
5288 RtlFreeUnicodeString(&environmentW
);
5289 RtlFreeUnicodeString(&nameW
);
5294 /*****************************************************************************
5295 * AddPrinterDriverA [WINSPOOL.@]
5297 * See AddPrinterDriverW.
5300 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5302 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
5303 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5306 /******************************************************************************
5307 * AddPrinterDriverW (WINSPOOL.@)
5309 * Install a Printer Driver
5312 * pName [I] Servername or NULL (local Computer)
5313 * level [I] Level for the supplied DRIVER_INFO_*W struct
5314 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5321 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5323 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
5324 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5327 /*****************************************************************************
5328 * AddPrintProcessorA [WINSPOOL.@]
5330 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
5331 LPSTR pPrintProcessorName
)
5333 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5334 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
5338 /*****************************************************************************
5339 * AddPrintProcessorW [WINSPOOL.@]
5341 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5342 LPWSTR pPrintProcessorName
)
5344 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5345 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5349 /*****************************************************************************
5350 * AddPrintProvidorA [WINSPOOL.@]
5352 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5354 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5358 /*****************************************************************************
5359 * AddPrintProvidorW [WINSPOOL.@]
5361 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5363 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5367 /*****************************************************************************
5368 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5370 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5371 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5373 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5374 pDevModeOutput
, pDevModeInput
);
5378 /*****************************************************************************
5379 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5381 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5382 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5384 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5385 pDevModeOutput
, pDevModeInput
);
5389 /*****************************************************************************
5390 * PrinterProperties [WINSPOOL.@]
5392 * Displays a dialog to set the properties of the printer.
5395 * nonzero on success or zero on failure
5398 * implemented as stub only
5400 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5401 HANDLE hPrinter
/* [in] handle to printer object */
5403 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5404 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5408 /*****************************************************************************
5409 * EnumJobsA [WINSPOOL.@]
5412 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5413 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5416 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5417 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5419 if(pcbNeeded
) *pcbNeeded
= 0;
5420 if(pcReturned
) *pcReturned
= 0;
5425 /*****************************************************************************
5426 * EnumJobsW [WINSPOOL.@]
5429 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5430 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5433 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5434 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5436 if(pcbNeeded
) *pcbNeeded
= 0;
5437 if(pcReturned
) *pcReturned
= 0;
5441 /*****************************************************************************
5442 * WINSPOOL_EnumPrinterDrivers [internal]
5444 * Delivers information about all printer drivers installed on the
5445 * localhost or a given server
5448 * nonzero on success or zero on failure. If the buffer for the returned
5449 * information is too small the function will return an error
5452 * - only implemented for localhost, foreign hosts will return an error
5454 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5455 DWORD Level
, LPBYTE pDriverInfo
,
5457 DWORD cbBuf
, LPDWORD pcbNeeded
,
5458 LPDWORD pcFound
, DWORD data_offset
)
5462 const printenv_t
* env
;
5464 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5465 debugstr_w(pName
), debugstr_w(pEnvironment
),
5466 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
5468 env
= validate_envW(pEnvironment
);
5469 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5473 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5475 ERR("Can't open Drivers key\n");
5479 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
5480 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5481 RegCloseKey(hkeyDrivers
);
5482 ERR("Can't query Drivers key\n");
5485 TRACE("Found %d Drivers\n", *pcFound
);
5487 /* get size of single struct
5488 * unicode and ascii structure have the same size
5490 size
= di_sizeof
[Level
];
5492 if (data_offset
== 0)
5493 data_offset
= size
* (*pcFound
);
5494 *pcbNeeded
= data_offset
;
5496 for( i
= 0; i
< *pcFound
; i
++) {
5497 WCHAR DriverNameW
[255];
5498 PBYTE table_ptr
= NULL
;
5499 PBYTE data_ptr
= NULL
;
5502 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
5504 ERR("Can't enum key number %d\n", i
);
5505 RegCloseKey(hkeyDrivers
);
5509 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
5510 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
5511 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
5512 data_ptr
= pDriverInfo
+ *pcbNeeded
;
5514 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5515 env
, Level
, table_ptr
, data_ptr
,
5516 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5518 RegCloseKey(hkeyDrivers
);
5522 *pcbNeeded
+= needed
;
5525 RegCloseKey(hkeyDrivers
);
5527 if(cbBuf
< *pcbNeeded
){
5528 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5535 /*****************************************************************************
5536 * EnumPrinterDriversW [WINSPOOL.@]
5538 * see function EnumPrinterDrivers for RETURNS, BUGS
5540 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5541 LPBYTE pDriverInfo
, DWORD cbBuf
,
5542 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5544 static const WCHAR allW
[] = {'a','l','l',0};
5548 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
5550 SetLastError(RPC_X_NULL_REF_POINTER
);
5554 /* check for local drivers */
5555 if((pName
) && (pName
[0])) {
5556 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5557 SetLastError(ERROR_ACCESS_DENIED
);
5561 /* check input parameter */
5562 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5563 SetLastError(ERROR_INVALID_LEVEL
);
5567 if(pDriverInfo
&& cbBuf
> 0)
5568 memset( pDriverInfo
, 0, cbBuf
);
5570 /* Exception: pull all printers */
5571 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
5573 DWORD i
, needed
, bufsize
= cbBuf
;
5574 DWORD total_found
= 0;
5577 /* Precompute the overall total; we need this to know
5578 where pointers end and data begins (i.e. data_offset) */
5579 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5582 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5583 NULL
, 0, 0, &needed
, &found
, 0);
5584 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5585 total_found
+= found
;
5588 data_offset
= di_sizeof
[Level
] * total_found
;
5593 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5596 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5597 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
5598 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5600 *pcReturned
+= found
;
5601 *pcbNeeded
= needed
;
5602 data_offset
= needed
;
5603 total_found
+= found
;
5608 /* Normal behavior */
5609 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5610 0, cbBuf
, pcbNeeded
, &found
, 0);
5612 *pcReturned
= found
;
5617 /*****************************************************************************
5618 * EnumPrinterDriversA [WINSPOOL.@]
5620 * see function EnumPrinterDrivers for RETURNS, BUGS
5622 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5623 LPBYTE pDriverInfo
, DWORD cbBuf
,
5624 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5627 UNICODE_STRING pNameW
, pEnvironmentW
;
5628 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5632 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5634 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5635 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5637 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5638 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5640 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5642 HeapFree(GetProcessHeap(), 0, buf
);
5644 RtlFreeUnicodeString(&pNameW
);
5645 RtlFreeUnicodeString(&pEnvironmentW
);
5650 /******************************************************************************
5651 * EnumPortsA (WINSPOOL.@)
5656 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5657 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5660 LPBYTE bufferW
= NULL
;
5661 LPWSTR nameW
= NULL
;
5663 DWORD numentries
= 0;
5666 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5667 cbBuf
, pcbNeeded
, pcReturned
);
5669 /* convert servername to unicode */
5671 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5672 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5673 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5675 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5676 needed
= cbBuf
* sizeof(WCHAR
);
5677 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5678 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5680 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5681 if (pcbNeeded
) needed
= *pcbNeeded
;
5682 /* HeapReAlloc return NULL, when bufferW was NULL */
5683 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5684 HeapAlloc(GetProcessHeap(), 0, needed
);
5686 /* Try again with the large Buffer */
5687 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5689 needed
= pcbNeeded
? *pcbNeeded
: 0;
5690 numentries
= pcReturned
? *pcReturned
: 0;
5693 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5694 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5697 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5698 DWORD entrysize
= 0;
5701 LPPORT_INFO_2W pi2w
;
5702 LPPORT_INFO_2A pi2a
;
5705 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5707 /* First pass: calculate the size for all Entries */
5708 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5709 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5711 while (index
< numentries
) {
5713 needed
+= entrysize
; /* PORT_INFO_?A */
5714 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5716 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5717 NULL
, 0, NULL
, NULL
);
5719 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5720 NULL
, 0, NULL
, NULL
);
5721 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5722 NULL
, 0, NULL
, NULL
);
5724 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5725 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5726 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5729 /* check for errors and quit on failure */
5730 if (cbBuf
< needed
) {
5731 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5735 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5736 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5737 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5738 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5739 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5741 /* Second Pass: Fill the User Buffer (if we have one) */
5742 while ((index
< numentries
) && pPorts
) {
5744 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5745 pi2a
->pPortName
= ptr
;
5746 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5747 ptr
, cbBuf
, NULL
, NULL
);
5751 pi2a
->pMonitorName
= ptr
;
5752 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5753 ptr
, cbBuf
, NULL
, NULL
);
5757 pi2a
->pDescription
= ptr
;
5758 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5759 ptr
, cbBuf
, NULL
, NULL
);
5763 pi2a
->fPortType
= pi2w
->fPortType
;
5764 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5767 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5768 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5769 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5774 if (pcbNeeded
) *pcbNeeded
= needed
;
5775 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5777 HeapFree(GetProcessHeap(), 0, nameW
);
5778 HeapFree(GetProcessHeap(), 0, bufferW
);
5780 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5781 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5787 /******************************************************************************
5788 * EnumPortsW (WINSPOOL.@)
5790 * Enumerate available Ports
5793 * pName [I] Servername or NULL (local Computer)
5794 * Level [I] Structure-Level (1 or 2)
5795 * pPorts [O] PTR to Buffer that receives the Result
5796 * cbBuf [I] Size of Buffer at pPorts
5797 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5798 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5802 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5805 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5808 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5809 cbBuf
, pcbNeeded
, pcReturned
);
5811 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5813 /* Level is not checked in win9x */
5814 if (!Level
|| (Level
> 2)) {
5815 WARN("level (%d) is ignored in win9x\n", Level
);
5816 SetLastError(ERROR_INVALID_LEVEL
);
5819 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5820 SetLastError(RPC_X_NULL_REF_POINTER
);
5824 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5827 /******************************************************************************
5828 * GetDefaultPrinterW (WINSPOOL.@)
5831 * This function must read the value from data 'device' of key
5832 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5834 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5838 WCHAR
*buffer
, *ptr
;
5842 SetLastError(ERROR_INVALID_PARAMETER
);
5846 /* make the buffer big enough for the stuff from the profile/registry,
5847 * the content must fit into the local buffer to compute the correct
5848 * size even if the extern buffer is too small or not given.
5849 * (20 for ,driver,port) */
5851 len
= max(100, (insize
+ 20));
5852 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5854 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5856 SetLastError (ERROR_FILE_NOT_FOUND
);
5860 TRACE("%s\n", debugstr_w(buffer
));
5862 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5864 SetLastError(ERROR_INVALID_NAME
);
5870 *namesize
= strlenW(buffer
) + 1;
5871 if(!name
|| (*namesize
> insize
))
5873 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5877 strcpyW(name
, buffer
);
5880 HeapFree( GetProcessHeap(), 0, buffer
);
5885 /******************************************************************************
5886 * GetDefaultPrinterA (WINSPOOL.@)
5888 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5892 WCHAR
*bufferW
= NULL
;
5896 SetLastError(ERROR_INVALID_PARAMETER
);
5900 if(name
&& *namesize
) {
5902 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5905 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5910 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5914 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5917 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5920 HeapFree( GetProcessHeap(), 0, bufferW
);
5925 /******************************************************************************
5926 * SetDefaultPrinterW (WINSPOOL.204)
5928 * Set the Name of the Default Printer
5931 * pszPrinter [I] Name of the Printer or NULL
5938 * When the Parameter is NULL or points to an Empty String and
5939 * a Default Printer was already present, then this Function changes nothing.
5940 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5941 * the First enumerated local Printer is used.
5944 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5946 WCHAR default_printer
[MAX_PATH
];
5947 LPWSTR buffer
= NULL
;
5953 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5954 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5956 default_printer
[0] = '\0';
5957 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5959 /* if we have a default Printer, do nothing. */
5960 if (GetDefaultPrinterW(default_printer
, &size
))
5964 /* we have no default Printer: search local Printers and use the first */
5965 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
5967 default_printer
[0] = '\0';
5968 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5969 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
5971 pszPrinter
= default_printer
;
5972 TRACE("using %s\n", debugstr_w(pszPrinter
));
5977 if (pszPrinter
== NULL
) {
5978 TRACE("no local printer found\n");
5979 SetLastError(ERROR_FILE_NOT_FOUND
);
5984 /* "pszPrinter" is never empty or NULL here. */
5985 namelen
= lstrlenW(pszPrinter
);
5986 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5987 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5989 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
5990 HeapFree(GetProcessHeap(), 0, buffer
);
5991 SetLastError(ERROR_FILE_NOT_FOUND
);
5995 /* read the devices entry for the printer (driver,port) to build the string for the
5996 default device entry (printer,driver,port) */
5997 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
5998 buffer
[namelen
] = ',';
5999 namelen
++; /* move index to the start of the driver */
6001 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
6002 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
6004 TRACE("set device to %s\n", debugstr_w(buffer
));
6006 if (!WriteProfileStringW(windowsW
, deviceW
, buffer
)) {
6007 TRACE("failed to set the device entry: %d\n", GetLastError());
6008 lres
= ERROR_INVALID_PRINTER_NAME
;
6011 /* remove the next section, when INIFileMapping is implemented */
6014 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
)) {
6015 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (LPBYTE
)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
6022 if (lres
!= ERROR_FILE_NOT_FOUND
)
6023 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
6025 SetLastError(ERROR_INVALID_PRINTER_NAME
);
6029 HeapFree(GetProcessHeap(), 0, buffer
);
6030 return (lres
== ERROR_SUCCESS
);
6033 /******************************************************************************
6034 * SetDefaultPrinterA (WINSPOOL.202)
6036 * See SetDefaultPrinterW.
6039 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
6041 LPWSTR bufferW
= NULL
;
6044 TRACE("(%s)\n", debugstr_a(pszPrinter
));
6046 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
6047 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6048 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
6050 res
= SetDefaultPrinterW(bufferW
);
6051 HeapFree(GetProcessHeap(), 0, bufferW
);
6055 /******************************************************************************
6056 * SetPrinterDataExA (WINSPOOL.@)
6058 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6059 LPCSTR pValueName
, DWORD Type
,
6060 LPBYTE pData
, DWORD cbData
)
6062 HKEY hkeyPrinter
, hkeySubkey
;
6065 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
6066 debugstr_a(pValueName
), Type
, pData
, cbData
);
6068 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6072 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6074 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
6075 RegCloseKey(hkeyPrinter
);
6078 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6079 RegCloseKey(hkeySubkey
);
6080 RegCloseKey(hkeyPrinter
);
6084 /******************************************************************************
6085 * SetPrinterDataExW (WINSPOOL.@)
6087 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6088 LPCWSTR pValueName
, DWORD Type
,
6089 LPBYTE pData
, DWORD cbData
)
6091 HKEY hkeyPrinter
, hkeySubkey
;
6094 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
6095 debugstr_w(pValueName
), Type
, pData
, cbData
);
6097 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6101 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6103 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
6104 RegCloseKey(hkeyPrinter
);
6107 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6108 RegCloseKey(hkeySubkey
);
6109 RegCloseKey(hkeyPrinter
);
6113 /******************************************************************************
6114 * SetPrinterDataA (WINSPOOL.@)
6116 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
6117 LPBYTE pData
, DWORD cbData
)
6119 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
6123 /******************************************************************************
6124 * SetPrinterDataW (WINSPOOL.@)
6126 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
6127 LPBYTE pData
, DWORD cbData
)
6129 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
6133 /******************************************************************************
6134 * GetPrinterDataExA (WINSPOOL.@)
6136 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6137 LPCSTR pValueName
, LPDWORD pType
,
6138 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6140 opened_printer_t
*printer
;
6141 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6144 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
6145 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6147 printer
= get_opened_printer(hPrinter
);
6148 if(!printer
) return ERROR_INVALID_HANDLE
;
6150 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6151 if (ret
) return ret
;
6153 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6155 if (printer
->name
) {
6157 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6159 RegCloseKey(hkeyPrinters
);
6162 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6163 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
6164 RegCloseKey(hkeyPrinter
);
6165 RegCloseKey(hkeyPrinters
);
6170 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6171 0, pType
, pData
, pcbNeeded
);
6173 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6175 RegCloseKey(hkeySubkey
);
6176 RegCloseKey(hkeyPrinter
);
6177 RegCloseKey(hkeyPrinters
);
6179 TRACE("--> %d\n", ret
);
6183 /******************************************************************************
6184 * GetPrinterDataExW (WINSPOOL.@)
6186 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6187 LPCWSTR pValueName
, LPDWORD pType
,
6188 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6190 opened_printer_t
*printer
;
6191 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6194 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
6195 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6197 printer
= get_opened_printer(hPrinter
);
6198 if(!printer
) return ERROR_INVALID_HANDLE
;
6200 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6201 if (ret
) return ret
;
6203 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6205 if (printer
->name
) {
6207 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6209 RegCloseKey(hkeyPrinters
);
6212 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6213 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
6214 RegCloseKey(hkeyPrinter
);
6215 RegCloseKey(hkeyPrinters
);
6220 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6221 0, pType
, pData
, pcbNeeded
);
6223 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6225 RegCloseKey(hkeySubkey
);
6226 RegCloseKey(hkeyPrinter
);
6227 RegCloseKey(hkeyPrinters
);
6229 TRACE("--> %d\n", ret
);
6233 /******************************************************************************
6234 * GetPrinterDataA (WINSPOOL.@)
6236 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
6237 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6239 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
6240 pData
, nSize
, pcbNeeded
);
6243 /******************************************************************************
6244 * GetPrinterDataW (WINSPOOL.@)
6246 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
6247 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6249 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
6250 pData
, nSize
, pcbNeeded
);
6253 /*******************************************************************************
6254 * EnumPrinterDataExW [WINSPOOL.@]
6256 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6257 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6258 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6260 HKEY hkPrinter
, hkSubKey
;
6261 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
6262 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
6267 PPRINTER_ENUM_VALUESW ppev
;
6269 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
6271 if (pKeyName
== NULL
|| *pKeyName
== 0)
6272 return ERROR_INVALID_PARAMETER
;
6274 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
6275 if (ret
!= ERROR_SUCCESS
)
6277 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6282 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
6283 if (ret
!= ERROR_SUCCESS
)
6285 r
= RegCloseKey (hkPrinter
);
6286 if (r
!= ERROR_SUCCESS
)
6287 WARN ("RegCloseKey returned %i\n", r
);
6288 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
6289 debugstr_w (pKeyName
), ret
);
6293 ret
= RegCloseKey (hkPrinter
);
6294 if (ret
!= ERROR_SUCCESS
)
6296 ERR ("RegCloseKey returned %i\n", ret
);
6297 r
= RegCloseKey (hkSubKey
);
6298 if (r
!= ERROR_SUCCESS
)
6299 WARN ("RegCloseKey returned %i\n", r
);
6303 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
6304 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
6305 if (ret
!= ERROR_SUCCESS
)
6307 r
= RegCloseKey (hkSubKey
);
6308 if (r
!= ERROR_SUCCESS
)
6309 WARN ("RegCloseKey returned %i\n", r
);
6310 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
6314 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6315 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
6317 if (cValues
== 0) /* empty key */
6319 r
= RegCloseKey (hkSubKey
);
6320 if (r
!= ERROR_SUCCESS
)
6321 WARN ("RegCloseKey returned %i\n", r
);
6322 *pcbEnumValues
= *pnEnumValues
= 0;
6323 return ERROR_SUCCESS
;
6326 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
6328 hHeap
= GetProcessHeap ();
6331 ERR ("GetProcessHeap failed\n");
6332 r
= RegCloseKey (hkSubKey
);
6333 if (r
!= ERROR_SUCCESS
)
6334 WARN ("RegCloseKey returned %i\n", r
);
6335 return ERROR_OUTOFMEMORY
;
6338 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
6339 if (lpValueName
== NULL
)
6341 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
6342 r
= RegCloseKey (hkSubKey
);
6343 if (r
!= ERROR_SUCCESS
)
6344 WARN ("RegCloseKey returned %i\n", r
);
6345 return ERROR_OUTOFMEMORY
;
6348 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
6349 if (lpValue
== NULL
)
6351 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
6352 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6353 WARN ("HeapFree failed with code %i\n", GetLastError ());
6354 r
= RegCloseKey (hkSubKey
);
6355 if (r
!= ERROR_SUCCESS
)
6356 WARN ("RegCloseKey returned %i\n", r
);
6357 return ERROR_OUTOFMEMORY
;
6360 TRACE ("pass 1: calculating buffer required for all names and values\n");
6362 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6364 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
6366 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6368 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6369 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6370 NULL
, NULL
, lpValue
, &cbValueLen
);
6371 if (ret
!= ERROR_SUCCESS
)
6373 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6374 WARN ("HeapFree failed with code %i\n", GetLastError ());
6375 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6376 WARN ("HeapFree failed with code %i\n", GetLastError ());
6377 r
= RegCloseKey (hkSubKey
);
6378 if (r
!= ERROR_SUCCESS
)
6379 WARN ("RegCloseKey returned %i\n", r
);
6380 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6384 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6385 debugstr_w (lpValueName
), dwIndex
,
6386 cbValueNameLen
+ 1, cbValueLen
);
6388 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6389 cbBufSize
+= cbValueLen
;
6392 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
6394 *pcbEnumValues
= cbBufSize
;
6395 *pnEnumValues
= cValues
;
6397 if (cbEnumValues
< cbBufSize
) /* buffer too small */
6399 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6400 WARN ("HeapFree failed with code %i\n", GetLastError ());
6401 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6402 WARN ("HeapFree failed with code %i\n", GetLastError ());
6403 r
= RegCloseKey (hkSubKey
);
6404 if (r
!= ERROR_SUCCESS
)
6405 WARN ("RegCloseKey returned %i\n", r
);
6406 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
6407 return ERROR_MORE_DATA
;
6410 TRACE ("pass 2: copying all names and values to buffer\n");
6412 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
6413 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6415 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6417 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6418 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6419 NULL
, &dwType
, lpValue
, &cbValueLen
);
6420 if (ret
!= ERROR_SUCCESS
)
6422 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6423 WARN ("HeapFree failed with code %i\n", GetLastError ());
6424 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6425 WARN ("HeapFree failed with code %i\n", GetLastError ());
6426 r
= RegCloseKey (hkSubKey
);
6427 if (r
!= ERROR_SUCCESS
)
6428 WARN ("RegCloseKey returned %i\n", r
);
6429 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6433 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6434 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
6435 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
6436 pEnumValues
+= cbValueNameLen
;
6438 /* return # of *bytes* (including trailing \0), not # of chars */
6439 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
6441 ppev
[dwIndex
].dwType
= dwType
;
6443 memcpy (pEnumValues
, lpValue
, cbValueLen
);
6444 ppev
[dwIndex
].pData
= pEnumValues
;
6445 pEnumValues
+= cbValueLen
;
6447 ppev
[dwIndex
].cbData
= cbValueLen
;
6449 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6450 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
6453 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6455 ret
= GetLastError ();
6456 ERR ("HeapFree failed with code %i\n", ret
);
6457 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6458 WARN ("HeapFree failed with code %i\n", GetLastError ());
6459 r
= RegCloseKey (hkSubKey
);
6460 if (r
!= ERROR_SUCCESS
)
6461 WARN ("RegCloseKey returned %i\n", r
);
6465 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6467 ret
= GetLastError ();
6468 ERR ("HeapFree failed with code %i\n", ret
);
6469 r
= RegCloseKey (hkSubKey
);
6470 if (r
!= ERROR_SUCCESS
)
6471 WARN ("RegCloseKey returned %i\n", r
);
6475 ret
= RegCloseKey (hkSubKey
);
6476 if (ret
!= ERROR_SUCCESS
)
6478 ERR ("RegCloseKey returned %i\n", ret
);
6482 return ERROR_SUCCESS
;
6485 /*******************************************************************************
6486 * EnumPrinterDataExA [WINSPOOL.@]
6488 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6489 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6490 * what Windows 2000 SP1 does.
6493 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6494 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6495 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6499 DWORD ret
, dwIndex
, dwBufSize
;
6503 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6505 if (pKeyName
== NULL
|| *pKeyName
== 0)
6506 return ERROR_INVALID_PARAMETER
;
6508 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6511 ret
= GetLastError ();
6512 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6516 hHeap
= GetProcessHeap ();
6519 ERR ("GetProcessHeap failed\n");
6520 return ERROR_OUTOFMEMORY
;
6523 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6524 if (pKeyNameW
== NULL
)
6526 ERR ("Failed to allocate %i bytes from process heap\n",
6527 (LONG
)(len
* sizeof (WCHAR
)));
6528 return ERROR_OUTOFMEMORY
;
6531 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6533 ret
= GetLastError ();
6534 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6535 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6536 WARN ("HeapFree failed with code %i\n", GetLastError ());
6540 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6541 pcbEnumValues
, pnEnumValues
);
6542 if (ret
!= ERROR_SUCCESS
)
6544 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6545 WARN ("HeapFree failed with code %i\n", GetLastError ());
6546 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6550 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6552 ret
= GetLastError ();
6553 ERR ("HeapFree failed with code %i\n", ret
);
6557 if (*pnEnumValues
== 0) /* empty key */
6558 return ERROR_SUCCESS
;
6561 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6563 PPRINTER_ENUM_VALUESW ppev
=
6564 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6566 if (dwBufSize
< ppev
->cbValueName
)
6567 dwBufSize
= ppev
->cbValueName
;
6569 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6570 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6571 dwBufSize
= ppev
->cbData
;
6574 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6576 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6577 if (pBuffer
== NULL
)
6579 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6580 return ERROR_OUTOFMEMORY
;
6583 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6585 PPRINTER_ENUM_VALUESW ppev
=
6586 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6588 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6589 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6593 ret
= GetLastError ();
6594 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6595 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6596 WARN ("HeapFree failed with code %i\n", GetLastError ());
6600 memcpy (ppev
->pValueName
, pBuffer
, len
);
6602 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6604 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6605 ppev
->dwType
!= REG_MULTI_SZ
)
6608 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6609 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6612 ret
= GetLastError ();
6613 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6614 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6615 WARN ("HeapFree failed with code %i\n", GetLastError ());
6619 memcpy (ppev
->pData
, pBuffer
, len
);
6621 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6622 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6625 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6627 ret
= GetLastError ();
6628 ERR ("HeapFree failed with code %i\n", ret
);
6632 return ERROR_SUCCESS
;
6635 /******************************************************************************
6636 * AbortPrinter (WINSPOOL.@)
6638 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6640 FIXME("(%p), stub!\n", hPrinter
);
6644 /******************************************************************************
6645 * AddPortA (WINSPOOL.@)
6650 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6652 LPWSTR nameW
= NULL
;
6653 LPWSTR monitorW
= NULL
;
6657 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6660 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6661 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6662 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6666 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6667 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6668 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6670 res
= AddPortW(nameW
, hWnd
, monitorW
);
6671 HeapFree(GetProcessHeap(), 0, nameW
);
6672 HeapFree(GetProcessHeap(), 0, monitorW
);
6676 /******************************************************************************
6677 * AddPortW (WINSPOOL.@)
6679 * Add a Port for a specific Monitor
6682 * pName [I] Servername or NULL (local Computer)
6683 * hWnd [I] Handle to parent Window for the Dialog-Box
6684 * pMonitorName [I] Name of the Monitor that manage the Port
6691 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6693 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6695 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6697 if (!pMonitorName
) {
6698 SetLastError(RPC_X_NULL_REF_POINTER
);
6702 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6705 /******************************************************************************
6706 * AddPortExA (WINSPOOL.@)
6711 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6714 PORT_INFO_2A
* pi2A
;
6715 LPWSTR nameW
= NULL
;
6716 LPWSTR monitorW
= NULL
;
6720 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6722 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6723 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6725 if ((level
< 1) || (level
> 2)) {
6726 SetLastError(ERROR_INVALID_LEVEL
);
6731 SetLastError(ERROR_INVALID_PARAMETER
);
6736 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6737 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6738 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6742 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6743 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6744 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6747 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6749 if (pi2A
->pPortName
) {
6750 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6751 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6752 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6756 if (pi2A
->pMonitorName
) {
6757 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6758 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6759 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6762 if (pi2A
->pDescription
) {
6763 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6764 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6765 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6767 pi2W
.fPortType
= pi2A
->fPortType
;
6768 pi2W
.Reserved
= pi2A
->Reserved
;
6771 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6773 HeapFree(GetProcessHeap(), 0, nameW
);
6774 HeapFree(GetProcessHeap(), 0, monitorW
);
6775 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6776 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6777 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6782 /******************************************************************************
6783 * AddPortExW (WINSPOOL.@)
6785 * Add a Port for a specific Monitor, without presenting a user interface
6788 * pName [I] Servername or NULL (local Computer)
6789 * level [I] Structure-Level (1 or 2) for pBuffer
6790 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6791 * pMonitorName [I] Name of the Monitor that manage the Port
6798 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6802 pi2
= (PORT_INFO_2W
*) pBuffer
;
6804 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6805 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6806 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6807 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6809 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6811 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6812 SetLastError(ERROR_INVALID_PARAMETER
);
6816 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6819 /******************************************************************************
6820 * AddPrinterConnectionA (WINSPOOL.@)
6822 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6824 FIXME("%s\n", debugstr_a(pName
));
6828 /******************************************************************************
6829 * AddPrinterConnectionW (WINSPOOL.@)
6831 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6833 FIXME("%s\n", debugstr_w(pName
));
6837 /******************************************************************************
6838 * AddPrinterDriverExW (WINSPOOL.@)
6840 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6843 * pName [I] Servername or NULL (local Computer)
6844 * level [I] Level for the supplied DRIVER_INFO_*W struct
6845 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6846 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6853 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6855 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6857 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6859 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6860 SetLastError(ERROR_INVALID_LEVEL
);
6865 SetLastError(ERROR_INVALID_PARAMETER
);
6869 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6872 /******************************************************************************
6873 * AddPrinterDriverExA (WINSPOOL.@)
6875 * See AddPrinterDriverExW.
6878 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6880 DRIVER_INFO_8A
*diA
;
6882 LPWSTR nameW
= NULL
;
6887 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6889 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6890 ZeroMemory(&diW
, sizeof(diW
));
6892 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6893 SetLastError(ERROR_INVALID_LEVEL
);
6898 SetLastError(ERROR_INVALID_PARAMETER
);
6902 /* convert servername to unicode */
6904 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6905 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6906 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6910 diW
.cVersion
= diA
->cVersion
;
6913 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6914 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6915 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6918 if (diA
->pEnvironment
) {
6919 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6920 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6921 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6924 if (diA
->pDriverPath
) {
6925 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6926 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6927 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6930 if (diA
->pDataFile
) {
6931 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6932 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6933 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6936 if (diA
->pConfigFile
) {
6937 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6938 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6939 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6942 if ((Level
> 2) && diA
->pDependentFiles
) {
6943 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6944 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6945 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6946 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6949 if ((Level
> 2) && diA
->pMonitorName
) {
6950 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6951 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6952 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6955 if ((Level
> 3) && diA
->pDefaultDataType
) {
6956 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6957 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6958 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6961 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6962 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6963 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6964 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6965 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6968 if ((Level
> 5) && diA
->pszMfgName
) {
6969 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6970 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6971 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6974 if ((Level
> 5) && diA
->pszOEMUrl
) {
6975 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6976 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6977 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6980 if ((Level
> 5) && diA
->pszHardwareID
) {
6981 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6982 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6983 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6986 if ((Level
> 5) && diA
->pszProvider
) {
6987 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6988 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6989 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6993 FIXME("level %u is incomplete\n", Level
);
6996 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6997 TRACE("got %u with %u\n", res
, GetLastError());
6998 HeapFree(GetProcessHeap(), 0, nameW
);
6999 HeapFree(GetProcessHeap(), 0, diW
.pName
);
7000 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
7001 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
7002 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
7003 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
7004 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
7005 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
7006 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
7007 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
7008 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
7009 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
7010 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
7011 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
7013 TRACE("=> %u with %u\n", res
, GetLastError());
7017 /******************************************************************************
7018 * ConfigurePortA (WINSPOOL.@)
7020 * See ConfigurePortW.
7023 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
7025 LPWSTR nameW
= NULL
;
7026 LPWSTR portW
= NULL
;
7030 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
7032 /* convert servername to unicode */
7034 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7035 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7036 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7039 /* convert portname to unicode */
7041 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
7042 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7043 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
7046 res
= ConfigurePortW(nameW
, hWnd
, portW
);
7047 HeapFree(GetProcessHeap(), 0, nameW
);
7048 HeapFree(GetProcessHeap(), 0, portW
);
7052 /******************************************************************************
7053 * ConfigurePortW (WINSPOOL.@)
7055 * Display the Configuration-Dialog for a specific Port
7058 * pName [I] Servername or NULL (local Computer)
7059 * hWnd [I] Handle to parent Window for the Dialog-Box
7060 * pPortName [I] Name of the Port, that should be configured
7067 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
7070 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
7072 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7075 SetLastError(RPC_X_NULL_REF_POINTER
);
7079 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
7082 /******************************************************************************
7083 * ConnectToPrinterDlg (WINSPOOL.@)
7085 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
7087 FIXME("%p %x\n", hWnd
, Flags
);
7091 /******************************************************************************
7092 * DeletePrinterConnectionA (WINSPOOL.@)
7094 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
7096 FIXME("%s\n", debugstr_a(pName
));
7100 /******************************************************************************
7101 * DeletePrinterConnectionW (WINSPOOL.@)
7103 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
7105 FIXME("%s\n", debugstr_w(pName
));
7109 /******************************************************************************
7110 * DeletePrinterDriverExW (WINSPOOL.@)
7112 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
7113 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7118 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7119 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
7121 if(pName
&& pName
[0])
7123 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
7124 SetLastError(ERROR_INVALID_PARAMETER
);
7130 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
7131 SetLastError(ERROR_INVALID_PARAMETER
);
7135 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
7139 ERR("Can't open drivers key\n");
7143 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
7146 RegCloseKey(hkey_drivers
);
7151 /******************************************************************************
7152 * DeletePrinterDriverExA (WINSPOOL.@)
7154 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
7155 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7157 UNICODE_STRING NameW
, EnvW
, DriverW
;
7160 asciitounicode(&NameW
, pName
);
7161 asciitounicode(&EnvW
, pEnvironment
);
7162 asciitounicode(&DriverW
, pDriverName
);
7164 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
7166 RtlFreeUnicodeString(&DriverW
);
7167 RtlFreeUnicodeString(&EnvW
);
7168 RtlFreeUnicodeString(&NameW
);
7173 /******************************************************************************
7174 * DeletePrinterDataExW (WINSPOOL.@)
7176 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
7179 FIXME("%p %s %s\n", hPrinter
,
7180 debugstr_w(pKeyName
), debugstr_w(pValueName
));
7181 return ERROR_INVALID_PARAMETER
;
7184 /******************************************************************************
7185 * DeletePrinterDataExA (WINSPOOL.@)
7187 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
7190 FIXME("%p %s %s\n", hPrinter
,
7191 debugstr_a(pKeyName
), debugstr_a(pValueName
));
7192 return ERROR_INVALID_PARAMETER
;
7195 /******************************************************************************
7196 * DeletePrintProcessorA (WINSPOOL.@)
7198 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
7200 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7201 debugstr_a(pPrintProcessorName
));
7205 /******************************************************************************
7206 * DeletePrintProcessorW (WINSPOOL.@)
7208 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
7210 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7211 debugstr_w(pPrintProcessorName
));
7215 /******************************************************************************
7216 * DeletePrintProvidorA (WINSPOOL.@)
7218 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
7220 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7221 debugstr_a(pPrintProviderName
));
7225 /******************************************************************************
7226 * DeletePrintProvidorW (WINSPOOL.@)
7228 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
7230 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7231 debugstr_w(pPrintProviderName
));
7235 /******************************************************************************
7236 * EnumFormsA (WINSPOOL.@)
7238 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7239 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7241 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7242 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7246 /******************************************************************************
7247 * EnumFormsW (WINSPOOL.@)
7249 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7250 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7252 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7253 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7257 /*****************************************************************************
7258 * EnumMonitorsA [WINSPOOL.@]
7260 * See EnumMonitorsW.
7263 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7264 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7267 LPBYTE bufferW
= NULL
;
7268 LPWSTR nameW
= NULL
;
7270 DWORD numentries
= 0;
7273 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
7274 cbBuf
, pcbNeeded
, pcReturned
);
7276 /* convert servername to unicode */
7278 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7279 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7280 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7282 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7283 needed
= cbBuf
* sizeof(WCHAR
);
7284 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7285 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7287 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7288 if (pcbNeeded
) needed
= *pcbNeeded
;
7289 /* HeapReAlloc return NULL, when bufferW was NULL */
7290 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7291 HeapAlloc(GetProcessHeap(), 0, needed
);
7293 /* Try again with the large Buffer */
7294 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7296 numentries
= pcReturned
? *pcReturned
: 0;
7299 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7300 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7303 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7304 DWORD entrysize
= 0;
7307 LPMONITOR_INFO_2W mi2w
;
7308 LPMONITOR_INFO_2A mi2a
;
7310 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7311 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
7313 /* First pass: calculate the size for all Entries */
7314 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7315 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7317 while (index
< numentries
) {
7319 needed
+= entrysize
; /* MONITOR_INFO_?A */
7320 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
7322 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7323 NULL
, 0, NULL
, NULL
);
7325 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7326 NULL
, 0, NULL
, NULL
);
7327 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7328 NULL
, 0, NULL
, NULL
);
7330 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7331 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7332 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7335 /* check for errors and quit on failure */
7336 if (cbBuf
< needed
) {
7337 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7341 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
7342 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
7343 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7344 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7345 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7347 /* Second Pass: Fill the User Buffer (if we have one) */
7348 while ((index
< numentries
) && pMonitors
) {
7350 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7352 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7353 ptr
, cbBuf
, NULL
, NULL
);
7357 mi2a
->pEnvironment
= ptr
;
7358 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7359 ptr
, cbBuf
, NULL
, NULL
);
7363 mi2a
->pDLLName
= ptr
;
7364 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7365 ptr
, cbBuf
, NULL
, NULL
);
7369 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7370 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7371 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7375 if (pcbNeeded
) *pcbNeeded
= needed
;
7376 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7378 HeapFree(GetProcessHeap(), 0, nameW
);
7379 HeapFree(GetProcessHeap(), 0, bufferW
);
7381 TRACE("returning %d with %d (%d byte for %d entries)\n",
7382 (res
), GetLastError(), needed
, numentries
);
7388 /*****************************************************************************
7389 * EnumMonitorsW [WINSPOOL.@]
7391 * Enumerate available Port-Monitors
7394 * pName [I] Servername or NULL (local Computer)
7395 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7396 * pMonitors [O] PTR to Buffer that receives the Result
7397 * cbBuf [I] Size of Buffer at pMonitors
7398 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7399 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7403 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7406 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7407 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7410 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7411 cbBuf
, pcbNeeded
, pcReturned
);
7413 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7415 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
7416 SetLastError(RPC_X_NULL_REF_POINTER
);
7420 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
7423 /******************************************************************************
7424 * SpoolerInit (WINSPOOL.@)
7426 * Initialize the Spooler
7433 * The function fails on windows, when the spooler service is not running
7436 BOOL WINAPI
SpoolerInit(void)
7439 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7443 /******************************************************************************
7444 * XcvDataW (WINSPOOL.@)
7446 * Execute commands in the Printmonitor DLL
7449 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7450 * pszDataName [i] Name of the command to execute
7451 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7452 * cbInputData [i] Size in Bytes of Buffer at pInputData
7453 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7454 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7455 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7456 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7463 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7464 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7466 * Minimal List of commands, that a Printmonitor DLL should support:
7468 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7469 *| "AddPort" : Add a Port
7470 *| "DeletePort": Delete a Port
7472 * Many Printmonitors support additional commands. Examples for localspl.dll:
7473 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7474 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7477 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7478 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7479 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7481 opened_printer_t
*printer
;
7483 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7484 pInputData
, cbInputData
, pOutputData
,
7485 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7487 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7489 printer
= get_opened_printer(hXcv
);
7490 if (!printer
|| (!printer
->backend_printer
)) {
7491 SetLastError(ERROR_INVALID_HANDLE
);
7495 if (!pcbOutputNeeded
) {
7496 SetLastError(ERROR_INVALID_PARAMETER
);
7500 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7501 SetLastError(RPC_X_NULL_REF_POINTER
);
7505 *pcbOutputNeeded
= 0;
7507 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
7508 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7512 /*****************************************************************************
7513 * EnumPrinterDataA [WINSPOOL.@]
7516 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7517 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7518 DWORD cbData
, LPDWORD pcbData
)
7520 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7521 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7522 return ERROR_NO_MORE_ITEMS
;
7525 /*****************************************************************************
7526 * EnumPrinterDataW [WINSPOOL.@]
7529 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7530 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7531 DWORD cbData
, LPDWORD pcbData
)
7533 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7534 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7535 return ERROR_NO_MORE_ITEMS
;
7538 /*****************************************************************************
7539 * EnumPrinterKeyA [WINSPOOL.@]
7542 DWORD WINAPI
EnumPrinterKeyA(HANDLE printer
, const CHAR
*key
, CHAR
*subkey
, DWORD size
, DWORD
*needed
)
7544 FIXME("%p %s %p %x %p\n", printer
, debugstr_a(key
), subkey
, size
, needed
);
7545 return ERROR_CALL_NOT_IMPLEMENTED
;
7548 /*****************************************************************************
7549 * EnumPrinterKeyW [WINSPOOL.@]
7552 DWORD WINAPI
EnumPrinterKeyW(HANDLE printer
, const WCHAR
*key
, WCHAR
*subkey
, DWORD size
, DWORD
*needed
)
7554 FIXME("%p %s %p %x %p\n", printer
, debugstr_w(key
), subkey
, size
, needed
);
7555 return ERROR_CALL_NOT_IMPLEMENTED
;
7558 /*****************************************************************************
7559 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7562 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7563 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7564 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7566 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7567 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7568 pcbNeeded
, pcReturned
);
7572 /*****************************************************************************
7573 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7576 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7577 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7578 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7580 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7581 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7582 pcbNeeded
, pcReturned
);
7586 /*****************************************************************************
7587 * EnumPrintProcessorsA [WINSPOOL.@]
7589 * See EnumPrintProcessorsW.
7592 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7593 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7596 LPBYTE bufferW
= NULL
;
7597 LPWSTR nameW
= NULL
;
7600 DWORD numentries
= 0;
7603 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7604 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7606 /* convert names to unicode */
7608 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7609 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7610 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7613 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
7614 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7615 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
7618 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7619 needed
= cbBuf
* sizeof(WCHAR
);
7620 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7621 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7623 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7624 if (pcbNeeded
) needed
= *pcbNeeded
;
7625 /* HeapReAlloc return NULL, when bufferW was NULL */
7626 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7627 HeapAlloc(GetProcessHeap(), 0, needed
);
7629 /* Try again with the large Buffer */
7630 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7632 numentries
= pcReturned
? *pcReturned
: 0;
7636 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7639 PPRINTPROCESSOR_INFO_1W ppiw
;
7640 PPRINTPROCESSOR_INFO_1A ppia
;
7642 /* First pass: calculate the size for all Entries */
7643 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7644 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7646 while (index
< numentries
) {
7648 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7649 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7651 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7652 NULL
, 0, NULL
, NULL
);
7654 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7655 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7658 /* check for errors and quit on failure */
7659 if (cbBuf
< needed
) {
7660 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7665 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7666 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7667 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7668 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7669 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7671 /* Second Pass: Fill the User Buffer (if we have one) */
7672 while ((index
< numentries
) && pPPInfo
) {
7674 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7676 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7677 ptr
, cbBuf
, NULL
, NULL
);
7681 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7682 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7687 if (pcbNeeded
) *pcbNeeded
= needed
;
7688 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7690 HeapFree(GetProcessHeap(), 0, nameW
);
7691 HeapFree(GetProcessHeap(), 0, envW
);
7692 HeapFree(GetProcessHeap(), 0, bufferW
);
7694 TRACE("returning %d with %d (%d byte for %d entries)\n",
7695 (res
), GetLastError(), needed
, numentries
);
7700 /*****************************************************************************
7701 * EnumPrintProcessorsW [WINSPOOL.@]
7703 * Enumerate available Print Processors
7706 * pName [I] Servername or NULL (local Computer)
7707 * pEnvironment [I] Printing-Environment or NULL (Default)
7708 * Level [I] Structure-Level (Only 1 is allowed)
7709 * pPPInfo [O] PTR to Buffer that receives the Result
7710 * cbBuf [I] Size of Buffer at pPPInfo
7711 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7712 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7716 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7719 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7720 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7723 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7724 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7726 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7728 if (!pcbNeeded
|| !pcReturned
) {
7729 SetLastError(RPC_X_NULL_REF_POINTER
);
7733 if (!pPPInfo
&& (cbBuf
> 0)) {
7734 SetLastError(ERROR_INVALID_USER_BUFFER
);
7738 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7739 cbBuf
, pcbNeeded
, pcReturned
);
7742 /*****************************************************************************
7743 * ExtDeviceMode [WINSPOOL.@]
7746 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7747 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7750 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7751 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7752 debugstr_a(pProfile
), fMode
);
7756 /*****************************************************************************
7757 * FindClosePrinterChangeNotification [WINSPOOL.@]
7760 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7762 FIXME("Stub: %p\n", hChange
);
7766 /*****************************************************************************
7767 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7770 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7771 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7773 FIXME("Stub: %p %x %x %p\n",
7774 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7775 return INVALID_HANDLE_VALUE
;
7778 /*****************************************************************************
7779 * FindNextPrinterChangeNotification [WINSPOOL.@]
7782 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7783 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7785 FIXME("Stub: %p %p %p %p\n",
7786 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7790 /*****************************************************************************
7791 * FreePrinterNotifyInfo [WINSPOOL.@]
7794 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7796 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7800 /*****************************************************************************
7803 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7804 * ansi depending on the unicode parameter.
7806 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7816 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7819 memcpy(ptr
, str
, *size
);
7826 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7829 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7836 /*****************************************************************************
7839 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7840 LPDWORD pcbNeeded
, BOOL unicode
)
7842 DWORD size
, left
= cbBuf
;
7843 BOOL space
= (cbBuf
> 0);
7850 ji1
->JobId
= job
->job_id
;
7853 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7854 if(space
&& size
<= left
)
7856 ji1
->pDocument
= (LPWSTR
)ptr
;
7864 if (job
->printer_name
)
7866 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7867 if(space
&& size
<= left
)
7869 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7881 /*****************************************************************************
7884 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7885 LPDWORD pcbNeeded
, BOOL unicode
)
7887 DWORD size
, left
= cbBuf
;
7889 BOOL space
= (cbBuf
> 0);
7891 LPDEVMODEA dmA
= NULL
;
7898 ji2
->JobId
= job
->job_id
;
7901 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7902 if(space
&& size
<= left
)
7904 ji2
->pDocument
= (LPWSTR
)ptr
;
7912 if (job
->printer_name
)
7914 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7915 if(space
&& size
<= left
)
7917 ji2
->pPrinterName
= (LPWSTR
)ptr
;
7930 dmA
= DEVMODEdupWtoA(job
->devmode
);
7931 devmode
= (LPDEVMODEW
) dmA
;
7932 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
7936 devmode
= job
->devmode
;
7937 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
7941 FIXME("Can't convert DEVMODE W to A\n");
7944 /* align DEVMODE to a DWORD boundary */
7945 shift
= (4 - (*pcbNeeded
& 3)) & 3;
7951 memcpy(ptr
, devmode
, size
-shift
);
7952 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
7953 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
7966 /*****************************************************************************
7969 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7970 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7973 DWORD needed
= 0, size
;
7977 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7979 EnterCriticalSection(&printer_handles_cs
);
7980 job
= get_job(hPrinter
, JobId
);
7987 size
= sizeof(JOB_INFO_1W
);
7992 memset(pJob
, 0, size
);
7996 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
8001 size
= sizeof(JOB_INFO_2W
);
8006 memset(pJob
, 0, size
);
8010 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
8015 size
= sizeof(JOB_INFO_3
);
8019 memset(pJob
, 0, size
);
8028 SetLastError(ERROR_INVALID_LEVEL
);
8032 *pcbNeeded
= needed
;
8034 LeaveCriticalSection(&printer_handles_cs
);
8038 /*****************************************************************************
8039 * GetJobA [WINSPOOL.@]
8042 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8043 DWORD cbBuf
, LPDWORD pcbNeeded
)
8045 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
8048 /*****************************************************************************
8049 * GetJobW [WINSPOOL.@]
8052 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8053 DWORD cbBuf
, LPDWORD pcbNeeded
)
8055 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
8058 /*****************************************************************************
8061 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
8064 char *unixname
, *cmdA
;
8066 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
8072 if(!(unixname
= wine_get_unix_file_name(filename
)))
8075 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
8076 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
8077 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
8079 TRACE("printing with: %s\n", cmdA
);
8081 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
8086 ERR("pipe() failed!\n");
8090 if ((pid
= fork()) == 0)
8096 /* reset signals that we previously set to SIG_IGN */
8097 signal(SIGPIPE
, SIG_DFL
);
8099 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
8104 ERR("fork() failed!\n");
8110 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
8111 write(fds
[1], buf
, no_read
);
8118 wret
= waitpid(pid
, &status
, 0);
8119 } while (wret
< 0 && errno
== EINTR
);
8122 ERR("waitpid() failed!\n");
8125 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
8127 ERR("child process failed! %d\n", status
);
8134 if(file_fd
!= -1) close(file_fd
);
8135 if(fds
[0] != -1) close(fds
[0]);
8136 if(fds
[1] != -1) close(fds
[1]);
8138 HeapFree(GetProcessHeap(), 0, cmdA
);
8139 HeapFree(GetProcessHeap(), 0, unixname
);
8146 /*****************************************************************************
8149 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
8152 const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8155 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
8156 sprintfW(cmd
, fmtW
, printer_name
);
8158 r
= schedule_pipe(cmd
, filename
);
8160 HeapFree(GetProcessHeap(), 0, cmd
);
8164 #ifdef SONAME_LIBCUPS
8165 /*****************************************************************************
8166 * get_cups_jobs_ticket_options
8168 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8169 * The CUPS scheduler only looks for these in Print-File requests, and since
8170 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8173 static int get_cups_job_ticket_options( const char *file
, int num_options
, cups_option_t
**options
)
8175 FILE *fp
= fopen( file
, "r" );
8176 char buf
[257]; /* DSC max of 256 + '\0' */
8177 const char *ps_adobe
= "%!PS-Adobe-";
8178 const char *cups_job
= "%cupsJobTicket:";
8180 if (!fp
) return num_options
;
8181 if (!fgets( buf
, sizeof(buf
), fp
)) goto end
;
8182 if (strncmp( buf
, ps_adobe
, strlen( ps_adobe
) )) goto end
;
8183 while (fgets( buf
, sizeof(buf
), fp
))
8185 if (strncmp( buf
, cups_job
, strlen( cups_job
) )) break;
8186 num_options
= pcupsParseOptions( buf
+ strlen( cups_job
), num_options
, options
);
8194 static int get_cups_default_options( const char *printer
, int num_options
, cups_option_t
**options
)
8199 if (!pcupsGetNamedDest
) return num_options
;
8201 dest
= pcupsGetNamedDest( NULL
, printer
, NULL
);
8202 if (!dest
) return num_options
;
8204 for (i
= 0; i
< dest
->num_options
; i
++)
8206 if (!pcupsGetOption( dest
->options
[i
].name
, num_options
, *options
))
8207 num_options
= pcupsAddOption( dest
->options
[i
].name
, dest
->options
[i
].value
,
8208 num_options
, options
);
8211 pcupsFreeDests( 1, dest
);
8216 /*****************************************************************************
8219 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
8221 #ifdef SONAME_LIBCUPS
8224 char *unixname
, *queue
, *unix_doc_title
;
8227 int num_options
= 0, i
;
8228 cups_option_t
*options
= NULL
;
8230 if(!(unixname
= wine_get_unix_file_name(filename
)))
8233 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
8234 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
8235 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
8237 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
8238 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
8239 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
8241 num_options
= get_cups_job_ticket_options( unixname
, num_options
, &options
);
8242 num_options
= get_cups_default_options( queue
, num_options
, &options
);
8244 TRACE( "printing via cups with options:\n" );
8245 for (i
= 0; i
< num_options
; i
++)
8246 TRACE( "\t%d: %s = %s\n", i
, options
[i
].name
, options
[i
].value
);
8248 ret
= pcupsPrintFile( queue
, unixname
, unix_doc_title
, num_options
, options
);
8249 if (ret
== 0 && pcupsLastErrorString
)
8250 WARN("cupsPrintFile failed with error %s\n", debugstr_a(pcupsLastErrorString()));
8252 pcupsFreeOptions( num_options
, options
);
8254 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
8255 HeapFree(GetProcessHeap(), 0, queue
);
8256 HeapFree(GetProcessHeap(), 0, unixname
);
8262 return schedule_lpr(printer_name
, filename
);
8266 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
8273 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
8277 if(HIWORD(wparam
) == BN_CLICKED
)
8279 if(LOWORD(wparam
) == IDOK
)
8282 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
8285 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
8286 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
8288 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
8290 WCHAR caption
[200], message
[200];
8293 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
8294 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
8295 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
8296 if(mb_ret
== IDCANCEL
)
8298 HeapFree(GetProcessHeap(), 0, filename
);
8302 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
8303 if(hf
== INVALID_HANDLE_VALUE
)
8305 WCHAR caption
[200], message
[200];
8307 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
8308 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
8309 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
8310 HeapFree(GetProcessHeap(), 0, filename
);
8314 DeleteFileW(filename
);
8315 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
8317 EndDialog(hwnd
, IDOK
);
8320 if(LOWORD(wparam
) == IDCANCEL
)
8322 EndDialog(hwnd
, IDCANCEL
);
8331 /*****************************************************************************
8334 static BOOL
get_filename(LPWSTR
*filename
)
8336 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
8337 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
8340 /*****************************************************************************
8343 static BOOL
schedule_file(LPCWSTR filename
)
8345 LPWSTR output
= NULL
;
8347 if(get_filename(&output
))
8350 TRACE("copy to %s\n", debugstr_w(output
));
8351 r
= CopyFileW(filename
, output
, FALSE
);
8352 HeapFree(GetProcessHeap(), 0, output
);
8358 /*****************************************************************************
8361 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
8363 int in_fd
, out_fd
, no_read
;
8366 char *unixname
, *outputA
;
8369 if(!(unixname
= wine_get_unix_file_name(filename
)))
8372 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
8373 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
8374 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
8376 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
8377 in_fd
= open(unixname
, O_RDONLY
);
8378 if(out_fd
== -1 || in_fd
== -1)
8381 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
8382 write(out_fd
, buf
, no_read
);
8386 if(in_fd
!= -1) close(in_fd
);
8387 if(out_fd
!= -1) close(out_fd
);
8388 HeapFree(GetProcessHeap(), 0, outputA
);
8389 HeapFree(GetProcessHeap(), 0, unixname
);
8393 /*****************************************************************************
8394 * ScheduleJob [WINSPOOL.@]
8397 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
8399 opened_printer_t
*printer
;
8401 struct list
*cursor
, *cursor2
;
8403 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
8404 EnterCriticalSection(&printer_handles_cs
);
8405 printer
= get_opened_printer(hPrinter
);
8409 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
8411 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
8414 if(job
->job_id
!= dwJobID
) continue;
8416 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
8417 if(hf
!= INVALID_HANDLE_VALUE
)
8419 PRINTER_INFO_5W
*pi5
= NULL
;
8420 LPWSTR portname
= job
->portname
;
8424 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8425 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8429 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
8430 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
8431 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
8432 portname
= pi5
->pPortName
;
8434 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
8435 debugstr_w(portname
));
8439 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8440 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
8442 DWORD type
, count
= sizeof(output
);
8443 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
8446 if(output
[0] == '|')
8448 ret
= schedule_pipe(output
+ 1, job
->filename
);
8452 ret
= schedule_unixfile(output
, job
->filename
);
8454 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
8456 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
8458 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
8460 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
8462 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
8464 ret
= schedule_file(job
->filename
);
8466 else if(isalpha(portname
[0]) && portname
[1] == ':')
8468 TRACE("copying to %s\n", debugstr_w(portname
));
8469 ret
= CopyFileW(job
->filename
, portname
, FALSE
);
8473 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
8475 HeapFree(GetProcessHeap(), 0, pi5
);
8477 DeleteFileW(job
->filename
);
8479 list_remove(cursor
);
8480 HeapFree(GetProcessHeap(), 0, job
->document_title
);
8481 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
8482 HeapFree(GetProcessHeap(), 0, job
->portname
);
8483 HeapFree(GetProcessHeap(), 0, job
->filename
);
8484 HeapFree(GetProcessHeap(), 0, job
->devmode
);
8485 HeapFree(GetProcessHeap(), 0, job
);
8489 LeaveCriticalSection(&printer_handles_cs
);
8493 /*****************************************************************************
8494 * StartDocDlgA [WINSPOOL.@]
8496 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
8498 UNICODE_STRING usBuffer
;
8501 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
8504 docW
.cbSize
= sizeof(docW
);
8505 if (doc
->lpszDocName
)
8507 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
8508 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
8510 if (doc
->lpszOutput
)
8512 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
8513 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
8515 if (doc
->lpszDatatype
)
8517 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
8518 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
8520 docW
.fwType
= doc
->fwType
;
8522 retW
= StartDocDlgW(hPrinter
, &docW
);
8526 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
8527 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
8528 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
8529 HeapFree(GetProcessHeap(), 0, retW
);
8532 HeapFree(GetProcessHeap(), 0, datatypeW
);
8533 HeapFree(GetProcessHeap(), 0, outputW
);
8534 HeapFree(GetProcessHeap(), 0, docnameW
);
8539 /*****************************************************************************
8540 * StartDocDlgW [WINSPOOL.@]
8542 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8543 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8544 * port is "FILE:". Also returns the full path if passed a relative path.
8546 * The caller should free the returned string from the process heap.
8548 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
8553 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
8555 PRINTER_INFO_5W
*pi5
;
8556 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
8557 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
8559 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
8560 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
8561 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
8563 HeapFree(GetProcessHeap(), 0, pi5
);
8566 HeapFree(GetProcessHeap(), 0, pi5
);
8569 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
8573 if (get_filename(&name
))
8575 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
8577 HeapFree(GetProcessHeap(), 0, name
);
8580 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8581 GetFullPathNameW(name
, len
, ret
, NULL
);
8582 HeapFree(GetProcessHeap(), 0, name
);
8587 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8590 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8591 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8593 attr
= GetFileAttributesW(ret
);
8594 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8596 HeapFree(GetProcessHeap(), 0, ret
);
8602 /*****************************************************************************
8603 * UploadPrinterDriverPackageA [WINSPOOL.@]
8605 HRESULT WINAPI
UploadPrinterDriverPackageA( LPCSTR server
, LPCSTR path
, LPCSTR env
,
8606 DWORD flags
, HWND hwnd
, LPSTR dst
, PULONG dstlen
)
8608 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_a(server
), debugstr_a(path
), debugstr_a(env
),
8609 flags
, hwnd
, dst
, dstlen
);
8613 /*****************************************************************************
8614 * UploadPrinterDriverPackageW [WINSPOOL.@]
8616 HRESULT WINAPI
UploadPrinterDriverPackageW( LPCWSTR server
, LPCWSTR path
, LPCWSTR env
,
8617 DWORD flags
, HWND hwnd
, LPWSTR dst
, PULONG dstlen
)
8619 FIXME("%s, %s, %s, %x, %p, %p, %p\n", debugstr_w(server
), debugstr_w(path
), debugstr_w(env
),
8620 flags
, hwnd
, dst
, dstlen
);