4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
37 #ifdef HAVE_SYS_WAIT_H
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
48 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
49 #define GetCurrentProcess GetCurrentProcess_Mac
50 #define GetCurrentThread GetCurrentThread_Mac
51 #define LoadResource LoadResource_Mac
52 #define AnimatePalette AnimatePalette_Mac
53 #define EqualRgn EqualRgn_Mac
54 #define FillRgn FillRgn_Mac
55 #define FrameRgn FrameRgn_Mac
56 #define GetPixel GetPixel_Mac
57 #define InvertRgn InvertRgn_Mac
58 #define LineTo LineTo_Mac
59 #define OffsetRgn OffsetRgn_Mac
60 #define PaintRgn PaintRgn_Mac
61 #define Polygon Polygon_Mac
62 #define ResizePalette ResizePalette_Mac
63 #define SetRectRgn SetRectRgn_Mac
64 #define EqualRect EqualRect_Mac
65 #define FillRect FillRect_Mac
66 #define FrameRect FrameRect_Mac
67 #define GetCursor GetCursor_Mac
68 #define InvertRect InvertRect_Mac
69 #define OffsetRect OffsetRect_Mac
70 #define PtInRect PtInRect_Mac
71 #define SetCursor SetCursor_Mac
72 #define SetRect SetRect_Mac
73 #define ShowCursor ShowCursor_Mac
74 #define UnionRect UnionRect_Mac
75 #include <ApplicationServices/ApplicationServices.h>
76 #undef GetCurrentProcess
77 #undef GetCurrentThread
105 #define NONAMELESSUNION
106 #define NONAMELESSSTRUCT
107 #include "wine/library.h"
111 #include "winerror.h"
114 #include "winspool.h"
115 #include "winternl.h"
116 #include "wine/windef16.h"
117 #include "wine/unicode.h"
118 #include "wine/debug.h"
119 #include "wine/list.h"
122 #include "ddk/winsplp.h"
125 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
127 /* ############################### */
129 static CRITICAL_SECTION printer_handles_cs
;
130 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
132 0, 0, &printer_handles_cs
,
133 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
134 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
136 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
138 /* ############################### */
153 HANDLE backend_printer
;
164 WCHAR
*document_title
;
174 LPCWSTR versionregpath
;
175 LPCWSTR versionsubdir
;
178 /* ############################### */
180 static opened_printer_t
**printer_handles
;
181 static UINT nb_printer_handles
;
182 static LONG next_job_id
= 1;
184 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
185 WORD fwCapability
, LPSTR lpszOutput
,
187 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
188 LPSTR lpszDevice
, LPSTR lpszPort
,
189 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
192 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
193 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
194 'c','o','n','t','r','o','l','\\',
195 'P','r','i','n','t','\\',
196 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
197 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
199 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
200 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
201 'C','o','n','t','r','o','l','\\',
202 'P','r','i','n','t','\\',
203 'P','r','i','n','t','e','r','s',0};
205 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
207 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
208 'M','i','c','r','o','s','o','f','t','\\',
209 'W','i','n','d','o','w','s',' ','N','T','\\',
210 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
211 'W','i','n','d','o','w','s',0};
213 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
214 'M','i','c','r','o','s','o','f','t','\\',
215 'W','i','n','d','o','w','s',' ','N','T','\\',
216 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
217 'D','e','v','i','c','e','s',0};
219 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
220 'M','i','c','r','o','s','o','f','t','\\',
221 'W','i','n','d','o','w','s',' ','N','T','\\',
222 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
223 'P','o','r','t','s',0};
225 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
226 'M','i','c','r','o','s','o','f','t','\\',
227 'W','i','n','d','o','w','s',' ','N','T','\\',
228 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
229 'P','r','i','n','t','e','r','P','o','r','t','s',0};
231 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
232 static WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
233 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
234 static WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
235 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
236 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
237 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
238 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
239 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
240 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
241 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
243 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
245 static const WCHAR AttributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0};
246 static const WCHAR backslashW
[] = {'\\',0};
247 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
248 'i','o','n',' ','F','i','l','e',0};
249 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
250 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
251 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
252 static const WCHAR Default_PriorityW
[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
253 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
254 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
255 static const WCHAR dnsTimeoutW
[] = {'d','n','s','T','i','m','e','o','u','t',0};
256 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
257 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
258 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
259 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
260 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
261 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
262 static const WCHAR NameW
[] = {'N','a','m','e',0};
263 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
264 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
265 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
266 static const WCHAR PortW
[] = {'P','o','r','t',0};
267 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
268 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
269 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
270 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
271 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
272 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
273 static const WCHAR PriorityW
[] = {'P','r','i','o','r','i','t','y',0};
274 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
275 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
276 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
277 static const WCHAR StartTimeW
[] = {'S','t','a','r','t','T','i','m','e',0};
278 static const WCHAR StatusW
[] = {'S','t','a','t','u','s',0};
279 static const WCHAR txTimeoutW
[] = {'t','x','T','i','m','e','o','u','t',0};
280 static const WCHAR UntilTimeW
[] = {'U','n','t','i','l','T','i','m','e',0};
281 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
282 static WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
283 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
284 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
285 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
286 static WCHAR rawW
[] = {'R','A','W',0};
287 static WCHAR driver_9x
[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
288 static WCHAR driver_nt
[] = {'w','i','n','e','p','s','.','d','r','v',0};
289 static const WCHAR timeout_15_45
[] = {',','1','5',',','4','5',0};
290 static const WCHAR commaW
[] = {',',0};
291 static WCHAR emptyStringW
[] = {0};
293 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
295 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
296 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
297 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
299 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
300 'D','o','c','u','m','e','n','t',0};
302 static const WCHAR PPD_Overrides
[] = {'P','P','D',' ','O','v','e','r','r','i','d','e','s',0};
303 static const WCHAR DefaultPageSize
[] = {'D','e','f','a','u','l','t','P','a','g','e','S','i','z','e',0};
305 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
306 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
307 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
308 0, sizeof(DRIVER_INFO_8W
)};
311 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
312 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
313 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
314 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
315 sizeof(PRINTER_INFO_9W
)};
317 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
318 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
319 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
321 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
323 /******************************************************************
324 * validate the user-supplied printing-environment [internal]
327 * env [I] PTR to Environment-String or NULL
331 * Success: PTR to printenv_t
334 * An empty string is handled the same way as NULL.
335 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
339 static const printenv_t
* validate_envW(LPCWSTR env
)
341 const printenv_t
*result
= NULL
;
344 TRACE("testing %s\n", debugstr_w(env
));
347 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
349 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
351 result
= all_printenv
[i
];
356 if (result
== NULL
) {
357 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
358 SetLastError(ERROR_INVALID_ENVIRONMENT
);
360 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
364 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
366 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
372 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
373 if passed a NULL string. This returns NULLs to the result.
375 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
379 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
380 return usBufferPtr
->Buffer
;
382 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
386 static LPWSTR
strdupW(LPCWSTR p
)
392 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
393 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
398 static LPSTR
strdupWtoA( LPCWSTR str
)
403 if (!str
) return NULL
;
404 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
405 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
406 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
410 static DEVMODEW
*dup_devmode( const DEVMODEW
*dm
)
414 if (!dm
) return NULL
;
415 ret
= HeapAlloc( GetProcessHeap(), 0, dm
->dmSize
+ dm
->dmDriverExtra
);
416 if (ret
) memcpy( ret
, dm
, dm
->dmSize
+ dm
->dmDriverExtra
);
420 /***********************************************************
422 * Creates an ansi copy of supplied devmode
424 static DEVMODEA
*DEVMODEdupWtoA( const DEVMODEW
*dmW
)
429 if (!dmW
) return NULL
;
430 size
= dmW
->dmSize
- CCHDEVICENAME
-
431 ((dmW
->dmSize
> FIELD_OFFSET( DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
433 dmA
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
434 if (!dmA
) return NULL
;
436 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmDeviceName
, -1,
437 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
439 if (FIELD_OFFSET( DEVMODEW
, dmFormName
) >= dmW
->dmSize
)
441 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
442 dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
446 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
447 FIELD_OFFSET( DEVMODEW
, dmFormName
) - FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
448 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmFormName
, -1,
449 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
451 memcpy( &dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmLogPixels
) );
455 memcpy( (char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
460 /******************************************************************
461 * verify, that the filename is a local file
464 static inline BOOL
is_local_file(LPWSTR name
)
466 return (name
[0] && (name
[1] == ':') && (name
[2] == '\\'));
469 /* ################################ */
471 static int multi_sz_lenA(const char *str
)
473 const char *ptr
= str
;
477 ptr
+= lstrlenA(ptr
) + 1;
480 return ptr
- str
+ 1;
483 /*****************************************************************************
486 * Return DWORD associated with name from hkey.
488 static DWORD
get_dword_from_reg( HKEY hkey
, const WCHAR
*name
)
490 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
493 ret
= RegQueryValueExW( hkey
, name
, 0, &type
, (LPBYTE
)&value
, &sz
);
495 if (ret
!= ERROR_SUCCESS
)
497 WARN( "Got ret = %d on name %s\n", ret
, debugstr_w(name
) );
500 if (type
!= REG_DWORD
)
502 ERR( "Got type %d\n", type
);
508 static inline DWORD
set_reg_DWORD( HKEY hkey
, const WCHAR
*keyname
, const DWORD value
)
510 return RegSetValueExW( hkey
, keyname
, 0, REG_DWORD
, (const BYTE
*)&value
, sizeof(value
) );
513 /******************************************************************
515 * Get the pointer to the opened printer referred by the handle
517 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
519 UINT_PTR idx
= (UINT_PTR
)hprn
;
520 opened_printer_t
*ret
= NULL
;
522 EnterCriticalSection(&printer_handles_cs
);
524 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
525 ret
= printer_handles
[idx
- 1];
527 LeaveCriticalSection(&printer_handles_cs
);
531 /******************************************************************
532 * get_opened_printer_name
533 * Get the pointer to the opened printer name referred by the handle
535 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
537 opened_printer_t
*printer
= get_opened_printer(hprn
);
538 if(!printer
) return NULL
;
539 return printer
->name
;
542 static DWORD
open_printer_reg_key( const WCHAR
*name
, HKEY
*key
)
548 err
= RegCreateKeyW( HKEY_LOCAL_MACHINE
, PrintersW
, &printers
);
551 err
= RegOpenKeyW( printers
, name
, key
);
552 if (err
) err
= ERROR_INVALID_PRINTER_NAME
;
553 RegCloseKey( printers
);
557 /******************************************************************
558 * WINSPOOL_GetOpenedPrinterRegKey
561 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
563 LPCWSTR name
= get_opened_printer_name(hPrinter
);
565 if(!name
) return ERROR_INVALID_HANDLE
;
566 return open_printer_reg_key( name
, phkey
);
570 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
573 /* If forcing, or no profile string entry for device yet, set the entry
575 * The always change entry if not WINEPS yet is discussable.
578 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
580 !strstr(qbuf
,"WINEPS.DRV")
582 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
585 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
586 WriteProfileStringA("windows","device",buf
);
587 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
588 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
591 HeapFree(GetProcessHeap(),0,buf
);
595 static BOOL
add_printer_driver(const WCHAR
*name
, WCHAR
*ppd
)
599 ZeroMemory(&di3
, sizeof(DRIVER_INFO_3W
));
601 di3
.pName
= (WCHAR
*)name
;
602 di3
.pEnvironment
= envname_x86W
;
603 di3
.pDriverPath
= driver_nt
;
605 di3
.pConfigFile
= driver_nt
;
606 di3
.pDefaultDataType
= rawW
;
608 if (AddPrinterDriverExW( NULL
, 3, (LPBYTE
)&di3
, APD_COPY_NEW_FILES
| APD_COPY_FROM_DIRECTORY
) ||
609 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
612 di3
.pEnvironment
= envname_win40W
;
613 di3
.pDriverPath
= driver_9x
;
614 di3
.pConfigFile
= driver_9x
;
615 if (AddPrinterDriverExW( NULL
, 3, (LPBYTE
)&di3
, APD_COPY_NEW_FILES
| APD_COPY_FROM_DIRECTORY
) ||
616 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
621 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3
.pDriverPath
), debugstr_w(di3
.pEnvironment
));
625 static inline char *expand_env_string( char *str
, DWORD type
)
627 if (type
== REG_EXPAND_SZ
)
630 DWORD needed
= ExpandEnvironmentStringsA( str
, NULL
, 0 );
631 tmp
= HeapAlloc( GetProcessHeap(), 0, needed
);
634 ExpandEnvironmentStringsA( str
, tmp
, needed
);
635 HeapFree( GetProcessHeap(), 0, str
);
642 static char *get_fallback_ppd_name( const char *printer_name
)
644 static const WCHAR ppds_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
645 'P','r','i','n','t','i','n','g','\\','P','P','D',' ','F','i','l','e','s',0};
650 if (RegOpenKeyW( HKEY_CURRENT_USER
, ppds_key
, &hkey
) == ERROR_SUCCESS
)
652 const char *value_name
= NULL
;
654 if (RegQueryValueExA( hkey
, printer_name
, 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
655 value_name
= printer_name
;
656 else if (RegQueryValueExA( hkey
, "generic", 0, NULL
, NULL
, &needed
) == ERROR_SUCCESS
)
657 value_name
= "generic";
661 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
662 if (!ret
) return NULL
;
663 RegQueryValueExA( hkey
, value_name
, 0, &type
, (BYTE
*)ret
, &needed
);
666 if (ret
) return expand_env_string( ret
, type
);
671 static BOOL
copy_file( const char *src
, const char *dst
)
673 int fds
[2] = {-1, -1}, num
;
677 fds
[0] = open( src
, O_RDONLY
);
678 fds
[1] = open( dst
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666 );
679 if (fds
[0] == -1 || fds
[1] == -1) goto fail
;
681 while ((num
= read( fds
[0], buf
, sizeof(buf
) )) != 0)
683 if (num
== -1) goto fail
;
684 if (write( fds
[1], buf
, num
) != num
) goto fail
;
689 if (fds
[1] != -1) close( fds
[1] );
690 if (fds
[0] != -1) close( fds
[0] );
694 static BOOL
get_internal_fallback_ppd( const WCHAR
*ppd
)
696 static const WCHAR typeW
[] = {'P','P','D','F','I','L','E',0};
702 HRSRC res
= FindResourceW( WINSPOOL_hInstance
, MAKEINTRESOURCEW(1), typeW
);
704 if (!res
|| !(ptr
= LoadResource( WINSPOOL_hInstance
, res
))) return FALSE
;
705 size
= SizeofResource( WINSPOOL_hInstance
, res
);
706 end
= memchr( ptr
, 0, size
); /* resource file may contain additional nulls */
707 if (end
) size
= end
- ptr
;
708 file
= CreateFileW( ppd
, GENERIC_WRITE
, FILE_SHARE_READ
, NULL
, CREATE_ALWAYS
, 0, 0 );
709 if (file
== INVALID_HANDLE_VALUE
) return FALSE
;
710 ret
= WriteFile( file
, ptr
, size
, &written
, NULL
) && written
== size
;
712 if (ret
) TRACE( "using internal fallback for %s\n", debugstr_w( ppd
));
713 else DeleteFileW( ppd
);
717 static BOOL
get_fallback_ppd( const char *printer_name
, const WCHAR
*ppd
)
719 char *dst
, *src
= get_fallback_ppd_name( printer_name
);
722 if (!src
) return get_internal_fallback_ppd( ppd
);
724 TRACE( "(%s %s) found %s\n", debugstr_a(printer_name
), debugstr_w(ppd
), debugstr_a(src
) );
726 if (!(dst
= wine_get_unix_file_name( ppd
))) goto fail
;
728 if (symlink( src
, dst
) == -1)
729 if (errno
!= ENOSYS
|| !copy_file( src
, dst
))
734 HeapFree( GetProcessHeap(), 0, dst
);
735 HeapFree( GetProcessHeap(), 0, src
);
739 static WCHAR
*get_ppd_filename( const WCHAR
*dir
, const WCHAR
*file_name
)
741 static const WCHAR dot_ppd
[] = {'.','p','p','d',0};
742 int len
= (strlenW( dir
) + strlenW( file_name
)) * sizeof(WCHAR
) + sizeof(dot_ppd
);
743 WCHAR
*ppd
= HeapAlloc( GetProcessHeap(), 0, len
);
745 if (!ppd
) return NULL
;
747 strcatW( ppd
, file_name
);
748 strcatW( ppd
, dot_ppd
);
753 static WCHAR
*get_ppd_dir( void )
755 static const WCHAR wine_ppds
[] = {'w','i','n','e','_','p','p','d','s','\\',0};
757 WCHAR
*dir
, tmp_path
[MAX_PATH
];
760 len
= GetTempPathW( sizeof(tmp_path
) / sizeof(tmp_path
[0]), tmp_path
);
761 if (!len
) return NULL
;
762 dir
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) + sizeof(wine_ppds
) ) ;
763 if (!dir
) return NULL
;
765 memcpy( dir
, tmp_path
, len
* sizeof(WCHAR
) );
766 memcpy( dir
+ len
, wine_ppds
, sizeof(wine_ppds
) );
767 res
= CreateDirectoryW( dir
, NULL
);
768 if (!res
&& GetLastError() != ERROR_ALREADY_EXISTS
)
770 HeapFree( GetProcessHeap(), 0, dir
);
773 TRACE( "ppd temporary dir: %s\n", debugstr_w(dir
) );
777 static void unlink_ppd( const WCHAR
*ppd
)
779 char *unix_name
= wine_get_unix_file_name( ppd
);
781 HeapFree( GetProcessHeap(), 0, unix_name
);
784 #ifdef SONAME_LIBCUPS
786 static void *cupshandle
;
789 DO_FUNC(cupsAddOption); \
790 DO_FUNC(cupsFreeDests); \
791 DO_FUNC(cupsFreeOptions); \
792 DO_FUNC(cupsGetDests); \
793 DO_FUNC(cupsGetOption); \
794 DO_FUNC(cupsGetPPD); \
795 DO_FUNC(cupsParseOptions); \
796 DO_FUNC(cupsPrintFile)
797 #define CUPS_OPT_FUNCS \
798 DO_FUNC(cupsGetNamedDest); \
801 #define DO_FUNC(f) static typeof(f) *p##f
804 static cups_dest_t
* (*pcupsGetNamedDest
)(http_t
*, const char *, const char *);
805 static http_status_t (*pcupsGetPPD3
)(http_t
*, const char *, time_t *, char *, size_t);
807 static http_status_t
cupsGetPPD3_wrapper( http_t
*http
, const char *name
,
808 time_t *modtime
, char *buffer
,
813 if (pcupsGetPPD3
) return pcupsGetPPD3( http
, name
, modtime
, buffer
, bufsize
);
815 if (!pcupsGetPPD
) return HTTP_NOT_FOUND
;
817 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
820 ppd
= pcupsGetPPD( name
);
822 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd
) );
824 if (!ppd
) return HTTP_NOT_FOUND
;
826 if (rename( ppd
, buffer
) == -1)
828 BOOL res
= copy_file( ppd
, buffer
);
830 if (!res
) return HTTP_NOT_FOUND
;
835 static BOOL
get_cups_ppd( const char *printer_name
, const WCHAR
*ppd
)
838 http_status_t http_status
;
839 char *unix_name
= wine_get_unix_file_name( ppd
);
841 TRACE( "(%s, %s)\n", debugstr_a(printer_name
), debugstr_w(ppd
) );
843 if (!unix_name
) return FALSE
;
845 http_status
= cupsGetPPD3_wrapper( 0, printer_name
, &modtime
,
846 unix_name
, strlen( unix_name
) + 1 );
848 if (http_status
!= HTTP_OK
) unlink( unix_name
);
849 HeapFree( GetProcessHeap(), 0, unix_name
);
851 if (http_status
== HTTP_OK
) return TRUE
;
853 TRACE( "failed to get ppd for printer %s from cups (status %d), calling fallback\n",
854 debugstr_a(printer_name
), http_status
);
855 return get_fallback_ppd( printer_name
, ppd
);
858 static WCHAR
*get_cups_option( const char *name
, int num_options
, cups_option_t
*options
)
864 value
= pcupsGetOption( name
, num_options
, options
);
865 if (!value
) return NULL
;
867 len
= MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, NULL
, 0 );
868 ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
869 if (ret
) MultiByteToWideChar( CP_UNIXCP
, 0, value
, -1, ret
, len
);
874 static cups_ptype_t
get_cups_printer_type( const cups_dest_t
*dest
)
876 WCHAR
*type
= get_cups_option( "printer-type", dest
->num_options
, dest
->options
), *end
;
877 cups_ptype_t ret
= 0;
881 ret
= (cups_ptype_t
)strtoulW( type
, &end
, 10 );
884 HeapFree( GetProcessHeap(), 0, type
);
888 static void load_cups(void)
890 cupshandle
= wine_dlopen( SONAME_LIBCUPS
, RTLD_NOW
, NULL
, 0 );
891 if (!cupshandle
) return;
893 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
896 p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); \
899 ERR("failed to load symbol %s\n", #x); \
905 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 )
910 static BOOL
CUPS_LoadPrinters(void)
913 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
916 WCHAR
*port
, *ppd_dir
= NULL
, *ppd
;
917 HKEY hkeyPrinter
, hkeyPrinters
;
918 WCHAR nameW
[MAX_PATH
];
919 HANDLE added_printer
;
920 cups_ptype_t printer_type
;
922 if (!cupshandle
) return FALSE
;
924 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
926 ERR("Can't create Printers key\n");
930 nrofdests
= pcupsGetDests(&dests
);
931 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
932 for (i
=0;i
<nrofdests
;i
++) {
933 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[i
].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
934 printer_type
= get_cups_printer_type( dests
+ i
);
936 TRACE( "Printer %d: %s. printer_type %x\n", i
, debugstr_w(nameW
), printer_type
);
938 if (printer_type
& 0x2000000 /* CUPS_PRINTER_SCANNER */)
940 TRACE( "skipping scanner-only device\n" );
944 port
= HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port
) + lstrlenW(nameW
) * sizeof(WCHAR
));
945 lstrcpyW(port
, CUPS_Port
);
946 lstrcatW(port
, nameW
);
948 if(RegOpenKeyW(hkeyPrinters
, nameW
, &hkeyPrinter
) == ERROR_SUCCESS
) {
949 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
950 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
952 TRACE("Printer already exists\n");
953 /* overwrite old LPR:* port */
954 RegSetValueExW(hkeyPrinter
, PortW
, 0, REG_SZ
, (LPBYTE
)port
, (lstrlenW(port
) + 1) * sizeof(WCHAR
));
955 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
956 /* flag that the PPD file should be checked for an update */
957 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
958 RegCloseKey(hkeyPrinter
);
960 BOOL added_driver
= FALSE
;
962 if (!ppd_dir
) ppd_dir
= get_ppd_dir();
963 ppd
= get_ppd_filename( ppd_dir
, nameW
);
964 if (get_cups_ppd( dests
[i
].name
, ppd
))
966 added_driver
= add_printer_driver( nameW
, ppd
);
969 HeapFree( GetProcessHeap(), 0, ppd
);
972 HeapFree( GetProcessHeap(), 0, port
);
976 memset(&pi2
, 0, sizeof(PRINTER_INFO_2W
));
977 pi2
.pPrinterName
= nameW
;
978 pi2
.pDatatype
= rawW
;
979 pi2
.pPrintProcessor
= WinPrintW
;
980 pi2
.pDriverName
= nameW
;
981 pi2
.pComment
= get_cups_option( "printer-info", dests
[i
].num_options
, dests
[i
].options
);
982 pi2
.pLocation
= get_cups_option( "printer-location", dests
[i
].num_options
, dests
[i
].options
);
983 pi2
.pPortName
= port
;
984 pi2
.pParameters
= emptyStringW
;
985 pi2
.pShareName
= emptyStringW
;
986 pi2
.pSepFile
= emptyStringW
;
988 added_printer
= AddPrinterW( NULL
, 2, (LPBYTE
)&pi2
);
989 if (added_printer
) ClosePrinter( added_printer
);
990 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
991 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW
), GetLastError() );
993 HeapFree( GetProcessHeap(), 0, pi2
.pComment
);
994 HeapFree( GetProcessHeap(), 0, pi2
.pLocation
);
996 HeapFree( GetProcessHeap(), 0, port
);
999 if (dests
[i
].is_default
) {
1000 SetDefaultPrinterW(nameW
);
1007 RemoveDirectoryW( ppd_dir
);
1008 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1011 if (hadprinter
&& !haddefault
) {
1012 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[0].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
1013 SetDefaultPrinterW(nameW
);
1015 pcupsFreeDests(nrofdests
, dests
);
1016 RegCloseKey(hkeyPrinters
);
1022 static char *get_queue_name( HANDLE printer
, BOOL
*cups
)
1024 WCHAR
*port
, *name
= NULL
;
1025 DWORD err
, needed
, type
;
1031 err
= WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
);
1032 if (err
) return NULL
;
1033 err
= RegQueryValueExW( key
, PortW
, 0, &type
, NULL
, &needed
);
1035 port
= HeapAlloc( GetProcessHeap(), 0, needed
);
1036 if (!port
) goto end
;
1037 RegQueryValueExW( key
, PortW
, 0, &type
, (BYTE
*)port
, &needed
);
1039 if (!strncmpW( port
, CUPS_Port
, sizeof(CUPS_Port
) / sizeof(WCHAR
) -1 ))
1041 name
= port
+ sizeof(CUPS_Port
) / sizeof(WCHAR
) - 1;
1044 else if (!strncmpW( port
, LPR_Port
, sizeof(LPR_Port
) / sizeof(WCHAR
) -1 ))
1045 name
= port
+ sizeof(LPR_Port
) / sizeof(WCHAR
) - 1;
1048 needed
= WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, NULL
, 0, NULL
, NULL
);
1049 ret
= HeapAlloc( GetProcessHeap(), 0, needed
);
1050 if(ret
) WideCharToMultiByte( CP_UNIXCP
, 0, name
, -1, ret
, needed
, NULL
, NULL
);
1052 HeapFree( GetProcessHeap(), 0, port
);
1059 static void set_ppd_overrides( HANDLE printer
)
1063 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
1065 PMPrintSession session
= NULL
;
1066 PMPageFormat format
= NULL
;
1068 CFStringRef paper_name
;
1071 status
= PMCreateSession( &session
);
1072 if (status
) goto end
;
1074 status
= PMCreatePageFormat( &format
);
1075 if (status
) goto end
;
1077 status
= PMSessionDefaultPageFormat( session
, format
);
1078 if (status
) goto end
;
1080 status
= PMGetPageFormatPaper( format
, &paper
);
1081 if (status
) goto end
;
1083 status
= PMPaperGetPPDPaperName( paper
, &paper_name
);
1084 if (status
) goto end
;
1087 range
.length
= CFStringGetLength( paper_name
);
1088 size
= (range
.length
+ 1) * sizeof(WCHAR
);
1090 wstr
= HeapAlloc( GetProcessHeap(), 0, size
);
1091 CFStringGetCharacters( paper_name
, range
, (UniChar
*)wstr
);
1092 wstr
[range
.length
] = 0;
1095 if (format
) PMRelease( format
);
1096 if (session
) PMRelease( session
);
1099 SetPrinterDataExW( printer
, PPD_Overrides
, DefaultPageSize
, REG_SZ
, (BYTE
*)wstr
, size
);
1100 HeapFree( GetProcessHeap(), 0, wstr
);
1103 static BOOL
update_driver( HANDLE printer
)
1106 const WCHAR
*name
= get_opened_printer_name( printer
);
1107 WCHAR
*ppd_dir
, *ppd
;
1110 if (!name
) return FALSE
;
1111 queue_name
= get_queue_name( printer
, &is_cups
);
1112 if (!queue_name
) return FALSE
;
1114 ppd_dir
= get_ppd_dir();
1115 ppd
= get_ppd_filename( ppd_dir
, name
);
1117 #ifdef SONAME_LIBCUPS
1119 ret
= get_cups_ppd( queue_name
, ppd
);
1122 ret
= get_fallback_ppd( queue_name
, ppd
);
1126 TRACE( "updating driver %s\n", debugstr_w( name
) );
1127 ret
= add_printer_driver( name
, ppd
);
1130 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1131 HeapFree( GetProcessHeap(), 0, ppd
);
1132 HeapFree( GetProcessHeap(), 0, queue_name
);
1134 set_ppd_overrides( printer
);
1136 /* call into the driver to update the devmode */
1137 DocumentPropertiesW( 0, printer
, NULL
, NULL
, NULL
, 0 );
1142 static BOOL
PRINTCAP_ParseEntry( const char *pent
, BOOL isfirst
)
1144 PRINTER_INFO_2A pinfo2a
;
1147 char *e
,*s
,*name
,*prettyname
,*devname
;
1148 BOOL ret
= FALSE
, set_default
= FALSE
;
1149 char *port
= NULL
, *env_default
;
1150 HKEY hkeyPrinter
, hkeyPrinters
= NULL
;
1151 WCHAR devnameW
[MAX_PATH
], *ppd_dir
= NULL
, *ppd
;
1152 HANDLE added_printer
;
1154 while (isspace(*pent
)) pent
++;
1155 r
= strchr(pent
,':');
1157 name_len
= r
- pent
;
1159 name_len
= strlen(pent
);
1160 name
= HeapAlloc(GetProcessHeap(), 0, name_len
+ 1);
1161 memcpy(name
, pent
, name_len
);
1162 name
[name_len
] = '\0';
1168 TRACE("name=%s entry=%s\n",name
, pent
);
1170 if(ispunct(*name
)) { /* a tc entry, not a real printer */
1171 TRACE("skipping tc entry\n");
1175 if(strstr(pent
,":server")) { /* server only version so skip */
1176 TRACE("skipping server entry\n");
1180 /* Determine whether this is a postscript printer. */
1183 env_default
= getenv("PRINTER");
1185 /* Get longest name, usually the one at the right for later display. */
1186 while((s
=strchr(prettyname
,'|'))) {
1189 while(isspace(*--e
)) *e
= '\0';
1190 TRACE("\t%s\n", debugstr_a(prettyname
));
1191 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
1192 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
1195 e
= prettyname
+ strlen(prettyname
);
1196 while(isspace(*--e
)) *e
= '\0';
1197 TRACE("\t%s\n", debugstr_a(prettyname
));
1198 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
1200 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
1201 * if it is too long, we use it as comment below. */
1202 devname
= prettyname
;
1203 if (strlen(devname
)>=CCHDEVICENAME
-1)
1205 if (strlen(devname
)>=CCHDEVICENAME
-1) {
1210 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
1211 sprintf(port
,"LPR:%s",name
);
1213 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
1215 ERR("Can't create Printers key\n");
1220 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, sizeof(devnameW
) / sizeof(WCHAR
));
1222 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
1223 DWORD status
= get_dword_from_reg( hkeyPrinter
, StatusW
);
1224 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
1226 TRACE("Printer already exists\n");
1227 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
1228 /* flag that the PPD file should be checked for an update */
1229 set_reg_DWORD( hkeyPrinter
, StatusW
, status
| PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
1230 RegCloseKey(hkeyPrinter
);
1232 static CHAR data_type
[] = "RAW",
1233 print_proc
[] = "WinPrint",
1234 comment
[] = "WINEPS Printer using LPR",
1235 params
[] = "<parameters?>",
1236 share_name
[] = "<share name?>",
1237 sep_file
[] = "<sep file?>";
1238 BOOL added_driver
= FALSE
;
1240 if (!ppd_dir
) ppd_dir
= get_ppd_dir();
1241 ppd
= get_ppd_filename( ppd_dir
, devnameW
);
1242 if (get_fallback_ppd( devname
, ppd
))
1244 added_driver
= add_printer_driver( devnameW
, ppd
);
1247 HeapFree( GetProcessHeap(), 0, ppd
);
1248 if (!added_driver
) goto end
;
1250 memset(&pinfo2a
,0,sizeof(pinfo2a
));
1251 pinfo2a
.pPrinterName
= devname
;
1252 pinfo2a
.pDatatype
= data_type
;
1253 pinfo2a
.pPrintProcessor
= print_proc
;
1254 pinfo2a
.pDriverName
= devname
;
1255 pinfo2a
.pComment
= comment
;
1256 pinfo2a
.pLocation
= prettyname
;
1257 pinfo2a
.pPortName
= port
;
1258 pinfo2a
.pParameters
= params
;
1259 pinfo2a
.pShareName
= share_name
;
1260 pinfo2a
.pSepFile
= sep_file
;
1262 added_printer
= AddPrinterA( NULL
, 2, (LPBYTE
)&pinfo2a
);
1263 if (added_printer
) ClosePrinter( added_printer
);
1264 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
1265 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name
), GetLastError() );
1268 if (isfirst
|| set_default
)
1269 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
1272 if (hkeyPrinters
) RegCloseKey( hkeyPrinters
);
1275 RemoveDirectoryW( ppd_dir
);
1276 HeapFree( GetProcessHeap(), 0, ppd_dir
);
1278 HeapFree(GetProcessHeap(), 0, port
);
1279 HeapFree(GetProcessHeap(), 0, name
);
1284 PRINTCAP_LoadPrinters(void) {
1285 BOOL hadprinter
= FALSE
;
1289 BOOL had_bash
= FALSE
;
1291 f
= fopen("/etc/printcap","r");
1295 while(fgets(buf
,sizeof(buf
),f
)) {
1298 end
=strchr(buf
,'\n');
1302 while(isspace(*start
)) start
++;
1303 if(*start
== '#' || *start
== '\0')
1306 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
1307 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1308 HeapFree(GetProcessHeap(),0,pent
);
1312 if (end
&& *--end
== '\\') {
1319 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
1322 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
1328 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
1329 HeapFree(GetProcessHeap(),0,pent
);
1335 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
1338 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
1339 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
1341 return ERROR_FILE_NOT_FOUND
;
1344 static inline DWORD
set_reg_devmode( HKEY key
, const WCHAR
*name
, const DEVMODEW
*dm
)
1346 DEVMODEA
*dmA
= DEVMODEdupWtoA( dm
);
1347 DWORD ret
= ERROR_FILE_NOT_FOUND
;
1349 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1350 and we support these drivers. NT writes DEVMODEW so somehow
1351 we'll need to distinguish between these when we support NT
1356 ret
= RegSetValueExW( key
, name
, 0, REG_BINARY
,
1357 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1358 HeapFree( GetProcessHeap(), 0, dmA
);
1364 /******************************************************************
1365 * get_servername_from_name (internal)
1367 * for an external server, a copy of the serverpart from the full name is returned
1370 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1374 WCHAR buffer
[MAX_PATH
];
1377 if (name
== NULL
) return NULL
;
1378 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1380 server
= strdupW(&name
[2]); /* skip over both backslash */
1381 if (server
== NULL
) return NULL
;
1383 /* strip '\' and the printername */
1384 ptr
= strchrW(server
, '\\');
1385 if (ptr
) ptr
[0] = '\0';
1387 TRACE("found %s\n", debugstr_w(server
));
1389 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1390 if (GetComputerNameW(buffer
, &len
)) {
1391 if (lstrcmpW(buffer
, server
) == 0) {
1392 /* The requested Servername is our computername */
1393 HeapFree(GetProcessHeap(), 0, server
);
1400 /******************************************************************
1401 * get_basename_from_name (internal)
1403 * skip over the serverpart from the full name
1406 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1408 if (name
== NULL
) return NULL
;
1409 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1410 /* skip over the servername and search for the following '\' */
1411 name
= strchrW(&name
[2], '\\');
1412 if ((name
) && (name
[1])) {
1413 /* found a separator ('\') followed by a name:
1414 skip over the separator and return the rest */
1419 /* no basename present (we found only a servername) */
1426 static void free_printer_entry( opened_printer_t
*printer
)
1428 /* the queue is shared, so don't free that here */
1429 HeapFree( GetProcessHeap(), 0, printer
->printername
);
1430 HeapFree( GetProcessHeap(), 0, printer
->name
);
1431 HeapFree( GetProcessHeap(), 0, printer
->devmode
);
1432 HeapFree( GetProcessHeap(), 0, printer
);
1435 /******************************************************************
1436 * get_opened_printer_entry
1437 * Get the first place empty in the opened printer table
1440 * - pDefault is ignored
1442 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1444 UINT_PTR handle
= nb_printer_handles
, i
;
1445 jobqueue_t
*queue
= NULL
;
1446 opened_printer_t
*printer
= NULL
;
1448 LPCWSTR printername
;
1450 if ((backend
== NULL
) && !load_backend()) return NULL
;
1452 servername
= get_servername_from_name(name
);
1454 FIXME("server %s not supported\n", debugstr_w(servername
));
1455 HeapFree(GetProcessHeap(), 0, servername
);
1456 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1460 printername
= get_basename_from_name(name
);
1461 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1463 /* an empty printername is invalid */
1464 if (printername
&& (!printername
[0])) {
1465 SetLastError(ERROR_INVALID_PARAMETER
);
1469 EnterCriticalSection(&printer_handles_cs
);
1471 for (i
= 0; i
< nb_printer_handles
; i
++)
1473 if (!printer_handles
[i
])
1475 if(handle
== nb_printer_handles
)
1480 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1481 queue
= printer_handles
[i
]->queue
;
1485 if (handle
>= nb_printer_handles
)
1487 opened_printer_t
**new_array
;
1488 if (printer_handles
)
1489 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1490 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1492 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1493 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1500 printer_handles
= new_array
;
1501 nb_printer_handles
+= 16;
1504 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1510 /* get a printer handle from the backend */
1511 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
1516 /* clone the base name. This is NULL for the printserver */
1517 printer
->printername
= strdupW(printername
);
1519 /* clone the full name */
1520 printer
->name
= strdupW(name
);
1521 if (name
&& (!printer
->name
)) {
1526 if (pDefault
&& pDefault
->pDevMode
)
1527 printer
->devmode
= dup_devmode( pDefault
->pDevMode
);
1530 printer
->queue
= queue
;
1533 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1534 if (!printer
->queue
) {
1538 list_init(&printer
->queue
->jobs
);
1539 printer
->queue
->ref
= 0;
1541 InterlockedIncrement(&printer
->queue
->ref
);
1543 printer_handles
[handle
] = printer
;
1546 LeaveCriticalSection(&printer_handles_cs
);
1547 if (!handle
&& printer
) {
1548 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1549 free_printer_entry( printer
);
1552 return (HANDLE
)handle
;
1555 static void old_printer_check( BOOL delete_phase
)
1557 PRINTER_INFO_5W
* pi
;
1558 DWORD needed
, type
, num
, delete, i
, size
;
1559 const DWORD one
= 1;
1563 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1564 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return;
1566 pi
= HeapAlloc( GetProcessHeap(), 0, needed
);
1567 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
);
1568 for (i
= 0; i
< num
; i
++)
1570 if (strncmpW( pi
[i
].pPortName
, CUPS_Port
, strlenW(CUPS_Port
) ) &&
1571 strncmpW( pi
[i
].pPortName
, LPR_Port
, strlenW(LPR_Port
) ))
1574 if (open_printer_reg_key( pi
[i
].pPrinterName
, &key
)) continue;
1578 RegSetValueExW( key
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&one
, sizeof(one
) );
1584 size
= sizeof( delete );
1585 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&delete, &size
);
1589 TRACE( "Deleting old printer %s\n", debugstr_w(pi
[i
].pPrinterName
) );
1590 if (OpenPrinterW( pi
[i
].pPrinterName
, &hprn
, NULL
))
1592 DeletePrinter( hprn
);
1593 ClosePrinter( hprn
);
1595 DeletePrinterDriverExW( NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0 );
1599 HeapFree(GetProcessHeap(), 0, pi
);
1602 static const WCHAR winspool_mutex_name
[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1603 'M','U','T','E','X','_','_','\0'};
1604 static HANDLE init_mutex
;
1606 void WINSPOOL_LoadSystemPrinters(void)
1608 HKEY hkey
, hkeyPrinters
;
1609 DWORD needed
, num
, i
;
1610 WCHAR PrinterName
[256];
1613 #ifdef SONAME_LIBCUPS
1617 /* FIXME: The init code should be moved to spoolsv.exe */
1618 init_mutex
= CreateMutexW( NULL
, TRUE
, winspool_mutex_name
);
1621 ERR( "Failed to create mutex\n" );
1624 if (GetLastError() == ERROR_ALREADY_EXISTS
)
1626 WaitForSingleObject( init_mutex
, INFINITE
);
1627 ReleaseMutex( init_mutex
);
1628 TRACE( "Init already done\n" );
1632 /* This ensures that all printer entries have a valid Name value. If causes
1633 problems later if they don't. If one is found to be missed we create one
1634 and set it equal to the name of the key */
1635 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1636 if(RegQueryInfoKeyW(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1637 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1638 for(i
= 0; i
< num
; i
++) {
1639 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1640 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1641 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1642 set_reg_szW(hkey
, NameW
, PrinterName
);
1649 RegCloseKey(hkeyPrinters
);
1652 old_printer_check( FALSE
);
1654 #ifdef SONAME_LIBCUPS
1655 done
= CUPS_LoadPrinters();
1658 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1659 PRINTCAP_LoadPrinters();
1661 old_printer_check( TRUE
);
1663 ReleaseMutex( init_mutex
);
1667 /******************************************************************
1670 * Get the pointer to the specified job.
1671 * Should hold the printer_handles_cs before calling.
1673 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1675 opened_printer_t
*printer
= get_opened_printer(hprn
);
1678 if(!printer
) return NULL
;
1679 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1681 if(job
->job_id
== JobId
)
1687 /***********************************************************
1690 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1693 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1696 Formname
= (dmA
->dmSize
> off_formname
);
1697 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1698 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1699 dmW
->dmDeviceName
, CCHDEVICENAME
);
1701 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1702 dmA
->dmSize
- CCHDEVICENAME
);
1704 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1705 off_formname
- CCHDEVICENAME
);
1706 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1707 dmW
->dmFormName
, CCHFORMNAME
);
1708 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1709 (off_formname
+ CCHFORMNAME
));
1712 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1713 dmA
->dmDriverExtra
);
1717 /******************************************************************
1718 * convert_printerinfo_W_to_A [internal]
1721 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1722 DWORD level
, DWORD outlen
, DWORD numentries
)
1728 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1730 len
= pi_sizeof
[level
] * numentries
;
1731 ptr
= (LPSTR
) out
+ len
;
1734 /* copy the numbers of all PRINTER_INFO_* first */
1735 memcpy(out
, pPrintersW
, len
);
1737 while (id
< numentries
) {
1741 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1742 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1744 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1745 if (piW
->pDescription
) {
1746 piA
->pDescription
= ptr
;
1747 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1748 ptr
, outlen
, NULL
, NULL
);
1754 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1755 ptr
, outlen
, NULL
, NULL
);
1759 if (piW
->pComment
) {
1760 piA
->pComment
= ptr
;
1761 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1762 ptr
, outlen
, NULL
, NULL
);
1771 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1772 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1775 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1776 if (piW
->pServerName
) {
1777 piA
->pServerName
= ptr
;
1778 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1779 ptr
, outlen
, NULL
, NULL
);
1783 if (piW
->pPrinterName
) {
1784 piA
->pPrinterName
= ptr
;
1785 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1786 ptr
, outlen
, NULL
, NULL
);
1790 if (piW
->pShareName
) {
1791 piA
->pShareName
= ptr
;
1792 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1793 ptr
, outlen
, NULL
, NULL
);
1797 if (piW
->pPortName
) {
1798 piA
->pPortName
= ptr
;
1799 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1800 ptr
, outlen
, NULL
, NULL
);
1804 if (piW
->pDriverName
) {
1805 piA
->pDriverName
= ptr
;
1806 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1807 ptr
, outlen
, NULL
, NULL
);
1811 if (piW
->pComment
) {
1812 piA
->pComment
= ptr
;
1813 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1814 ptr
, outlen
, NULL
, NULL
);
1818 if (piW
->pLocation
) {
1819 piA
->pLocation
= ptr
;
1820 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1821 ptr
, outlen
, NULL
, NULL
);
1826 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1828 /* align DEVMODEA to a DWORD boundary */
1829 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1833 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1834 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1835 memcpy(ptr
, dmA
, len
);
1836 HeapFree(GetProcessHeap(), 0, dmA
);
1842 if (piW
->pSepFile
) {
1843 piA
->pSepFile
= ptr
;
1844 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1845 ptr
, outlen
, NULL
, NULL
);
1849 if (piW
->pPrintProcessor
) {
1850 piA
->pPrintProcessor
= ptr
;
1851 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1852 ptr
, outlen
, NULL
, NULL
);
1856 if (piW
->pDatatype
) {
1857 piA
->pDatatype
= ptr
;
1858 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1859 ptr
, outlen
, NULL
, NULL
);
1863 if (piW
->pParameters
) {
1864 piA
->pParameters
= ptr
;
1865 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1866 ptr
, outlen
, NULL
, NULL
);
1870 if (piW
->pSecurityDescriptor
) {
1871 piA
->pSecurityDescriptor
= NULL
;
1872 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1879 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1880 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1882 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1884 if (piW
->pPrinterName
) {
1885 piA
->pPrinterName
= ptr
;
1886 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1887 ptr
, outlen
, NULL
, NULL
);
1891 if (piW
->pServerName
) {
1892 piA
->pServerName
= ptr
;
1893 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1894 ptr
, outlen
, NULL
, NULL
);
1903 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1904 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1906 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1908 if (piW
->pPrinterName
) {
1909 piA
->pPrinterName
= ptr
;
1910 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1911 ptr
, outlen
, NULL
, NULL
);
1915 if (piW
->pPortName
) {
1916 piA
->pPortName
= ptr
;
1917 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1918 ptr
, outlen
, NULL
, NULL
);
1925 case 6: /* 6A and 6W are the same structure */
1930 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1931 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1933 TRACE("(%u) #%u\n", level
, id
);
1934 if (piW
->pszObjectGUID
) {
1935 piA
->pszObjectGUID
= ptr
;
1936 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1937 ptr
, outlen
, NULL
, NULL
);
1947 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1948 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1951 TRACE("(%u) #%u\n", level
, id
);
1952 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1954 /* align DEVMODEA to a DWORD boundary */
1955 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1959 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1960 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1961 memcpy(ptr
, dmA
, len
);
1962 HeapFree(GetProcessHeap(), 0, dmA
);
1972 FIXME("for level %u\n", level
);
1974 pPrintersW
+= pi_sizeof
[level
];
1975 out
+= pi_sizeof
[level
];
1980 /******************************************************************
1981 * convert_driverinfo_W_to_A [internal]
1984 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1985 DWORD level
, DWORD outlen
, DWORD numentries
)
1991 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1993 len
= di_sizeof
[level
] * numentries
;
1994 ptr
= (LPSTR
) out
+ len
;
1997 /* copy the numbers of all PRINTER_INFO_* first */
1998 memcpy(out
, pDriversW
, len
);
2000 #define COPY_STRING(fld) \
2003 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
2004 ptr += len; outlen -= len;\
2006 #define COPY_MULTIZ_STRING(fld) \
2007 { LPWSTR p = diW->fld; if (p){ \
2010 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
2011 ptr += len; outlen -= len; p += len;\
2013 while(len > 1 && outlen > 0); \
2016 while (id
< numentries
)
2022 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
2023 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
2025 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2032 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
2033 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
2035 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2038 COPY_STRING(pEnvironment
);
2039 COPY_STRING(pDriverPath
);
2040 COPY_STRING(pDataFile
);
2041 COPY_STRING(pConfigFile
);
2046 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
2047 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
2049 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2052 COPY_STRING(pEnvironment
);
2053 COPY_STRING(pDriverPath
);
2054 COPY_STRING(pDataFile
);
2055 COPY_STRING(pConfigFile
);
2056 COPY_STRING(pHelpFile
);
2057 COPY_MULTIZ_STRING(pDependentFiles
);
2058 COPY_STRING(pMonitorName
);
2059 COPY_STRING(pDefaultDataType
);
2064 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
2065 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
2067 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2070 COPY_STRING(pEnvironment
);
2071 COPY_STRING(pDriverPath
);
2072 COPY_STRING(pDataFile
);
2073 COPY_STRING(pConfigFile
);
2074 COPY_STRING(pHelpFile
);
2075 COPY_MULTIZ_STRING(pDependentFiles
);
2076 COPY_STRING(pMonitorName
);
2077 COPY_STRING(pDefaultDataType
);
2078 COPY_MULTIZ_STRING(pszzPreviousNames
);
2083 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
2084 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
2086 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2089 COPY_STRING(pEnvironment
);
2090 COPY_STRING(pDriverPath
);
2091 COPY_STRING(pDataFile
);
2092 COPY_STRING(pConfigFile
);
2097 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
2098 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
2100 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2103 COPY_STRING(pEnvironment
);
2104 COPY_STRING(pDriverPath
);
2105 COPY_STRING(pDataFile
);
2106 COPY_STRING(pConfigFile
);
2107 COPY_STRING(pHelpFile
);
2108 COPY_MULTIZ_STRING(pDependentFiles
);
2109 COPY_STRING(pMonitorName
);
2110 COPY_STRING(pDefaultDataType
);
2111 COPY_MULTIZ_STRING(pszzPreviousNames
);
2112 COPY_STRING(pszMfgName
);
2113 COPY_STRING(pszOEMUrl
);
2114 COPY_STRING(pszHardwareID
);
2115 COPY_STRING(pszProvider
);
2120 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
2121 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
2123 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
2126 COPY_STRING(pEnvironment
);
2127 COPY_STRING(pDriverPath
);
2128 COPY_STRING(pDataFile
);
2129 COPY_STRING(pConfigFile
);
2130 COPY_STRING(pHelpFile
);
2131 COPY_MULTIZ_STRING(pDependentFiles
);
2132 COPY_STRING(pMonitorName
);
2133 COPY_STRING(pDefaultDataType
);
2134 COPY_MULTIZ_STRING(pszzPreviousNames
);
2135 COPY_STRING(pszMfgName
);
2136 COPY_STRING(pszOEMUrl
);
2137 COPY_STRING(pszHardwareID
);
2138 COPY_STRING(pszProvider
);
2139 COPY_STRING(pszPrintProcessor
);
2140 COPY_STRING(pszVendorSetup
);
2141 COPY_MULTIZ_STRING(pszzColorProfiles
);
2142 COPY_STRING(pszInfPath
);
2143 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
2149 FIXME("for level %u\n", level
);
2152 pDriversW
+= di_sizeof
[level
];
2153 out
+= di_sizeof
[level
];
2158 #undef COPY_MULTIZ_STRING
2162 /***********************************************************
2165 static void *printer_info_AtoW( const void *data
, DWORD level
)
2168 UNICODE_STRING usBuffer
;
2170 if (!data
) return NULL
;
2172 if (level
< 1 || level
> 9) return NULL
;
2174 ret
= HeapAlloc( GetProcessHeap(), 0, pi_sizeof
[level
] );
2175 if (!ret
) return NULL
;
2177 memcpy( ret
, data
, pi_sizeof
[level
] ); /* copy everything first */
2183 const PRINTER_INFO_2A
*piA
= (const PRINTER_INFO_2A
*)data
;
2184 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)ret
;
2186 piW
->pServerName
= asciitounicode( &usBuffer
, piA
->pServerName
);
2187 piW
->pPrinterName
= asciitounicode( &usBuffer
, piA
->pPrinterName
);
2188 piW
->pShareName
= asciitounicode( &usBuffer
, piA
->pShareName
);
2189 piW
->pPortName
= asciitounicode( &usBuffer
, piA
->pPortName
);
2190 piW
->pDriverName
= asciitounicode( &usBuffer
, piA
->pDriverName
);
2191 piW
->pComment
= asciitounicode( &usBuffer
, piA
->pComment
);
2192 piW
->pLocation
= asciitounicode( &usBuffer
, piA
->pLocation
);
2193 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2194 piW
->pSepFile
= asciitounicode( &usBuffer
, piA
->pSepFile
);
2195 piW
->pPrintProcessor
= asciitounicode( &usBuffer
, piA
->pPrintProcessor
);
2196 piW
->pDatatype
= asciitounicode( &usBuffer
, piA
->pDatatype
);
2197 piW
->pParameters
= asciitounicode( &usBuffer
, piA
->pParameters
);
2204 const PRINTER_INFO_9A
*piA
= (const PRINTER_INFO_9A
*)data
;
2205 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)ret
;
2207 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
2212 FIXME( "Unhandled level %d\n", level
);
2213 HeapFree( GetProcessHeap(), 0, ret
);
2220 /***********************************************************
2223 static void free_printer_info( void *data
, DWORD level
)
2231 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)data
;
2233 HeapFree( GetProcessHeap(), 0, piW
->pServerName
);
2234 HeapFree( GetProcessHeap(), 0, piW
->pPrinterName
);
2235 HeapFree( GetProcessHeap(), 0, piW
->pShareName
);
2236 HeapFree( GetProcessHeap(), 0, piW
->pPortName
);
2237 HeapFree( GetProcessHeap(), 0, piW
->pDriverName
);
2238 HeapFree( GetProcessHeap(), 0, piW
->pComment
);
2239 HeapFree( GetProcessHeap(), 0, piW
->pLocation
);
2240 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2241 HeapFree( GetProcessHeap(), 0, piW
->pSepFile
);
2242 HeapFree( GetProcessHeap(), 0, piW
->pPrintProcessor
);
2243 HeapFree( GetProcessHeap(), 0, piW
->pDatatype
);
2244 HeapFree( GetProcessHeap(), 0, piW
->pParameters
);
2251 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)data
;
2253 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
2258 FIXME( "Unhandled level %d\n", level
);
2261 HeapFree( GetProcessHeap(), 0, data
);
2265 /******************************************************************
2266 * DeviceCapabilities [WINSPOOL.@]
2267 * DeviceCapabilitiesA [WINSPOOL.@]
2270 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
2271 LPSTR pOutput
, LPDEVMODEA lpdm
)
2275 TRACE("%s,%s,%u,%p,%p\n", debugstr_a(pDevice
), debugstr_a(pPort
), cap
, pOutput
, lpdm
);
2277 if (!GDI_CallDeviceCapabilities16
)
2279 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2281 if (!GDI_CallDeviceCapabilities16
) return -1;
2283 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
2285 /* If DC_PAPERSIZE map POINT16s to POINTs */
2286 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
2287 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
2288 POINT
*pt
= (POINT
*)pOutput
;
2290 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
2291 for(i
= 0; i
< ret
; i
++, pt
++)
2296 HeapFree( GetProcessHeap(), 0, tmp
);
2302 /*****************************************************************************
2303 * DeviceCapabilitiesW [WINSPOOL.@]
2305 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2308 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
2309 WORD fwCapability
, LPWSTR pOutput
,
2310 const DEVMODEW
*pDevMode
)
2312 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
2313 LPSTR pDeviceA
= strdupWtoA(pDevice
);
2314 LPSTR pPortA
= strdupWtoA(pPort
);
2317 TRACE("%s,%s,%u,%p,%p\n", debugstr_w(pDevice
), debugstr_w(pPort
), fwCapability
, pOutput
, pDevMode
);
2319 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
2320 fwCapability
== DC_FILEDEPENDENCIES
||
2321 fwCapability
== DC_PAPERNAMES
)) {
2322 /* These need A -> W translation */
2325 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
2329 switch(fwCapability
) {
2334 case DC_FILEDEPENDENCIES
:
2338 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
2339 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
2341 for(i
= 0; i
< ret
; i
++)
2342 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
2343 pOutput
+ (i
* size
), size
);
2344 HeapFree(GetProcessHeap(), 0, pOutputA
);
2346 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
2347 (LPSTR
)pOutput
, dmA
);
2349 HeapFree(GetProcessHeap(),0,pPortA
);
2350 HeapFree(GetProcessHeap(),0,pDeviceA
);
2351 HeapFree(GetProcessHeap(),0,dmA
);
2355 /******************************************************************
2356 * DocumentPropertiesA [WINSPOOL.@]
2358 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2360 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
2361 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
2362 LPDEVMODEA pDevModeInput
,DWORD fMode
)
2364 LPSTR lpName
= pDeviceName
;
2365 static CHAR port
[] = "LPT1:";
2368 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2369 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
2372 if(!pDeviceName
|| !*pDeviceName
) {
2373 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2375 ERR("no name from hPrinter?\n");
2376 SetLastError(ERROR_INVALID_HANDLE
);
2379 lpName
= strdupWtoA(lpNameW
);
2382 if (!GDI_CallExtDeviceMode16
)
2384 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2386 if (!GDI_CallExtDeviceMode16
) {
2387 ERR("No CallExtDeviceMode16?\n");
2391 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
2392 pDevModeInput
, NULL
, fMode
);
2395 HeapFree(GetProcessHeap(),0,lpName
);
2400 /*****************************************************************************
2401 * DocumentPropertiesW (WINSPOOL.@)
2403 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2405 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
2407 LPDEVMODEW pDevModeOutput
,
2408 LPDEVMODEW pDevModeInput
, DWORD fMode
)
2411 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
2412 LPDEVMODEA pDevModeInputA
;
2413 LPDEVMODEA pDevModeOutputA
= NULL
;
2416 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2417 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
2419 if(pDevModeOutput
) {
2420 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
2421 if(ret
< 0) return ret
;
2422 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
2424 pDevModeInputA
= (fMode
& DM_IN_BUFFER
) ? DEVMODEdupWtoA(pDevModeInput
) : NULL
;
2425 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
2426 pDevModeInputA
, fMode
);
2427 if(pDevModeOutput
) {
2428 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
2429 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
2431 if(fMode
== 0 && ret
> 0)
2432 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2433 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
2434 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
2438 /*****************************************************************************
2439 * IsValidDevmodeA [WINSPOOL.@]
2441 * Validate a DEVMODE structure and fix errors if possible.
2444 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA
*pDevMode
, SIZE_T size
)
2446 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2454 /*****************************************************************************
2455 * IsValidDevmodeW [WINSPOOL.@]
2457 * Validate a DEVMODE structure and fix errors if possible.
2460 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW
*pDevMode
, SIZE_T size
)
2462 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
2470 /******************************************************************
2471 * OpenPrinterA [WINSPOOL.@]
2476 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
2477 LPPRINTER_DEFAULTSA pDefault
)
2479 UNICODE_STRING lpPrinterNameW
;
2480 UNICODE_STRING usBuffer
;
2481 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
2482 PWSTR pwstrPrinterNameW
;
2485 TRACE("%s,%p,%p\n", debugstr_a(lpPrinterName
), phPrinter
, pDefault
);
2487 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
2490 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
2491 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
2492 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
2493 pDefaultW
= &DefaultW
;
2495 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
2497 RtlFreeUnicodeString(&usBuffer
);
2498 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
2500 RtlFreeUnicodeString(&lpPrinterNameW
);
2504 /******************************************************************
2505 * OpenPrinterW [WINSPOOL.@]
2507 * Open a Printer / Printserver or a Printer-Object
2510 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2511 * phPrinter [O] The resulting Handle is stored here
2512 * pDefault [I] PTR to Default Printer Settings or NULL
2519 * lpPrinterName is one of:
2520 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2521 *| Printer: "PrinterName"
2522 *| Printer-Object: "PrinterName,Job xxx"
2523 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2524 *| XcvPort: "Servername,XcvPort PortName"
2527 *| Printer-Object not supported
2528 *| pDefaults is ignored
2531 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
);
2548 DWORD deleting
= 0, size
= sizeof( deleting
), type
;
2550 WINSPOOL_GetOpenedPrinterRegKey( *phPrinter
, &key
);
2551 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&deleting
, &size
);
2552 WaitForSingleObject( init_mutex
, INFINITE
);
2553 status
= get_dword_from_reg( key
, StatusW
);
2554 set_reg_DWORD( key
, StatusW
, status
& ~PRINTER_STATUS_DRIVER_UPDATE_NEEDED
);
2555 ReleaseMutex( init_mutex
);
2556 if (!deleting
&& (status
& PRINTER_STATUS_DRIVER_UPDATE_NEEDED
))
2557 update_driver( *phPrinter
);
2561 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2562 return (*phPrinter
!= 0);
2565 /******************************************************************
2566 * AddMonitorA [WINSPOOL.@]
2571 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2573 LPWSTR nameW
= NULL
;
2576 LPMONITOR_INFO_2A mi2a
;
2577 MONITOR_INFO_2W mi2w
;
2579 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2580 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2581 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2582 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2583 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2586 SetLastError(ERROR_INVALID_LEVEL
);
2590 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2596 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2597 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2598 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2601 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2603 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2604 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2605 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2607 if (mi2a
->pEnvironment
) {
2608 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2609 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2610 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2612 if (mi2a
->pDLLName
) {
2613 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2614 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2615 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2618 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2620 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2621 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2622 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2624 HeapFree(GetProcessHeap(), 0, nameW
);
2628 /******************************************************************************
2629 * AddMonitorW [WINSPOOL.@]
2631 * Install a Printmonitor
2634 * pName [I] Servername or NULL (local Computer)
2635 * Level [I] Structure-Level (Must be 2)
2636 * pMonitors [I] PTR to MONITOR_INFO_2
2643 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2646 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2648 LPMONITOR_INFO_2W mi2w
;
2650 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2651 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2652 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2653 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2654 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2656 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2659 SetLastError(ERROR_INVALID_LEVEL
);
2663 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2668 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2671 /******************************************************************
2672 * DeletePrinterDriverA [WINSPOOL.@]
2675 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2677 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2680 /******************************************************************
2681 * DeletePrinterDriverW [WINSPOOL.@]
2684 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2686 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2689 /******************************************************************
2690 * DeleteMonitorA [WINSPOOL.@]
2692 * See DeleteMonitorW.
2695 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2697 LPWSTR nameW
= NULL
;
2698 LPWSTR EnvironmentW
= NULL
;
2699 LPWSTR MonitorNameW
= NULL
;
2704 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2705 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2706 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2710 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2711 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2712 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2715 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2716 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2717 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2720 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2722 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2723 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2724 HeapFree(GetProcessHeap(), 0, nameW
);
2728 /******************************************************************
2729 * DeleteMonitorW [WINSPOOL.@]
2731 * Delete a specific Printmonitor from a Printing-Environment
2734 * pName [I] Servername or NULL (local Computer)
2735 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2736 * pMonitorName [I] Name of the Monitor, that should be deleted
2743 * pEnvironment is ignored in Windows for the local Computer.
2746 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2749 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2750 debugstr_w(pMonitorName
));
2752 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2754 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2758 /******************************************************************
2759 * DeletePortA [WINSPOOL.@]
2764 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2766 LPWSTR nameW
= NULL
;
2767 LPWSTR portW
= NULL
;
2771 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2773 /* convert servername to unicode */
2775 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2776 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2777 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2780 /* convert portname to unicode */
2782 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2783 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2784 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2787 res
= DeletePortW(nameW
, hWnd
, portW
);
2788 HeapFree(GetProcessHeap(), 0, nameW
);
2789 HeapFree(GetProcessHeap(), 0, portW
);
2793 /******************************************************************
2794 * DeletePortW [WINSPOOL.@]
2796 * Delete a specific Port
2799 * pName [I] Servername or NULL (local Computer)
2800 * hWnd [I] Handle to parent Window for the Dialog-Box
2801 * pPortName [I] Name of the Port, that should be deleted
2808 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2810 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2812 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2815 SetLastError(RPC_X_NULL_REF_POINTER
);
2819 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2822 /******************************************************************************
2823 * WritePrinter [WINSPOOL.@]
2825 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2827 opened_printer_t
*printer
;
2830 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2832 EnterCriticalSection(&printer_handles_cs
);
2833 printer
= get_opened_printer(hPrinter
);
2836 SetLastError(ERROR_INVALID_HANDLE
);
2842 SetLastError(ERROR_SPL_NO_STARTDOC
);
2846 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2848 LeaveCriticalSection(&printer_handles_cs
);
2852 /*****************************************************************************
2853 * AddFormA [WINSPOOL.@]
2855 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2857 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2861 /*****************************************************************************
2862 * AddFormW [WINSPOOL.@]
2864 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2866 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2870 /*****************************************************************************
2871 * AddJobA [WINSPOOL.@]
2873 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2876 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2880 SetLastError(ERROR_INVALID_LEVEL
);
2884 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2887 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2888 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2889 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2890 if(*pcbNeeded
> cbBuf
) {
2891 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2894 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2895 addjobA
->JobId
= addjobW
->JobId
;
2896 addjobA
->Path
= (char *)(addjobA
+ 1);
2897 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2903 /*****************************************************************************
2904 * AddJobW [WINSPOOL.@]
2906 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2908 opened_printer_t
*printer
;
2911 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2912 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2913 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2915 ADDJOB_INFO_1W
*addjob
;
2917 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2919 EnterCriticalSection(&printer_handles_cs
);
2921 printer
= get_opened_printer(hPrinter
);
2924 SetLastError(ERROR_INVALID_HANDLE
);
2929 SetLastError(ERROR_INVALID_LEVEL
);
2933 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2937 job
->job_id
= InterlockedIncrement(&next_job_id
);
2939 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2940 if(path
[len
- 1] != '\\')
2942 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2943 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2945 len
= strlenW(filename
);
2946 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2947 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2948 job
->portname
= NULL
;
2949 job
->document_title
= strdupW(default_doc_title
);
2950 job
->printer_name
= strdupW(printer
->name
);
2951 job
->devmode
= dup_devmode( printer
->devmode
);
2952 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2954 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2955 if(*pcbNeeded
<= cbBuf
) {
2956 addjob
= (ADDJOB_INFO_1W
*)pData
;
2957 addjob
->JobId
= job
->job_id
;
2958 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2959 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2962 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2965 LeaveCriticalSection(&printer_handles_cs
);
2969 /*****************************************************************************
2970 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2972 * Return the PATH for the Print-Processors
2974 * See GetPrintProcessorDirectoryW.
2978 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2979 DWORD level
, LPBYTE Info
,
2980 DWORD cbBuf
, LPDWORD pcbNeeded
)
2982 LPWSTR serverW
= NULL
;
2987 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2988 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2992 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2993 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2994 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2998 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2999 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3000 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
3003 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
3004 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
3006 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
3009 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
3010 cbBuf
, NULL
, NULL
) > 0;
3013 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
3014 HeapFree(GetProcessHeap(), 0, envW
);
3015 HeapFree(GetProcessHeap(), 0, serverW
);
3019 /*****************************************************************************
3020 * GetPrintProcessorDirectoryW [WINSPOOL.@]
3022 * Return the PATH for the Print-Processors
3025 * server [I] Servername (NT only) or NULL (local Computer)
3026 * env [I] Printing-Environment (see below) or NULL (Default)
3027 * level [I] Structure-Level (must be 1)
3028 * Info [O] PTR to Buffer that receives the Result
3029 * cbBuf [I] Size of Buffer at "Info"
3030 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3031 * required for the Buffer at "Info"
3034 * Success: TRUE and in pcbNeeded the Bytes used in Info
3035 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
3036 * if cbBuf is too small
3038 * Native Values returned in Info on Success:
3039 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
3040 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
3041 *| win9x(Windows 4.0): "%winsysdir%"
3043 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3046 * Only NULL or "" is supported for server
3049 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
3050 DWORD level
, LPBYTE Info
,
3051 DWORD cbBuf
, LPDWORD pcbNeeded
)
3054 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
3055 Info
, cbBuf
, pcbNeeded
);
3057 if ((backend
== NULL
) && !load_backend()) return FALSE
;
3060 /* (Level != 1) is ignored in win9x */
3061 SetLastError(ERROR_INVALID_LEVEL
);
3065 if (pcbNeeded
== NULL
) {
3066 /* (pcbNeeded == NULL) is ignored in win9x */
3067 SetLastError(RPC_X_NULL_REF_POINTER
);
3071 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
3074 /*****************************************************************************
3075 * WINSPOOL_OpenDriverReg [internal]
3077 * opens the registry for the printer drivers depending on the given input
3078 * variable pEnvironment
3081 * the opened hkey on success
3084 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
3088 const printenv_t
* env
;
3090 TRACE("(%s)\n", debugstr_w(pEnvironment
));
3092 env
= validate_envW(pEnvironment
);
3093 if (!env
) return NULL
;
3095 buffer
= HeapAlloc( GetProcessHeap(), 0,
3096 (strlenW(DriversW
) + strlenW(env
->envname
) +
3097 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
3099 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
3100 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
3101 HeapFree(GetProcessHeap(), 0, buffer
);
3106 /*****************************************************************************
3107 * set_devices_and_printerports [internal]
3109 * set the [Devices] and [PrinterPorts] entries for a printer.
3112 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
3114 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
3118 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
3120 /* FIXME: the driver must change to "winspool" */
3121 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
3123 lstrcpyW(devline
, driver_nt
);
3124 lstrcatW(devline
, commaW
);
3125 lstrcatW(devline
, pi
->pPortName
);
3127 TRACE("using %s\n", debugstr_w(devline
));
3128 WriteProfileStringW(devicesW
, pi
->pPrinterName
, devline
);
3129 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
3130 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3131 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3135 lstrcatW(devline
, timeout_15_45
);
3136 WriteProfileStringW(PrinterPortsW
, pi
->pPrinterName
, devline
);
3137 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
3138 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
3139 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
3142 HeapFree(GetProcessHeap(), 0, devline
);
3146 /*****************************************************************************
3147 * AddPrinterW [WINSPOOL.@]
3149 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3151 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
3154 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
3157 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
3160 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
3161 SetLastError(ERROR_INVALID_PARAMETER
);
3165 ERR("Level = %d, unsupported!\n", Level
);
3166 SetLastError(ERROR_INVALID_LEVEL
);
3170 SetLastError(ERROR_INVALID_PARAMETER
);
3173 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3175 ERR("Can't create Printers key\n");
3178 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
3179 if (!RegQueryValueW(hkeyPrinter
, AttributesW
, NULL
, NULL
)) {
3180 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
3181 RegCloseKey(hkeyPrinter
);
3182 RegCloseKey(hkeyPrinters
);
3185 RegCloseKey(hkeyPrinter
);
3187 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
3189 ERR("Can't create Drivers key\n");
3190 RegCloseKey(hkeyPrinters
);
3193 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
3195 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
3196 RegCloseKey(hkeyPrinters
);
3197 RegCloseKey(hkeyDrivers
);
3198 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
3201 RegCloseKey(hkeyDriver
);
3202 RegCloseKey(hkeyDrivers
);
3204 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
3205 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
3206 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
3207 RegCloseKey(hkeyPrinters
);
3211 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
3213 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
3214 SetLastError(ERROR_INVALID_PRINTER_NAME
);
3215 RegCloseKey(hkeyPrinters
);
3219 set_devices_and_printerports(pi
);
3221 set_reg_DWORD(hkeyPrinter
, AttributesW
, pi
->Attributes
);
3222 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
3223 set_reg_DWORD(hkeyPrinter
, Default_PriorityW
, pi
->DefaultPriority
);
3224 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
3225 set_reg_DWORD(hkeyPrinter
, dnsTimeoutW
, 0);
3226 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
3227 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
3228 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
3229 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
3230 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
3231 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
3232 set_reg_DWORD(hkeyPrinter
, PriorityW
, pi
->Priority
);
3233 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
3234 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
3235 set_reg_DWORD(hkeyPrinter
, StartTimeW
, pi
->StartTime
);
3236 set_reg_DWORD(hkeyPrinter
, StatusW
, pi
->Status
);
3237 set_reg_DWORD(hkeyPrinter
, txTimeoutW
, 0);
3238 set_reg_DWORD(hkeyPrinter
, UntilTimeW
, pi
->UntilTime
);
3240 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
3244 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
3245 size
= sizeof(DEVMODEW
);
3251 dm
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3253 if (DocumentPropertiesW(0, 0, pi
->pPrinterName
, dm
, NULL
, DM_OUT_BUFFER
) < 0)
3255 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
3256 HeapFree( GetProcessHeap(), 0, dm
);
3261 /* set devmode to printer name */
3262 lstrcpynW( dm
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
3266 set_reg_devmode( hkeyPrinter
, Default_DevModeW
, dm
);
3267 if (!pi
->pDevMode
) HeapFree( GetProcessHeap(), 0, dm
);
3269 RegCloseKey(hkeyPrinter
);
3270 RegCloseKey(hkeyPrinters
);
3271 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
3272 ERR("OpenPrinter failing\n");
3278 /*****************************************************************************
3279 * AddPrinterA [WINSPOOL.@]
3281 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
3283 UNICODE_STRING pNameW
;
3285 PRINTER_INFO_2W
*piW
;
3286 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
3289 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
3291 ERR("Level = %d, unsupported!\n", Level
);
3292 SetLastError(ERROR_INVALID_LEVEL
);
3295 pwstrNameW
= asciitounicode(&pNameW
,pName
);
3296 piW
= printer_info_AtoW( piA
, Level
);
3298 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
3300 free_printer_info( piW
, Level
);
3301 RtlFreeUnicodeString(&pNameW
);
3306 /*****************************************************************************
3307 * ClosePrinter [WINSPOOL.@]
3309 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
3311 UINT_PTR i
= (UINT_PTR
)hPrinter
;
3312 opened_printer_t
*printer
= NULL
;
3315 TRACE("(%p)\n", hPrinter
);
3317 EnterCriticalSection(&printer_handles_cs
);
3319 if ((i
> 0) && (i
<= nb_printer_handles
))
3320 printer
= printer_handles
[i
- 1];
3325 struct list
*cursor
, *cursor2
;
3327 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
3329 if (printer
->backend_printer
) {
3330 backend
->fpClosePrinter(printer
->backend_printer
);
3334 EndDocPrinter(hPrinter
);
3336 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
3338 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
3340 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
3341 ScheduleJob(hPrinter
, job
->job_id
);
3343 HeapFree(GetProcessHeap(), 0, printer
->queue
);
3346 free_printer_entry( printer
);
3347 printer_handles
[i
- 1] = NULL
;
3350 LeaveCriticalSection(&printer_handles_cs
);
3354 /*****************************************************************************
3355 * DeleteFormA [WINSPOOL.@]
3357 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3359 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3363 /*****************************************************************************
3364 * DeleteFormW [WINSPOOL.@]
3366 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3368 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3372 /*****************************************************************************
3373 * DeletePrinter [WINSPOOL.@]
3375 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3377 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3378 HKEY hkeyPrinters
, hkey
;
3379 WCHAR def
[MAX_PATH
];
3380 DWORD size
= sizeof( def
) / sizeof( def
[0] );
3383 SetLastError(ERROR_INVALID_HANDLE
);
3386 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3387 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3388 RegCloseKey(hkeyPrinters
);
3390 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3391 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
3393 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3394 RegDeleteValueW(hkey
, lpNameW
);
3398 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
3399 RegDeleteValueW(hkey
, lpNameW
);
3403 if (GetDefaultPrinterW( def
, &size
) && !strcmpW( def
, lpNameW
))
3405 WriteProfileStringW( windowsW
, deviceW
, NULL
);
3406 if (!RegCreateKeyW( HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
))
3408 RegDeleteValueW( hkey
, deviceW
);
3409 RegCloseKey( hkey
);
3411 SetDefaultPrinterW( NULL
);
3417 /*****************************************************************************
3418 * SetPrinterA [WINSPOOL.@]
3420 BOOL WINAPI
SetPrinterA( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3427 dataW
= printer_info_AtoW( data
, level
);
3428 if (!dataW
) return FALSE
;
3431 ret
= SetPrinterW( printer
, level
, dataW
, command
);
3433 if (dataW
!= data
) free_printer_info( dataW
, level
);
3438 static void set_printer_2( HKEY key
, const PRINTER_INFO_2W
*pi
)
3440 set_reg_szW( key
, NameW
, pi
->pPrinterName
);
3441 set_reg_szW( key
, Share_NameW
, pi
->pShareName
);
3442 set_reg_szW( key
, PortW
, pi
->pPortName
);
3443 set_reg_szW( key
, Printer_DriverW
, pi
->pDriverName
);
3444 set_reg_szW( key
, DescriptionW
, pi
->pComment
);
3445 set_reg_szW( key
, LocationW
, pi
->pLocation
);
3448 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3450 set_reg_szW( key
, Separator_FileW
, pi
->pSepFile
);
3451 set_reg_szW( key
, Print_ProcessorW
, pi
->pPrintProcessor
);
3452 set_reg_szW( key
, DatatypeW
, pi
->pDatatype
);
3453 set_reg_szW( key
, ParametersW
, pi
->pParameters
);
3455 set_reg_DWORD( key
, AttributesW
, pi
->Attributes
);
3456 set_reg_DWORD( key
, PriorityW
, pi
->Priority
);
3457 set_reg_DWORD( key
, Default_PriorityW
, pi
->DefaultPriority
);
3458 set_reg_DWORD( key
, StartTimeW
, pi
->StartTime
);
3459 set_reg_DWORD( key
, UntilTimeW
, pi
->UntilTime
);
3462 static BOOL
set_printer_9( HKEY key
, const PRINTER_INFO_9W
*pi
)
3464 if (!pi
->pDevMode
) return FALSE
;
3466 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
3470 /******************************************************************************
3471 * SetPrinterW [WINSPOOL.@]
3473 BOOL WINAPI
SetPrinterW( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
3478 TRACE( "(%p, %d, %p, %d)\n", printer
, level
, data
, command
);
3480 if (command
!= 0) FIXME( "Ignoring command %d\n", command
);
3482 if (WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
))
3489 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)data
;
3490 set_printer_2( key
, pi2
);
3497 PRINTER_INFO_9W
*pi
= (PRINTER_INFO_9W
*)data
;
3498 ret
= set_printer_9( key
, pi
);
3503 FIXME( "Unimplemented level %d\n", level
);
3504 SetLastError( ERROR_INVALID_LEVEL
);
3511 /*****************************************************************************
3512 * SetJobA [WINSPOOL.@]
3514 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3515 LPBYTE pJob
, DWORD Command
)
3519 UNICODE_STRING usBuffer
;
3521 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3523 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3524 are all ignored by SetJob, so we don't bother copying them */
3532 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3533 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3535 JobW
= (LPBYTE
)info1W
;
3536 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3537 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3538 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3539 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3540 info1W
->Status
= info1A
->Status
;
3541 info1W
->Priority
= info1A
->Priority
;
3542 info1W
->Position
= info1A
->Position
;
3543 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3548 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3549 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3551 JobW
= (LPBYTE
)info2W
;
3552 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3553 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3554 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3555 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3556 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3557 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3558 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3559 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3560 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3561 info2W
->Status
= info2A
->Status
;
3562 info2W
->Priority
= info2A
->Priority
;
3563 info2W
->Position
= info2A
->Position
;
3564 info2W
->StartTime
= info2A
->StartTime
;
3565 info2W
->UntilTime
= info2A
->UntilTime
;
3566 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3570 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3571 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3574 SetLastError(ERROR_INVALID_LEVEL
);
3578 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3584 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3585 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3586 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3587 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3588 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3593 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3594 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3595 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3596 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3597 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3598 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3599 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3600 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3601 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3605 HeapFree(GetProcessHeap(), 0, JobW
);
3610 /*****************************************************************************
3611 * SetJobW [WINSPOOL.@]
3613 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3614 LPBYTE pJob
, DWORD Command
)
3619 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3620 FIXME("Ignoring everything other than document title\n");
3622 EnterCriticalSection(&printer_handles_cs
);
3623 job
= get_job(hPrinter
, JobId
);
3633 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3634 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3635 job
->document_title
= strdupW(info1
->pDocument
);
3640 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3641 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3642 job
->document_title
= strdupW(info2
->pDocument
);
3643 HeapFree(GetProcessHeap(), 0, job
->devmode
);
3644 job
->devmode
= dup_devmode( info2
->pDevMode
);
3650 SetLastError(ERROR_INVALID_LEVEL
);
3655 LeaveCriticalSection(&printer_handles_cs
);
3659 /*****************************************************************************
3660 * EndDocPrinter [WINSPOOL.@]
3662 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3664 opened_printer_t
*printer
;
3666 TRACE("(%p)\n", hPrinter
);
3668 EnterCriticalSection(&printer_handles_cs
);
3670 printer
= get_opened_printer(hPrinter
);
3673 SetLastError(ERROR_INVALID_HANDLE
);
3679 SetLastError(ERROR_SPL_NO_STARTDOC
);
3683 CloseHandle(printer
->doc
->hf
);
3684 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3685 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3686 printer
->doc
= NULL
;
3689 LeaveCriticalSection(&printer_handles_cs
);
3693 /*****************************************************************************
3694 * EndPagePrinter [WINSPOOL.@]
3696 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3698 FIXME("(%p): stub\n", hPrinter
);
3702 /*****************************************************************************
3703 * StartDocPrinterA [WINSPOOL.@]
3705 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3707 UNICODE_STRING usBuffer
;
3709 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3712 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3713 or one (DOC_INFO_3) extra DWORDs */
3717 doc2W
.JobId
= doc2
->JobId
;
3720 doc2W
.dwMode
= doc2
->dwMode
;
3723 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3724 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3725 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3729 SetLastError(ERROR_INVALID_LEVEL
);
3733 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3735 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3736 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3737 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3742 /*****************************************************************************
3743 * StartDocPrinterW [WINSPOOL.@]
3745 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3747 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3748 opened_printer_t
*printer
;
3749 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3750 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3751 JOB_INFO_1W job_info
;
3752 DWORD needed
, ret
= 0;
3757 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3758 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3759 debugstr_w(doc
->pDatatype
));
3761 if(Level
< 1 || Level
> 3)
3763 SetLastError(ERROR_INVALID_LEVEL
);
3767 EnterCriticalSection(&printer_handles_cs
);
3768 printer
= get_opened_printer(hPrinter
);
3771 SetLastError(ERROR_INVALID_HANDLE
);
3777 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3781 /* Even if we're printing to a file we still add a print job, we'll
3782 just ignore the spool file name */
3784 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3786 ERR("AddJob failed gle %u\n", GetLastError());
3790 /* use pOutputFile only, when it is a real filename */
3791 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3792 filename
= doc
->pOutputFile
;
3794 filename
= addjob
->Path
;
3796 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3797 if(hf
== INVALID_HANDLE_VALUE
)
3800 memset(&job_info
, 0, sizeof(job_info
));
3801 job_info
.pDocument
= doc
->pDocName
;
3802 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3804 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3805 printer
->doc
->hf
= hf
;
3806 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3807 job
= get_job(hPrinter
, ret
);
3808 job
->portname
= strdupW(doc
->pOutputFile
);
3811 LeaveCriticalSection(&printer_handles_cs
);
3816 /*****************************************************************************
3817 * StartPagePrinter [WINSPOOL.@]
3819 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3821 FIXME("(%p): stub\n", hPrinter
);
3825 /*****************************************************************************
3826 * GetFormA [WINSPOOL.@]
3828 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3829 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3831 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3832 Level
,pForm
,cbBuf
,pcbNeeded
);
3836 /*****************************************************************************
3837 * GetFormW [WINSPOOL.@]
3839 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3840 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3842 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3843 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3847 /*****************************************************************************
3848 * SetFormA [WINSPOOL.@]
3850 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3853 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3857 /*****************************************************************************
3858 * SetFormW [WINSPOOL.@]
3860 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3863 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3867 /*****************************************************************************
3868 * ReadPrinter [WINSPOOL.@]
3870 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3871 LPDWORD pNoBytesRead
)
3873 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3877 /*****************************************************************************
3878 * ResetPrinterA [WINSPOOL.@]
3880 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3882 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3886 /*****************************************************************************
3887 * ResetPrinterW [WINSPOOL.@]
3889 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3891 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3895 /*****************************************************************************
3896 * get_filename_from_reg [internal]
3898 * Get ValueName from hkey storing result in out
3899 * when the Value in the registry has only a filename, use driverdir as prefix
3900 * outlen is space left in out
3901 * String is stored either as unicode or ascii
3905 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3906 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3908 WCHAR filename
[MAX_PATH
];
3912 LPWSTR buffer
= filename
;
3916 size
= sizeof(filename
);
3918 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3919 if (ret
== ERROR_MORE_DATA
) {
3920 TRACE("need dynamic buffer: %u\n", size
);
3921 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3923 /* No Memory is bad */
3927 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3930 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3931 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3937 /* do we have a full path ? */
3938 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3939 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3942 /* we must build the full Path */
3944 if ((out
) && (outlen
> dirlen
)) {
3945 lstrcpyW((LPWSTR
)out
, driverdir
);
3953 /* write the filename */
3954 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3955 if ((out
) && (outlen
>= size
)) {
3956 lstrcpyW((LPWSTR
)out
, ptr
);
3963 ptr
+= lstrlenW(ptr
)+1;
3964 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3967 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3969 /* write the multisz-termination */
3970 if (type
== REG_MULTI_SZ
) {
3971 size
= sizeof(WCHAR
);
3974 if (out
&& (outlen
>= size
)) {
3975 memset (out
, 0, size
);
3981 /*****************************************************************************
3982 * WINSPOOL_GetStringFromReg
3984 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3985 * String is stored as unicode.
3987 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3988 DWORD buflen
, DWORD
*needed
)
3990 DWORD sz
= buflen
, type
;
3993 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3994 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3995 WARN("Got ret = %d\n", ret
);
3999 /* add space for terminating '\0' */
4000 sz
+= sizeof(WCHAR
);
4004 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
4009 /*****************************************************************************
4010 * WINSPOOL_GetDefaultDevMode
4012 * Get a default DevMode values for wineps.
4014 static void WINSPOOL_GetDefaultDevMode(LPBYTE ptr
, DWORD buflen
, DWORD
*needed
)
4016 static const WCHAR winepsW
[] = { 'w','i','n','e','p','s','.','d','r','v',0 };
4018 if (buflen
>= sizeof(DEVMODEW
))
4020 DEVMODEW
*dm
= (DEVMODEW
*)ptr
;
4022 /* the driver will update registry with real values */
4023 memset(dm
, 0, sizeof(*dm
));
4024 dm
->dmSize
= sizeof(*dm
);
4025 lstrcpyW(dm
->dmDeviceName
, winepsW
);
4027 *needed
= sizeof(DEVMODEW
);
4030 /*****************************************************************************
4031 * WINSPOOL_GetDevModeFromReg
4033 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
4034 * DevMode is stored either as unicode or ascii.
4036 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
4038 DWORD buflen
, DWORD
*needed
)
4040 DWORD sz
= buflen
, type
;
4043 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
4044 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
4045 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
4046 if (sz
< sizeof(DEVMODEA
))
4048 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
4051 /* ensures that dmSize is not erratically bogus if registry is invalid */
4052 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
4053 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
4054 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
4055 if (ptr
&& (buflen
>= sz
)) {
4056 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
4057 memcpy(ptr
, dmW
, sz
);
4058 HeapFree(GetProcessHeap(),0,dmW
);
4064 /*********************************************************************
4065 * WINSPOOL_GetPrinter_1
4067 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
4069 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
4070 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4072 DWORD size
, left
= cbBuf
;
4073 BOOL space
= (cbBuf
> 0);
4078 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4079 if(space
&& size
<= left
) {
4080 pi1
->pName
= (LPWSTR
)ptr
;
4088 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
4089 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4090 if(space
&& size
<= left
) {
4091 pi1
->pDescription
= (LPWSTR
)ptr
;
4099 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4100 if(space
&& size
<= left
) {
4101 pi1
->pComment
= (LPWSTR
)ptr
;
4109 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
4111 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
4112 memset(pi1
, 0, sizeof(*pi1
));
4116 /*********************************************************************
4117 * WINSPOOL_GetPrinter_2
4119 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
4121 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
4122 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4124 DWORD size
, left
= cbBuf
;
4125 BOOL space
= (cbBuf
> 0);
4130 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4131 if(space
&& size
<= left
) {
4132 pi2
->pPrinterName
= (LPWSTR
)ptr
;
4139 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
4140 if(space
&& size
<= left
) {
4141 pi2
->pShareName
= (LPWSTR
)ptr
;
4148 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4149 if(space
&& size
<= left
) {
4150 pi2
->pPortName
= (LPWSTR
)ptr
;
4157 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
4158 if(space
&& size
<= left
) {
4159 pi2
->pDriverName
= (LPWSTR
)ptr
;
4166 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
4167 if(space
&& size
<= left
) {
4168 pi2
->pComment
= (LPWSTR
)ptr
;
4175 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
4176 if(space
&& size
<= left
) {
4177 pi2
->pLocation
= (LPWSTR
)ptr
;
4184 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
4185 if(space
&& size
<= left
) {
4186 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4195 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
4196 if(space
&& size
<= left
) {
4197 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
4204 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
4205 if(space
&& size
<= left
) {
4206 pi2
->pSepFile
= (LPWSTR
)ptr
;
4213 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
4214 if(space
&& size
<= left
) {
4215 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
4222 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
4223 if(space
&& size
<= left
) {
4224 pi2
->pDatatype
= (LPWSTR
)ptr
;
4231 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
4232 if(space
&& size
<= left
) {
4233 pi2
->pParameters
= (LPWSTR
)ptr
;
4241 pi2
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4242 pi2
->Priority
= get_dword_from_reg( hkeyPrinter
, PriorityW
);
4243 pi2
->DefaultPriority
= get_dword_from_reg( hkeyPrinter
, Default_PriorityW
);
4244 pi2
->StartTime
= get_dword_from_reg( hkeyPrinter
, StartTimeW
);
4245 pi2
->UntilTime
= get_dword_from_reg( hkeyPrinter
, UntilTimeW
);
4248 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
4249 memset(pi2
, 0, sizeof(*pi2
));
4254 /*********************************************************************
4255 * WINSPOOL_GetPrinter_4
4257 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4259 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
4260 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4262 DWORD size
, left
= cbBuf
;
4263 BOOL space
= (cbBuf
> 0);
4268 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4269 if(space
&& size
<= left
) {
4270 pi4
->pPrinterName
= (LPWSTR
)ptr
;
4278 pi4
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4281 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
4282 memset(pi4
, 0, sizeof(*pi4
));
4287 /*********************************************************************
4288 * WINSPOOL_GetPrinter_5
4290 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4292 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
4293 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
4295 DWORD size
, left
= cbBuf
;
4296 BOOL space
= (cbBuf
> 0);
4301 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
4302 if(space
&& size
<= left
) {
4303 pi5
->pPrinterName
= (LPWSTR
)ptr
;
4310 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
4311 if(space
&& size
<= left
) {
4312 pi5
->pPortName
= (LPWSTR
)ptr
;
4320 pi5
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
4321 pi5
->DeviceNotSelectedTimeout
= get_dword_from_reg( hkeyPrinter
, dnsTimeoutW
);
4322 pi5
->TransmissionRetryTimeout
= get_dword_from_reg( hkeyPrinter
, txTimeoutW
);
4325 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
4326 memset(pi5
, 0, sizeof(*pi5
));
4331 /*********************************************************************
4332 * WINSPOOL_GetPrinter_7
4334 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4336 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
4337 DWORD cbBuf
, LPDWORD pcbNeeded
)
4339 DWORD size
, left
= cbBuf
;
4340 BOOL space
= (cbBuf
> 0);
4345 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
4348 size
= sizeof(pi7
->pszObjectGUID
);
4350 if (space
&& size
<= left
) {
4351 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
4358 /* We do not have a Directory Service */
4359 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
4362 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
4363 memset(pi7
, 0, sizeof(*pi7
));
4368 /*********************************************************************
4369 * WINSPOOL_GetPrinter_9
4371 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
4373 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
4374 DWORD cbBuf
, LPDWORD pcbNeeded
)
4377 BOOL space
= (cbBuf
> 0);
4381 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
4382 if(space
&& size
<= cbBuf
) {
4383 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4390 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
4391 if(space
&& size
<= cbBuf
) {
4392 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4398 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
4399 memset(pi9
, 0, sizeof(*pi9
));
4404 /*****************************************************************************
4405 * GetPrinterW [WINSPOOL.@]
4407 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4408 DWORD cbBuf
, LPDWORD pcbNeeded
)
4410 DWORD size
, needed
= 0, err
;
4415 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4417 err
= WINSPOOL_GetOpenedPrinterRegKey( hPrinter
, &hkeyPrinter
);
4420 SetLastError( err
);
4427 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4429 size
= sizeof(PRINTER_INFO_2W
);
4431 ptr
= pPrinter
+ size
;
4433 memset(pPrinter
, 0, size
);
4438 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
4445 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4447 size
= sizeof(PRINTER_INFO_4W
);
4449 ptr
= pPrinter
+ size
;
4451 memset(pPrinter
, 0, size
);
4456 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
4464 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4466 size
= sizeof(PRINTER_INFO_5W
);
4468 ptr
= pPrinter
+ size
;
4470 memset(pPrinter
, 0, size
);
4476 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
4484 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4486 size
= sizeof(PRINTER_INFO_6
);
4487 if (size
<= cbBuf
) {
4488 /* FIXME: We do not update the status yet */
4489 pi6
->dwStatus
= get_dword_from_reg( hkeyPrinter
, StatusW
);
4501 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4503 size
= sizeof(PRINTER_INFO_7W
);
4504 if (size
<= cbBuf
) {
4505 ptr
= pPrinter
+ size
;
4507 memset(pPrinter
, 0, size
);
4513 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
4520 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4521 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4525 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4527 size
= sizeof(PRINTER_INFO_9W
);
4529 ptr
= pPrinter
+ size
;
4531 memset(pPrinter
, 0, size
);
4537 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
4544 FIXME("Unimplemented level %d\n", Level
);
4545 SetLastError(ERROR_INVALID_LEVEL
);
4546 RegCloseKey(hkeyPrinter
);
4550 RegCloseKey(hkeyPrinter
);
4552 TRACE("returning %d needed = %d\n", ret
, needed
);
4553 if(pcbNeeded
) *pcbNeeded
= needed
;
4555 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4559 /*****************************************************************************
4560 * GetPrinterA [WINSPOOL.@]
4562 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4563 DWORD cbBuf
, LPDWORD pcbNeeded
)
4569 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4571 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
4573 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
4574 HeapFree(GetProcessHeap(), 0, buf
);
4579 /*****************************************************************************
4580 * WINSPOOL_EnumPrintersW
4582 * Implementation of EnumPrintersW
4584 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
4585 DWORD dwLevel
, LPBYTE lpbPrinters
,
4586 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4587 LPDWORD lpdwReturned
)
4590 HKEY hkeyPrinters
, hkeyPrinter
;
4591 WCHAR PrinterName
[255];
4592 DWORD needed
= 0, number
= 0;
4593 DWORD used
, i
, left
;
4597 memset(lpbPrinters
, 0, cbBuf
);
4603 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4604 if(dwType
== PRINTER_ENUM_DEFAULT
)
4607 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4608 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4609 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4611 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4617 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4618 FIXME("dwType = %08x\n", dwType
);
4619 SetLastError(ERROR_INVALID_FLAGS
);
4623 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4625 ERR("Can't create Printers key\n");
4629 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4630 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4631 RegCloseKey(hkeyPrinters
);
4632 ERR("Can't query Printers key\n");
4635 TRACE("Found %d printers\n", number
);
4639 used
= number
* sizeof(PRINTER_INFO_1W
);
4642 used
= number
* sizeof(PRINTER_INFO_2W
);
4645 used
= number
* sizeof(PRINTER_INFO_4W
);
4648 used
= number
* sizeof(PRINTER_INFO_5W
);
4652 SetLastError(ERROR_INVALID_LEVEL
);
4653 RegCloseKey(hkeyPrinters
);
4656 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4658 for(i
= 0; i
< number
; i
++) {
4659 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4661 ERR("Can't enum key number %d\n", i
);
4662 RegCloseKey(hkeyPrinters
);
4665 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4666 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4668 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4669 RegCloseKey(hkeyPrinters
);
4674 buf
= lpbPrinters
+ used
;
4675 left
= cbBuf
- used
;
4683 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4686 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4689 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4692 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4695 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4698 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4701 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4704 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4707 ERR("Shouldn't be here!\n");
4708 RegCloseKey(hkeyPrinter
);
4709 RegCloseKey(hkeyPrinters
);
4712 RegCloseKey(hkeyPrinter
);
4714 RegCloseKey(hkeyPrinters
);
4721 memset(lpbPrinters
, 0, cbBuf
);
4722 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4726 *lpdwReturned
= number
;
4727 SetLastError(ERROR_SUCCESS
);
4732 /******************************************************************
4733 * EnumPrintersW [WINSPOOL.@]
4735 * Enumerates the available printers, print servers and print
4736 * providers, depending on the specified flags, name and level.
4740 * If level is set to 1:
4741 * Returns an array of PRINTER_INFO_1 data structures in the
4742 * lpbPrinters buffer.
4744 * If level is set to 2:
4745 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4746 * Returns an array of PRINTER_INFO_2 data structures in the
4747 * lpbPrinters buffer. Note that according to MSDN also an
4748 * OpenPrinter should be performed on every remote printer.
4750 * If level is set to 4 (officially WinNT only):
4751 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4752 * Fast: Only the registry is queried to retrieve printer names,
4753 * no connection to the driver is made.
4754 * Returns an array of PRINTER_INFO_4 data structures in the
4755 * lpbPrinters buffer.
4757 * If level is set to 5 (officially WinNT4/Win9x only):
4758 * Fast: Only the registry is queried to retrieve printer names,
4759 * no connection to the driver is made.
4760 * Returns an array of PRINTER_INFO_5 data structures in the
4761 * lpbPrinters buffer.
4763 * If level set to 3 or 6+:
4764 * returns zero (failure!)
4766 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4770 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4771 * - Only levels 2, 4 and 5 are implemented at the moment.
4772 * - 16-bit printer drivers are not enumerated.
4773 * - Returned amount of bytes used/needed does not match the real Windoze
4774 * implementation (as in this implementation, all strings are part
4775 * of the buffer, whereas Win32 keeps them somewhere else)
4776 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4779 * - In a regular Wine installation, no registry settings for printers
4780 * exist, which makes this function return an empty list.
4782 BOOL WINAPI
EnumPrintersW(
4783 DWORD dwType
, /* [in] Types of print objects to enumerate */
4784 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4785 DWORD dwLevel
, /* [in] type of printer info structure */
4786 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4787 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4788 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4789 LPDWORD lpdwReturned
/* [out] number of entries returned */
4792 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4793 lpdwNeeded
, lpdwReturned
);
4796 /******************************************************************
4797 * EnumPrintersA [WINSPOOL.@]
4802 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4803 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4806 UNICODE_STRING pNameU
;
4810 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4811 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4813 pNameW
= asciitounicode(&pNameU
, pName
);
4815 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4816 MS Office need this */
4817 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4819 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4821 RtlFreeUnicodeString(&pNameU
);
4823 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4825 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4829 /*****************************************************************************
4830 * WINSPOOL_GetDriverInfoFromReg [internal]
4832 * Enters the information from the registry into the DRIVER_INFO struct
4835 * zero if the printer driver does not exist in the registry
4836 * (only if Level > 1) otherwise nonzero
4838 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4841 const printenv_t
* env
,
4843 LPBYTE ptr
, /* DRIVER_INFO */
4844 LPBYTE pDriverStrings
, /* strings buffer */
4845 DWORD cbBuf
, /* size of string buffer */
4846 LPDWORD pcbNeeded
) /* space needed for str. */
4850 WCHAR driverdir
[MAX_PATH
];
4852 LPBYTE strPtr
= pDriverStrings
;
4853 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4855 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4856 debugstr_w(DriverName
), env
,
4857 Level
, di
, pDriverStrings
, cbBuf
);
4859 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4861 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4862 if (*pcbNeeded
<= cbBuf
)
4863 strcpyW((LPWSTR
)strPtr
, DriverName
);
4865 /* pName for level 1 has a different offset! */
4867 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4871 /* .cVersion and .pName for level > 1 */
4873 di
->cVersion
= env
->driverversion
;
4874 di
->pName
= (LPWSTR
) strPtr
;
4875 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4878 /* Reserve Space for the largest subdir and a Backslash*/
4879 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4880 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4881 /* Should never Fail */
4884 lstrcatW(driverdir
, env
->versionsubdir
);
4885 lstrcatW(driverdir
, backslashW
);
4887 /* dirlen must not include the terminating zero */
4888 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4890 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4891 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4892 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4897 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4900 if (*pcbNeeded
<= cbBuf
) {
4901 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4902 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4903 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4906 /* .pDriverPath is the Graphics rendering engine.
4907 The full Path is required to avoid a crash in some apps */
4908 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4910 if (*pcbNeeded
<= cbBuf
)
4911 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4913 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4914 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4917 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4918 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4920 if (*pcbNeeded
<= cbBuf
)
4921 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4923 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4924 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4927 /* .pConfigFile is the Driver user Interface */
4928 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4930 if (*pcbNeeded
<= cbBuf
)
4931 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4933 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4934 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4938 RegCloseKey(hkeyDriver
);
4939 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4944 RegCloseKey(hkeyDriver
);
4945 FIXME("level 5: incomplete\n");
4950 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4952 if (*pcbNeeded
<= cbBuf
)
4953 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4955 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4956 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4959 /* .pDependentFiles */
4960 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4962 if (*pcbNeeded
<= cbBuf
)
4963 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4965 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4966 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4968 else if (GetVersion() & 0x80000000) {
4969 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4970 size
= 2 * sizeof(WCHAR
);
4972 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4974 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4975 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4978 /* .pMonitorName is the optional Language Monitor */
4979 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4981 if (*pcbNeeded
<= cbBuf
)
4982 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4984 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4985 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4988 /* .pDefaultDataType */
4989 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
4991 if(*pcbNeeded
<= cbBuf
)
4992 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
4994 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4995 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4999 RegCloseKey(hkeyDriver
);
5000 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5004 /* .pszzPreviousNames */
5005 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
5007 if(*pcbNeeded
<= cbBuf
)
5008 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
5010 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
5011 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5015 RegCloseKey(hkeyDriver
);
5016 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5020 /* support is missing, but not important enough for a FIXME */
5021 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
5024 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
5026 if(*pcbNeeded
<= cbBuf
)
5027 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
5029 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
5030 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5034 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
5036 if(*pcbNeeded
<= cbBuf
)
5037 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
5039 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
5040 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5043 /* .pszHardwareID */
5044 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
5046 if(*pcbNeeded
<= cbBuf
)
5047 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
5049 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
5050 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5054 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
5056 if(*pcbNeeded
<= cbBuf
)
5057 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
5059 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
5060 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
5064 RegCloseKey(hkeyDriver
);
5068 /* support is missing, but not important enough for a FIXME */
5069 TRACE("level 8: incomplete\n");
5071 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
5072 RegCloseKey(hkeyDriver
);
5076 /*****************************************************************************
5077 * GetPrinterDriverW [WINSPOOL.@]
5079 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
5080 DWORD Level
, LPBYTE pDriverInfo
,
5081 DWORD cbBuf
, LPDWORD pcbNeeded
)
5084 WCHAR DriverName
[100];
5085 DWORD ret
, type
, size
, needed
= 0;
5087 HKEY hkeyPrinter
, hkeyDrivers
;
5088 const printenv_t
* env
;
5090 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
5091 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
5094 ZeroMemory(pDriverInfo
, cbBuf
);
5096 if (!(name
= get_opened_printer_name(hPrinter
))) {
5097 SetLastError(ERROR_INVALID_HANDLE
);
5101 if (Level
< 1 || Level
== 7 || Level
> 8) {
5102 SetLastError(ERROR_INVALID_LEVEL
);
5106 env
= validate_envW(pEnvironment
);
5107 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5109 ret
= open_printer_reg_key( name
, &hkeyPrinter
);
5112 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name
) );
5113 SetLastError( ret
);
5117 size
= sizeof(DriverName
);
5119 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
5120 (LPBYTE
)DriverName
, &size
);
5121 RegCloseKey(hkeyPrinter
);
5122 if(ret
!= ERROR_SUCCESS
) {
5123 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
5127 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5129 ERR("Can't create Drivers key\n");
5133 size
= di_sizeof
[Level
];
5134 if ((size
<= cbBuf
) && pDriverInfo
)
5135 ptr
= pDriverInfo
+ size
;
5137 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
5138 env
, Level
, pDriverInfo
, ptr
,
5139 (cbBuf
< size
) ? 0 : cbBuf
- size
,
5141 RegCloseKey(hkeyDrivers
);
5145 RegCloseKey(hkeyDrivers
);
5147 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
5148 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
5149 if(cbBuf
>= size
+ needed
) return TRUE
;
5150 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5154 /*****************************************************************************
5155 * GetPrinterDriverA [WINSPOOL.@]
5157 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
5158 DWORD Level
, LPBYTE pDriverInfo
,
5159 DWORD cbBuf
, LPDWORD pcbNeeded
)
5162 UNICODE_STRING pEnvW
;
5168 ZeroMemory(pDriverInfo
, cbBuf
);
5169 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5172 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
5173 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
5176 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
5178 HeapFree(GetProcessHeap(), 0, buf
);
5180 RtlFreeUnicodeString(&pEnvW
);
5184 /*****************************************************************************
5185 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5187 * Return the PATH for the Printer-Drivers (UNICODE)
5190 * pName [I] Servername (NT only) or NULL (local Computer)
5191 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5192 * Level [I] Structure-Level (must be 1)
5193 * pDriverDirectory [O] PTR to Buffer that receives the Result
5194 * cbBuf [I] Size of Buffer at pDriverDirectory
5195 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5196 * required for pDriverDirectory
5199 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5200 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5201 * if cbBuf is too small
5203 * Native Values returned in pDriverDirectory on Success:
5204 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5205 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5206 *| win9x(Windows 4.0): "%winsysdir%"
5208 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5211 *- Only NULL or "" is supported for pName
5214 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
5215 DWORD Level
, LPBYTE pDriverDirectory
,
5216 DWORD cbBuf
, LPDWORD pcbNeeded
)
5218 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
5219 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5221 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5224 /* (Level != 1) is ignored in win9x */
5225 SetLastError(ERROR_INVALID_LEVEL
);
5228 if (pcbNeeded
== NULL
) {
5229 /* (pcbNeeded == NULL) is ignored in win9x */
5230 SetLastError(RPC_X_NULL_REF_POINTER
);
5234 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
5235 pDriverDirectory
, cbBuf
, pcbNeeded
);
5240 /*****************************************************************************
5241 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5243 * Return the PATH for the Printer-Drivers (ANSI)
5245 * See GetPrinterDriverDirectoryW.
5248 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5251 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
5252 DWORD Level
, LPBYTE pDriverDirectory
,
5253 DWORD cbBuf
, LPDWORD pcbNeeded
)
5255 UNICODE_STRING nameW
, environmentW
;
5258 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
5259 WCHAR
*driverDirectoryW
= NULL
;
5261 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
5262 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5264 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
5266 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
5267 else nameW
.Buffer
= NULL
;
5268 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
5269 else environmentW
.Buffer
= NULL
;
5271 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
5272 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
5275 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
5276 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
5278 *pcbNeeded
= needed
;
5279 ret
= needed
<= cbBuf
;
5281 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
5283 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
5285 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
5286 RtlFreeUnicodeString(&environmentW
);
5287 RtlFreeUnicodeString(&nameW
);
5292 /*****************************************************************************
5293 * AddPrinterDriverA [WINSPOOL.@]
5295 * See AddPrinterDriverW.
5298 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5300 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
5301 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5304 /******************************************************************************
5305 * AddPrinterDriverW (WINSPOOL.@)
5307 * Install a Printer Driver
5310 * pName [I] Servername or NULL (local Computer)
5311 * level [I] Level for the supplied DRIVER_INFO_*W struct
5312 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5319 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5321 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
5322 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5325 /*****************************************************************************
5326 * AddPrintProcessorA [WINSPOOL.@]
5328 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
5329 LPSTR pPrintProcessorName
)
5331 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5332 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
5336 /*****************************************************************************
5337 * AddPrintProcessorW [WINSPOOL.@]
5339 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5340 LPWSTR pPrintProcessorName
)
5342 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5343 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5347 /*****************************************************************************
5348 * AddPrintProvidorA [WINSPOOL.@]
5350 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5352 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5356 /*****************************************************************************
5357 * AddPrintProvidorW [WINSPOOL.@]
5359 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5361 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5365 /*****************************************************************************
5366 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5368 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5369 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5371 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5372 pDevModeOutput
, pDevModeInput
);
5376 /*****************************************************************************
5377 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5379 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5380 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5382 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5383 pDevModeOutput
, pDevModeInput
);
5387 /*****************************************************************************
5388 * PrinterProperties [WINSPOOL.@]
5390 * Displays a dialog to set the properties of the printer.
5393 * nonzero on success or zero on failure
5396 * implemented as stub only
5398 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5399 HANDLE hPrinter
/* [in] handle to printer object */
5401 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5402 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5406 /*****************************************************************************
5407 * EnumJobsA [WINSPOOL.@]
5410 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5411 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5414 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5415 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5417 if(pcbNeeded
) *pcbNeeded
= 0;
5418 if(pcReturned
) *pcReturned
= 0;
5423 /*****************************************************************************
5424 * EnumJobsW [WINSPOOL.@]
5427 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5428 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5431 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5432 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5434 if(pcbNeeded
) *pcbNeeded
= 0;
5435 if(pcReturned
) *pcReturned
= 0;
5439 /*****************************************************************************
5440 * WINSPOOL_EnumPrinterDrivers [internal]
5442 * Delivers information about all printer drivers installed on the
5443 * localhost or a given server
5446 * nonzero on success or zero on failure. If the buffer for the returned
5447 * information is too small the function will return an error
5450 * - only implemented for localhost, foreign hosts will return an error
5452 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5453 DWORD Level
, LPBYTE pDriverInfo
,
5455 DWORD cbBuf
, LPDWORD pcbNeeded
,
5456 LPDWORD pcFound
, DWORD data_offset
)
5460 const printenv_t
* env
;
5462 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
5463 debugstr_w(pName
), debugstr_w(pEnvironment
),
5464 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
5466 env
= validate_envW(pEnvironment
);
5467 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5471 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5473 ERR("Can't open Drivers key\n");
5477 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
5478 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5479 RegCloseKey(hkeyDrivers
);
5480 ERR("Can't query Drivers key\n");
5483 TRACE("Found %d Drivers\n", *pcFound
);
5485 /* get size of single struct
5486 * unicode and ascii structure have the same size
5488 size
= di_sizeof
[Level
];
5490 if (data_offset
== 0)
5491 data_offset
= size
* (*pcFound
);
5492 *pcbNeeded
= data_offset
;
5494 for( i
= 0; i
< *pcFound
; i
++) {
5495 WCHAR DriverNameW
[255];
5496 PBYTE table_ptr
= NULL
;
5497 PBYTE data_ptr
= NULL
;
5500 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
5502 ERR("Can't enum key number %d\n", i
);
5503 RegCloseKey(hkeyDrivers
);
5507 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
5508 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
5509 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
5510 data_ptr
= pDriverInfo
+ *pcbNeeded
;
5512 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5513 env
, Level
, table_ptr
, data_ptr
,
5514 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5516 RegCloseKey(hkeyDrivers
);
5520 *pcbNeeded
+= needed
;
5523 RegCloseKey(hkeyDrivers
);
5525 if(cbBuf
< *pcbNeeded
){
5526 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5533 /*****************************************************************************
5534 * EnumPrinterDriversW [WINSPOOL.@]
5536 * see function EnumPrinterDrivers for RETURNS, BUGS
5538 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5539 LPBYTE pDriverInfo
, DWORD cbBuf
,
5540 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5542 static const WCHAR allW
[] = {'a','l','l',0};
5546 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
5548 SetLastError(RPC_X_NULL_REF_POINTER
);
5552 /* check for local drivers */
5553 if((pName
) && (pName
[0])) {
5554 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5555 SetLastError(ERROR_ACCESS_DENIED
);
5559 /* check input parameter */
5560 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5561 SetLastError(ERROR_INVALID_LEVEL
);
5565 if(pDriverInfo
&& cbBuf
> 0)
5566 memset( pDriverInfo
, 0, cbBuf
);
5568 /* Exception: pull all printers */
5569 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
5571 DWORD i
, needed
, bufsize
= cbBuf
;
5572 DWORD total_found
= 0;
5575 /* Precompute the overall total; we need this to know
5576 where pointers end and data begins (i.e. data_offset) */
5577 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5580 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5581 NULL
, 0, 0, &needed
, &found
, 0);
5582 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5583 total_found
+= found
;
5586 data_offset
= di_sizeof
[Level
] * total_found
;
5591 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5594 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5595 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
5596 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5598 *pcReturned
+= found
;
5599 *pcbNeeded
= needed
;
5600 data_offset
= needed
;
5601 total_found
+= found
;
5606 /* Normal behavior */
5607 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5608 0, cbBuf
, pcbNeeded
, &found
, 0);
5610 *pcReturned
= found
;
5615 /*****************************************************************************
5616 * EnumPrinterDriversA [WINSPOOL.@]
5618 * see function EnumPrinterDrivers for RETURNS, BUGS
5620 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5621 LPBYTE pDriverInfo
, DWORD cbBuf
,
5622 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5625 UNICODE_STRING pNameW
, pEnvironmentW
;
5626 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5630 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5632 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5633 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5635 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5636 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5638 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5640 HeapFree(GetProcessHeap(), 0, buf
);
5642 RtlFreeUnicodeString(&pNameW
);
5643 RtlFreeUnicodeString(&pEnvironmentW
);
5648 /******************************************************************************
5649 * EnumPortsA (WINSPOOL.@)
5654 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5655 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5658 LPBYTE bufferW
= NULL
;
5659 LPWSTR nameW
= NULL
;
5661 DWORD numentries
= 0;
5664 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5665 cbBuf
, pcbNeeded
, pcReturned
);
5667 /* convert servername to unicode */
5669 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5670 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5671 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5673 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5674 needed
= cbBuf
* sizeof(WCHAR
);
5675 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5676 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5678 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5679 if (pcbNeeded
) needed
= *pcbNeeded
;
5680 /* HeapReAlloc return NULL, when bufferW was NULL */
5681 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5682 HeapAlloc(GetProcessHeap(), 0, needed
);
5684 /* Try again with the large Buffer */
5685 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5687 needed
= pcbNeeded
? *pcbNeeded
: 0;
5688 numentries
= pcReturned
? *pcReturned
: 0;
5691 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5692 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5695 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5696 DWORD entrysize
= 0;
5699 LPPORT_INFO_2W pi2w
;
5700 LPPORT_INFO_2A pi2a
;
5703 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5705 /* First pass: calculate the size for all Entries */
5706 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5707 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5709 while (index
< numentries
) {
5711 needed
+= entrysize
; /* PORT_INFO_?A */
5712 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5714 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5715 NULL
, 0, NULL
, NULL
);
5717 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5718 NULL
, 0, NULL
, NULL
);
5719 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5720 NULL
, 0, NULL
, NULL
);
5722 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5723 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5724 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5727 /* check for errors and quit on failure */
5728 if (cbBuf
< needed
) {
5729 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5733 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5734 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5735 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5736 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5737 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5739 /* Second Pass: Fill the User Buffer (if we have one) */
5740 while ((index
< numentries
) && pPorts
) {
5742 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5743 pi2a
->pPortName
= ptr
;
5744 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5745 ptr
, cbBuf
, NULL
, NULL
);
5749 pi2a
->pMonitorName
= ptr
;
5750 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5751 ptr
, cbBuf
, NULL
, NULL
);
5755 pi2a
->pDescription
= ptr
;
5756 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5757 ptr
, cbBuf
, NULL
, NULL
);
5761 pi2a
->fPortType
= pi2w
->fPortType
;
5762 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5765 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5766 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5767 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5772 if (pcbNeeded
) *pcbNeeded
= needed
;
5773 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5775 HeapFree(GetProcessHeap(), 0, nameW
);
5776 HeapFree(GetProcessHeap(), 0, bufferW
);
5778 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5779 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5785 /******************************************************************************
5786 * EnumPortsW (WINSPOOL.@)
5788 * Enumerate available Ports
5791 * pName [I] Servername or NULL (local Computer)
5792 * Level [I] Structure-Level (1 or 2)
5793 * pPorts [O] PTR to Buffer that receives the Result
5794 * cbBuf [I] Size of Buffer at pPorts
5795 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5796 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5800 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5803 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5806 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5807 cbBuf
, pcbNeeded
, pcReturned
);
5809 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5811 /* Level is not checked in win9x */
5812 if (!Level
|| (Level
> 2)) {
5813 WARN("level (%d) is ignored in win9x\n", Level
);
5814 SetLastError(ERROR_INVALID_LEVEL
);
5817 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5818 SetLastError(RPC_X_NULL_REF_POINTER
);
5822 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5825 /******************************************************************************
5826 * GetDefaultPrinterW (WINSPOOL.@)
5829 * This function must read the value from data 'device' of key
5830 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5832 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5836 WCHAR
*buffer
, *ptr
;
5840 SetLastError(ERROR_INVALID_PARAMETER
);
5844 /* make the buffer big enough for the stuff from the profile/registry,
5845 * the content must fit into the local buffer to compute the correct
5846 * size even if the extern buffer is too small or not given.
5847 * (20 for ,driver,port) */
5849 len
= max(100, (insize
+ 20));
5850 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5852 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5854 SetLastError (ERROR_FILE_NOT_FOUND
);
5858 TRACE("%s\n", debugstr_w(buffer
));
5860 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5862 SetLastError(ERROR_INVALID_NAME
);
5868 *namesize
= strlenW(buffer
) + 1;
5869 if(!name
|| (*namesize
> insize
))
5871 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5875 strcpyW(name
, buffer
);
5878 HeapFree( GetProcessHeap(), 0, buffer
);
5883 /******************************************************************************
5884 * GetDefaultPrinterA (WINSPOOL.@)
5886 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5890 WCHAR
*bufferW
= NULL
;
5894 SetLastError(ERROR_INVALID_PARAMETER
);
5898 if(name
&& *namesize
) {
5900 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5903 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5908 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5912 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5915 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5918 HeapFree( GetProcessHeap(), 0, bufferW
);
5923 /******************************************************************************
5924 * SetDefaultPrinterW (WINSPOOL.204)
5926 * Set the Name of the Default Printer
5929 * pszPrinter [I] Name of the Printer or NULL
5936 * When the Parameter is NULL or points to an Empty String and
5937 * a Default Printer was already present, then this Function changes nothing.
5938 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5939 * the First enumerated local Printer is used.
5942 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5944 WCHAR default_printer
[MAX_PATH
];
5945 LPWSTR buffer
= NULL
;
5951 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5952 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5954 default_printer
[0] = '\0';
5955 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5957 /* if we have a default Printer, do nothing. */
5958 if (GetDefaultPrinterW(default_printer
, &size
))
5962 /* we have no default Printer: search local Printers and use the first */
5963 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
5965 default_printer
[0] = '\0';
5966 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5967 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
5969 pszPrinter
= default_printer
;
5970 TRACE("using %s\n", debugstr_w(pszPrinter
));
5975 if (pszPrinter
== NULL
) {
5976 TRACE("no local printer found\n");
5977 SetLastError(ERROR_FILE_NOT_FOUND
);
5982 /* "pszPrinter" is never empty or NULL here. */
5983 namelen
= lstrlenW(pszPrinter
);
5984 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5985 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5987 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
5988 HeapFree(GetProcessHeap(), 0, buffer
);
5989 SetLastError(ERROR_FILE_NOT_FOUND
);
5993 /* read the devices entry for the printer (driver,port) to build the string for the
5994 default device entry (printer,driver,port) */
5995 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
5996 buffer
[namelen
] = ',';
5997 namelen
++; /* move index to the start of the driver */
5999 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
6000 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
6002 TRACE("set device to %s\n", debugstr_w(buffer
));
6004 if (!WriteProfileStringW(windowsW
, deviceW
, buffer
)) {
6005 TRACE("failed to set the device entry: %d\n", GetLastError());
6006 lres
= ERROR_INVALID_PRINTER_NAME
;
6009 /* remove the next section, when INIFileMapping is implemented */
6012 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
)) {
6013 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (LPBYTE
)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
6020 if (lres
!= ERROR_FILE_NOT_FOUND
)
6021 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
6023 SetLastError(ERROR_INVALID_PRINTER_NAME
);
6027 HeapFree(GetProcessHeap(), 0, buffer
);
6028 return (lres
== ERROR_SUCCESS
);
6031 /******************************************************************************
6032 * SetDefaultPrinterA (WINSPOOL.202)
6034 * See SetDefaultPrinterW.
6037 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
6039 LPWSTR bufferW
= NULL
;
6042 TRACE("(%s)\n", debugstr_a(pszPrinter
));
6044 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
6045 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6046 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
6048 res
= SetDefaultPrinterW(bufferW
);
6049 HeapFree(GetProcessHeap(), 0, bufferW
);
6053 /******************************************************************************
6054 * SetPrinterDataExA (WINSPOOL.@)
6056 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6057 LPCSTR pValueName
, DWORD Type
,
6058 LPBYTE pData
, DWORD cbData
)
6060 HKEY hkeyPrinter
, hkeySubkey
;
6063 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
6064 debugstr_a(pValueName
), Type
, pData
, cbData
);
6066 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6070 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6072 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
6073 RegCloseKey(hkeyPrinter
);
6076 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6077 RegCloseKey(hkeySubkey
);
6078 RegCloseKey(hkeyPrinter
);
6082 /******************************************************************************
6083 * SetPrinterDataExW (WINSPOOL.@)
6085 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6086 LPCWSTR pValueName
, DWORD Type
,
6087 LPBYTE pData
, DWORD cbData
)
6089 HKEY hkeyPrinter
, hkeySubkey
;
6092 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
6093 debugstr_w(pValueName
), Type
, pData
, cbData
);
6095 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
6099 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
6101 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
6102 RegCloseKey(hkeyPrinter
);
6105 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
6106 RegCloseKey(hkeySubkey
);
6107 RegCloseKey(hkeyPrinter
);
6111 /******************************************************************************
6112 * SetPrinterDataA (WINSPOOL.@)
6114 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
6115 LPBYTE pData
, DWORD cbData
)
6117 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
6121 /******************************************************************************
6122 * SetPrinterDataW (WINSPOOL.@)
6124 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
6125 LPBYTE pData
, DWORD cbData
)
6127 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
6131 /******************************************************************************
6132 * GetPrinterDataExA (WINSPOOL.@)
6134 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6135 LPCSTR pValueName
, LPDWORD pType
,
6136 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6138 opened_printer_t
*printer
;
6139 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6142 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
6143 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6145 printer
= get_opened_printer(hPrinter
);
6146 if(!printer
) return ERROR_INVALID_HANDLE
;
6148 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6149 if (ret
) return ret
;
6151 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6153 if (printer
->name
) {
6155 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6157 RegCloseKey(hkeyPrinters
);
6160 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6161 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
6162 RegCloseKey(hkeyPrinter
);
6163 RegCloseKey(hkeyPrinters
);
6168 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6169 0, pType
, pData
, pcbNeeded
);
6171 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6173 RegCloseKey(hkeySubkey
);
6174 RegCloseKey(hkeyPrinter
);
6175 RegCloseKey(hkeyPrinters
);
6177 TRACE("--> %d\n", ret
);
6181 /******************************************************************************
6182 * GetPrinterDataExW (WINSPOOL.@)
6184 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6185 LPCWSTR pValueName
, LPDWORD pType
,
6186 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6188 opened_printer_t
*printer
;
6189 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
6192 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
6193 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
6195 printer
= get_opened_printer(hPrinter
);
6196 if(!printer
) return ERROR_INVALID_HANDLE
;
6198 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
6199 if (ret
) return ret
;
6201 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
6203 if (printer
->name
) {
6205 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
6207 RegCloseKey(hkeyPrinters
);
6210 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
6211 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
6212 RegCloseKey(hkeyPrinter
);
6213 RegCloseKey(hkeyPrinters
);
6218 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
6219 0, pType
, pData
, pcbNeeded
);
6221 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
6223 RegCloseKey(hkeySubkey
);
6224 RegCloseKey(hkeyPrinter
);
6225 RegCloseKey(hkeyPrinters
);
6227 TRACE("--> %d\n", ret
);
6231 /******************************************************************************
6232 * GetPrinterDataA (WINSPOOL.@)
6234 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
6235 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6237 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
6238 pData
, nSize
, pcbNeeded
);
6241 /******************************************************************************
6242 * GetPrinterDataW (WINSPOOL.@)
6244 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
6245 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
6247 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
6248 pData
, nSize
, pcbNeeded
);
6251 /*******************************************************************************
6252 * EnumPrinterDataExW [WINSPOOL.@]
6254 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
6255 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6256 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6258 HKEY hkPrinter
, hkSubKey
;
6259 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
6260 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
6265 PPRINTER_ENUM_VALUESW ppev
;
6267 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
6269 if (pKeyName
== NULL
|| *pKeyName
== 0)
6270 return ERROR_INVALID_PARAMETER
;
6272 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
6273 if (ret
!= ERROR_SUCCESS
)
6275 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6280 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
6281 if (ret
!= ERROR_SUCCESS
)
6283 r
= RegCloseKey (hkPrinter
);
6284 if (r
!= ERROR_SUCCESS
)
6285 WARN ("RegCloseKey returned %i\n", r
);
6286 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
6287 debugstr_w (pKeyName
), ret
);
6291 ret
= RegCloseKey (hkPrinter
);
6292 if (ret
!= ERROR_SUCCESS
)
6294 ERR ("RegCloseKey returned %i\n", ret
);
6295 r
= RegCloseKey (hkSubKey
);
6296 if (r
!= ERROR_SUCCESS
)
6297 WARN ("RegCloseKey returned %i\n", r
);
6301 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
6302 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
6303 if (ret
!= ERROR_SUCCESS
)
6305 r
= RegCloseKey (hkSubKey
);
6306 if (r
!= ERROR_SUCCESS
)
6307 WARN ("RegCloseKey returned %i\n", r
);
6308 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
6312 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6313 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
6315 if (cValues
== 0) /* empty key */
6317 r
= RegCloseKey (hkSubKey
);
6318 if (r
!= ERROR_SUCCESS
)
6319 WARN ("RegCloseKey returned %i\n", r
);
6320 *pcbEnumValues
= *pnEnumValues
= 0;
6321 return ERROR_SUCCESS
;
6324 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
6326 hHeap
= GetProcessHeap ();
6329 ERR ("GetProcessHeap failed\n");
6330 r
= RegCloseKey (hkSubKey
);
6331 if (r
!= ERROR_SUCCESS
)
6332 WARN ("RegCloseKey returned %i\n", r
);
6333 return ERROR_OUTOFMEMORY
;
6336 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
6337 if (lpValueName
== NULL
)
6339 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
6340 r
= RegCloseKey (hkSubKey
);
6341 if (r
!= ERROR_SUCCESS
)
6342 WARN ("RegCloseKey returned %i\n", r
);
6343 return ERROR_OUTOFMEMORY
;
6346 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
6347 if (lpValue
== NULL
)
6349 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
6350 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6351 WARN ("HeapFree failed with code %i\n", GetLastError ());
6352 r
= RegCloseKey (hkSubKey
);
6353 if (r
!= ERROR_SUCCESS
)
6354 WARN ("RegCloseKey returned %i\n", r
);
6355 return ERROR_OUTOFMEMORY
;
6358 TRACE ("pass 1: calculating buffer required for all names and values\n");
6360 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6362 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
6364 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6366 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6367 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6368 NULL
, NULL
, lpValue
, &cbValueLen
);
6369 if (ret
!= ERROR_SUCCESS
)
6371 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6372 WARN ("HeapFree failed with code %i\n", GetLastError ());
6373 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6374 WARN ("HeapFree failed with code %i\n", GetLastError ());
6375 r
= RegCloseKey (hkSubKey
);
6376 if (r
!= ERROR_SUCCESS
)
6377 WARN ("RegCloseKey returned %i\n", r
);
6378 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6382 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6383 debugstr_w (lpValueName
), dwIndex
,
6384 cbValueNameLen
+ 1, cbValueLen
);
6386 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6387 cbBufSize
+= cbValueLen
;
6390 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
6392 *pcbEnumValues
= cbBufSize
;
6393 *pnEnumValues
= cValues
;
6395 if (cbEnumValues
< cbBufSize
) /* buffer too small */
6397 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6398 WARN ("HeapFree failed with code %i\n", GetLastError ());
6399 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6400 WARN ("HeapFree failed with code %i\n", GetLastError ());
6401 r
= RegCloseKey (hkSubKey
);
6402 if (r
!= ERROR_SUCCESS
)
6403 WARN ("RegCloseKey returned %i\n", r
);
6404 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
6405 return ERROR_MORE_DATA
;
6408 TRACE ("pass 2: copying all names and values to buffer\n");
6410 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
6411 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6413 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6415 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6416 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6417 NULL
, &dwType
, lpValue
, &cbValueLen
);
6418 if (ret
!= ERROR_SUCCESS
)
6420 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6421 WARN ("HeapFree failed with code %i\n", GetLastError ());
6422 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6423 WARN ("HeapFree failed with code %i\n", GetLastError ());
6424 r
= RegCloseKey (hkSubKey
);
6425 if (r
!= ERROR_SUCCESS
)
6426 WARN ("RegCloseKey returned %i\n", r
);
6427 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6431 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6432 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
6433 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
6434 pEnumValues
+= cbValueNameLen
;
6436 /* return # of *bytes* (including trailing \0), not # of chars */
6437 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
6439 ppev
[dwIndex
].dwType
= dwType
;
6441 memcpy (pEnumValues
, lpValue
, cbValueLen
);
6442 ppev
[dwIndex
].pData
= pEnumValues
;
6443 pEnumValues
+= cbValueLen
;
6445 ppev
[dwIndex
].cbData
= cbValueLen
;
6447 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6448 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
6451 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6453 ret
= GetLastError ();
6454 ERR ("HeapFree failed with code %i\n", ret
);
6455 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6456 WARN ("HeapFree failed with code %i\n", GetLastError ());
6457 r
= RegCloseKey (hkSubKey
);
6458 if (r
!= ERROR_SUCCESS
)
6459 WARN ("RegCloseKey returned %i\n", r
);
6463 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6465 ret
= GetLastError ();
6466 ERR ("HeapFree failed with code %i\n", ret
);
6467 r
= RegCloseKey (hkSubKey
);
6468 if (r
!= ERROR_SUCCESS
)
6469 WARN ("RegCloseKey returned %i\n", r
);
6473 ret
= RegCloseKey (hkSubKey
);
6474 if (ret
!= ERROR_SUCCESS
)
6476 ERR ("RegCloseKey returned %i\n", ret
);
6480 return ERROR_SUCCESS
;
6483 /*******************************************************************************
6484 * EnumPrinterDataExA [WINSPOOL.@]
6486 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6487 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6488 * what Windows 2000 SP1 does.
6491 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6492 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6493 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6497 DWORD ret
, dwIndex
, dwBufSize
;
6501 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6503 if (pKeyName
== NULL
|| *pKeyName
== 0)
6504 return ERROR_INVALID_PARAMETER
;
6506 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6509 ret
= GetLastError ();
6510 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6514 hHeap
= GetProcessHeap ();
6517 ERR ("GetProcessHeap failed\n");
6518 return ERROR_OUTOFMEMORY
;
6521 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6522 if (pKeyNameW
== NULL
)
6524 ERR ("Failed to allocate %i bytes from process heap\n",
6525 (LONG
)(len
* sizeof (WCHAR
)));
6526 return ERROR_OUTOFMEMORY
;
6529 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6531 ret
= GetLastError ();
6532 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6533 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6534 WARN ("HeapFree failed with code %i\n", GetLastError ());
6538 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6539 pcbEnumValues
, pnEnumValues
);
6540 if (ret
!= ERROR_SUCCESS
)
6542 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6543 WARN ("HeapFree failed with code %i\n", GetLastError ());
6544 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6548 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6550 ret
= GetLastError ();
6551 ERR ("HeapFree failed with code %i\n", ret
);
6555 if (*pnEnumValues
== 0) /* empty key */
6556 return ERROR_SUCCESS
;
6559 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6561 PPRINTER_ENUM_VALUESW ppev
=
6562 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6564 if (dwBufSize
< ppev
->cbValueName
)
6565 dwBufSize
= ppev
->cbValueName
;
6567 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6568 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6569 dwBufSize
= ppev
->cbData
;
6572 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6574 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6575 if (pBuffer
== NULL
)
6577 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6578 return ERROR_OUTOFMEMORY
;
6581 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6583 PPRINTER_ENUM_VALUESW ppev
=
6584 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6586 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6587 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6591 ret
= GetLastError ();
6592 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6593 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6594 WARN ("HeapFree failed with code %i\n", GetLastError ());
6598 memcpy (ppev
->pValueName
, pBuffer
, len
);
6600 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6602 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6603 ppev
->dwType
!= REG_MULTI_SZ
)
6606 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6607 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6610 ret
= GetLastError ();
6611 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6612 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6613 WARN ("HeapFree failed with code %i\n", GetLastError ());
6617 memcpy (ppev
->pData
, pBuffer
, len
);
6619 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6620 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6623 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6625 ret
= GetLastError ();
6626 ERR ("HeapFree failed with code %i\n", ret
);
6630 return ERROR_SUCCESS
;
6633 /******************************************************************************
6634 * AbortPrinter (WINSPOOL.@)
6636 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6638 FIXME("(%p), stub!\n", hPrinter
);
6642 /******************************************************************************
6643 * AddPortA (WINSPOOL.@)
6648 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6650 LPWSTR nameW
= NULL
;
6651 LPWSTR monitorW
= NULL
;
6655 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6658 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6659 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6660 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6664 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6665 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6666 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6668 res
= AddPortW(nameW
, hWnd
, monitorW
);
6669 HeapFree(GetProcessHeap(), 0, nameW
);
6670 HeapFree(GetProcessHeap(), 0, monitorW
);
6674 /******************************************************************************
6675 * AddPortW (WINSPOOL.@)
6677 * Add a Port for a specific Monitor
6680 * pName [I] Servername or NULL (local Computer)
6681 * hWnd [I] Handle to parent Window for the Dialog-Box
6682 * pMonitorName [I] Name of the Monitor that manage the Port
6689 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6691 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6693 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6695 if (!pMonitorName
) {
6696 SetLastError(RPC_X_NULL_REF_POINTER
);
6700 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6703 /******************************************************************************
6704 * AddPortExA (WINSPOOL.@)
6709 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6712 PORT_INFO_2A
* pi2A
;
6713 LPWSTR nameW
= NULL
;
6714 LPWSTR monitorW
= NULL
;
6718 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6720 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6721 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6723 if ((level
< 1) || (level
> 2)) {
6724 SetLastError(ERROR_INVALID_LEVEL
);
6729 SetLastError(ERROR_INVALID_PARAMETER
);
6734 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6735 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6736 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6740 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6741 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6742 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6745 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6747 if (pi2A
->pPortName
) {
6748 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6749 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6750 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6754 if (pi2A
->pMonitorName
) {
6755 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6756 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6757 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6760 if (pi2A
->pDescription
) {
6761 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6762 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6763 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6765 pi2W
.fPortType
= pi2A
->fPortType
;
6766 pi2W
.Reserved
= pi2A
->Reserved
;
6769 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6771 HeapFree(GetProcessHeap(), 0, nameW
);
6772 HeapFree(GetProcessHeap(), 0, monitorW
);
6773 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6774 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6775 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6780 /******************************************************************************
6781 * AddPortExW (WINSPOOL.@)
6783 * Add a Port for a specific Monitor, without presenting a user interface
6786 * pName [I] Servername or NULL (local Computer)
6787 * level [I] Structure-Level (1 or 2) for pBuffer
6788 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6789 * pMonitorName [I] Name of the Monitor that manage the Port
6796 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6800 pi2
= (PORT_INFO_2W
*) pBuffer
;
6802 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6803 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6804 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6805 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6807 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6809 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6810 SetLastError(ERROR_INVALID_PARAMETER
);
6814 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6817 /******************************************************************************
6818 * AddPrinterConnectionA (WINSPOOL.@)
6820 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6822 FIXME("%s\n", debugstr_a(pName
));
6826 /******************************************************************************
6827 * AddPrinterConnectionW (WINSPOOL.@)
6829 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6831 FIXME("%s\n", debugstr_w(pName
));
6835 /******************************************************************************
6836 * AddPrinterDriverExW (WINSPOOL.@)
6838 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6841 * pName [I] Servername or NULL (local Computer)
6842 * level [I] Level for the supplied DRIVER_INFO_*W struct
6843 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6844 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6851 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6853 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6855 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6857 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6858 SetLastError(ERROR_INVALID_LEVEL
);
6863 SetLastError(ERROR_INVALID_PARAMETER
);
6867 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6870 /******************************************************************************
6871 * AddPrinterDriverExA (WINSPOOL.@)
6873 * See AddPrinterDriverExW.
6876 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6878 DRIVER_INFO_8A
*diA
;
6880 LPWSTR nameW
= NULL
;
6885 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6887 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6888 ZeroMemory(&diW
, sizeof(diW
));
6890 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6891 SetLastError(ERROR_INVALID_LEVEL
);
6896 SetLastError(ERROR_INVALID_PARAMETER
);
6900 /* convert servername to unicode */
6902 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6903 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6904 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6908 diW
.cVersion
= diA
->cVersion
;
6911 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6912 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6913 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6916 if (diA
->pEnvironment
) {
6917 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6918 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6919 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6922 if (diA
->pDriverPath
) {
6923 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6924 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6925 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6928 if (diA
->pDataFile
) {
6929 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6930 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6931 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6934 if (diA
->pConfigFile
) {
6935 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6936 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6937 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6940 if ((Level
> 2) && diA
->pDependentFiles
) {
6941 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6942 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6943 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6944 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6947 if ((Level
> 2) && diA
->pMonitorName
) {
6948 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6949 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6950 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6953 if ((Level
> 3) && diA
->pDefaultDataType
) {
6954 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6955 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6956 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6959 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6960 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6961 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6962 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6963 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6966 if ((Level
> 5) && diA
->pszMfgName
) {
6967 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6968 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6969 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6972 if ((Level
> 5) && diA
->pszOEMUrl
) {
6973 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6974 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6975 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6978 if ((Level
> 5) && diA
->pszHardwareID
) {
6979 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6980 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6981 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6984 if ((Level
> 5) && diA
->pszProvider
) {
6985 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6986 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6987 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6991 FIXME("level %u is incomplete\n", Level
);
6994 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6995 TRACE("got %u with %u\n", res
, GetLastError());
6996 HeapFree(GetProcessHeap(), 0, nameW
);
6997 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6998 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6999 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
7000 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
7001 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
7002 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
7003 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
7004 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
7005 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
7006 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
7007 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
7008 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
7009 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
7011 TRACE("=> %u with %u\n", res
, GetLastError());
7015 /******************************************************************************
7016 * ConfigurePortA (WINSPOOL.@)
7018 * See ConfigurePortW.
7021 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
7023 LPWSTR nameW
= NULL
;
7024 LPWSTR portW
= NULL
;
7028 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
7030 /* convert servername to unicode */
7032 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7033 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7034 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7037 /* convert portname to unicode */
7039 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
7040 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7041 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
7044 res
= ConfigurePortW(nameW
, hWnd
, portW
);
7045 HeapFree(GetProcessHeap(), 0, nameW
);
7046 HeapFree(GetProcessHeap(), 0, portW
);
7050 /******************************************************************************
7051 * ConfigurePortW (WINSPOOL.@)
7053 * Display the Configuration-Dialog for a specific Port
7056 * pName [I] Servername or NULL (local Computer)
7057 * hWnd [I] Handle to parent Window for the Dialog-Box
7058 * pPortName [I] Name of the Port, that should be configured
7065 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
7068 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
7070 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7073 SetLastError(RPC_X_NULL_REF_POINTER
);
7077 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
7080 /******************************************************************************
7081 * ConnectToPrinterDlg (WINSPOOL.@)
7083 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
7085 FIXME("%p %x\n", hWnd
, Flags
);
7089 /******************************************************************************
7090 * DeletePrinterConnectionA (WINSPOOL.@)
7092 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
7094 FIXME("%s\n", debugstr_a(pName
));
7098 /******************************************************************************
7099 * DeletePrinterConnectionW (WINSPOOL.@)
7101 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
7103 FIXME("%s\n", debugstr_w(pName
));
7107 /******************************************************************************
7108 * DeletePrinterDriverExW (WINSPOOL.@)
7110 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
7111 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7116 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7117 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
7119 if(pName
&& pName
[0])
7121 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
7122 SetLastError(ERROR_INVALID_PARAMETER
);
7128 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
7129 SetLastError(ERROR_INVALID_PARAMETER
);
7133 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
7137 ERR("Can't open drivers key\n");
7141 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
7144 RegCloseKey(hkey_drivers
);
7149 /******************************************************************************
7150 * DeletePrinterDriverExA (WINSPOOL.@)
7152 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
7153 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
7155 UNICODE_STRING NameW
, EnvW
, DriverW
;
7158 asciitounicode(&NameW
, pName
);
7159 asciitounicode(&EnvW
, pEnvironment
);
7160 asciitounicode(&DriverW
, pDriverName
);
7162 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
7164 RtlFreeUnicodeString(&DriverW
);
7165 RtlFreeUnicodeString(&EnvW
);
7166 RtlFreeUnicodeString(&NameW
);
7171 /******************************************************************************
7172 * DeletePrinterDataExW (WINSPOOL.@)
7174 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
7177 FIXME("%p %s %s\n", hPrinter
,
7178 debugstr_w(pKeyName
), debugstr_w(pValueName
));
7179 return ERROR_INVALID_PARAMETER
;
7182 /******************************************************************************
7183 * DeletePrinterDataExA (WINSPOOL.@)
7185 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
7188 FIXME("%p %s %s\n", hPrinter
,
7189 debugstr_a(pKeyName
), debugstr_a(pValueName
));
7190 return ERROR_INVALID_PARAMETER
;
7193 /******************************************************************************
7194 * DeletePrintProcessorA (WINSPOOL.@)
7196 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
7198 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7199 debugstr_a(pPrintProcessorName
));
7203 /******************************************************************************
7204 * DeletePrintProcessorW (WINSPOOL.@)
7206 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
7208 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7209 debugstr_w(pPrintProcessorName
));
7213 /******************************************************************************
7214 * DeletePrintProvidorA (WINSPOOL.@)
7216 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
7218 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7219 debugstr_a(pPrintProviderName
));
7223 /******************************************************************************
7224 * DeletePrintProvidorW (WINSPOOL.@)
7226 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
7228 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7229 debugstr_w(pPrintProviderName
));
7233 /******************************************************************************
7234 * EnumFormsA (WINSPOOL.@)
7236 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7237 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7239 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7240 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7244 /******************************************************************************
7245 * EnumFormsW (WINSPOOL.@)
7247 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7248 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7250 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7251 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7255 /*****************************************************************************
7256 * EnumMonitorsA [WINSPOOL.@]
7258 * See EnumMonitorsW.
7261 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7262 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7265 LPBYTE bufferW
= NULL
;
7266 LPWSTR nameW
= NULL
;
7268 DWORD numentries
= 0;
7271 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
7272 cbBuf
, pcbNeeded
, pcReturned
);
7274 /* convert servername to unicode */
7276 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7277 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7278 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7280 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7281 needed
= cbBuf
* sizeof(WCHAR
);
7282 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7283 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7285 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7286 if (pcbNeeded
) needed
= *pcbNeeded
;
7287 /* HeapReAlloc return NULL, when bufferW was NULL */
7288 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7289 HeapAlloc(GetProcessHeap(), 0, needed
);
7291 /* Try again with the large Buffer */
7292 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7294 numentries
= pcReturned
? *pcReturned
: 0;
7297 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7298 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7301 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7302 DWORD entrysize
= 0;
7305 LPMONITOR_INFO_2W mi2w
;
7306 LPMONITOR_INFO_2A mi2a
;
7308 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7309 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
7311 /* First pass: calculate the size for all Entries */
7312 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7313 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7315 while (index
< numentries
) {
7317 needed
+= entrysize
; /* MONITOR_INFO_?A */
7318 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
7320 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7321 NULL
, 0, NULL
, NULL
);
7323 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7324 NULL
, 0, NULL
, NULL
);
7325 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7326 NULL
, 0, NULL
, NULL
);
7328 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7329 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7330 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7333 /* check for errors and quit on failure */
7334 if (cbBuf
< needed
) {
7335 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7339 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
7340 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
7341 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7342 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7343 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7345 /* Second Pass: Fill the User Buffer (if we have one) */
7346 while ((index
< numentries
) && pMonitors
) {
7348 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7350 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7351 ptr
, cbBuf
, NULL
, NULL
);
7355 mi2a
->pEnvironment
= ptr
;
7356 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7357 ptr
, cbBuf
, NULL
, NULL
);
7361 mi2a
->pDLLName
= ptr
;
7362 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7363 ptr
, cbBuf
, NULL
, NULL
);
7367 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7368 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7369 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7373 if (pcbNeeded
) *pcbNeeded
= needed
;
7374 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7376 HeapFree(GetProcessHeap(), 0, nameW
);
7377 HeapFree(GetProcessHeap(), 0, bufferW
);
7379 TRACE("returning %d with %d (%d byte for %d entries)\n",
7380 (res
), GetLastError(), needed
, numentries
);
7386 /*****************************************************************************
7387 * EnumMonitorsW [WINSPOOL.@]
7389 * Enumerate available Port-Monitors
7392 * pName [I] Servername or NULL (local Computer)
7393 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7394 * pMonitors [O] PTR to Buffer that receives the Result
7395 * cbBuf [I] Size of Buffer at pMonitors
7396 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7397 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7401 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7404 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7405 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7408 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7409 cbBuf
, pcbNeeded
, pcReturned
);
7411 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7413 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
7414 SetLastError(RPC_X_NULL_REF_POINTER
);
7418 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
7421 /******************************************************************************
7422 * SpoolerInit (WINSPOOL.@)
7424 * Initialize the Spooler
7431 * The function fails on windows, when the spooler service is not running
7434 BOOL WINAPI
SpoolerInit(void)
7437 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7441 /******************************************************************************
7442 * XcvDataW (WINSPOOL.@)
7444 * Execute commands in the Printmonitor DLL
7447 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7448 * pszDataName [i] Name of the command to execute
7449 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7450 * cbInputData [i] Size in Bytes of Buffer at pInputData
7451 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7452 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7453 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7454 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7461 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7462 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7464 * Minimal List of commands, that a Printmonitor DLL should support:
7466 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7467 *| "AddPort" : Add a Port
7468 *| "DeletePort": Delete a Port
7470 * Many Printmonitors support additional commands. Examples for localspl.dll:
7471 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7472 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7475 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7476 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7477 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7479 opened_printer_t
*printer
;
7481 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7482 pInputData
, cbInputData
, pOutputData
,
7483 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7485 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7487 printer
= get_opened_printer(hXcv
);
7488 if (!printer
|| (!printer
->backend_printer
)) {
7489 SetLastError(ERROR_INVALID_HANDLE
);
7493 if (!pcbOutputNeeded
) {
7494 SetLastError(ERROR_INVALID_PARAMETER
);
7498 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7499 SetLastError(RPC_X_NULL_REF_POINTER
);
7503 *pcbOutputNeeded
= 0;
7505 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
7506 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7510 /*****************************************************************************
7511 * EnumPrinterDataA [WINSPOOL.@]
7514 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7515 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7516 DWORD cbData
, LPDWORD pcbData
)
7518 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7519 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7520 return ERROR_NO_MORE_ITEMS
;
7523 /*****************************************************************************
7524 * EnumPrinterDataW [WINSPOOL.@]
7527 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7528 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7529 DWORD cbData
, LPDWORD pcbData
)
7531 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7532 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7533 return ERROR_NO_MORE_ITEMS
;
7536 /*****************************************************************************
7537 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7540 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7541 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7542 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7544 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7545 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7546 pcbNeeded
, pcReturned
);
7550 /*****************************************************************************
7551 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7554 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7555 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7556 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7558 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7559 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7560 pcbNeeded
, pcReturned
);
7564 /*****************************************************************************
7565 * EnumPrintProcessorsA [WINSPOOL.@]
7567 * See EnumPrintProcessorsW.
7570 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7571 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7574 LPBYTE bufferW
= NULL
;
7575 LPWSTR nameW
= NULL
;
7578 DWORD numentries
= 0;
7581 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7582 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7584 /* convert names to unicode */
7586 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7587 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7588 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7591 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
7592 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7593 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
7596 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7597 needed
= cbBuf
* sizeof(WCHAR
);
7598 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7599 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7601 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7602 if (pcbNeeded
) needed
= *pcbNeeded
;
7603 /* HeapReAlloc return NULL, when bufferW was NULL */
7604 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7605 HeapAlloc(GetProcessHeap(), 0, needed
);
7607 /* Try again with the large Buffer */
7608 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7610 numentries
= pcReturned
? *pcReturned
: 0;
7614 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7617 PPRINTPROCESSOR_INFO_1W ppiw
;
7618 PPRINTPROCESSOR_INFO_1A ppia
;
7620 /* First pass: calculate the size for all Entries */
7621 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7622 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7624 while (index
< numentries
) {
7626 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7627 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7629 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7630 NULL
, 0, NULL
, NULL
);
7632 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7633 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7636 /* check for errors and quit on failure */
7637 if (cbBuf
< needed
) {
7638 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7643 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7644 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7645 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7646 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7647 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7649 /* Second Pass: Fill the User Buffer (if we have one) */
7650 while ((index
< numentries
) && pPPInfo
) {
7652 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7654 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7655 ptr
, cbBuf
, NULL
, NULL
);
7659 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7660 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7665 if (pcbNeeded
) *pcbNeeded
= needed
;
7666 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7668 HeapFree(GetProcessHeap(), 0, nameW
);
7669 HeapFree(GetProcessHeap(), 0, envW
);
7670 HeapFree(GetProcessHeap(), 0, bufferW
);
7672 TRACE("returning %d with %d (%d byte for %d entries)\n",
7673 (res
), GetLastError(), needed
, numentries
);
7678 /*****************************************************************************
7679 * EnumPrintProcessorsW [WINSPOOL.@]
7681 * Enumerate available Print Processors
7684 * pName [I] Servername or NULL (local Computer)
7685 * pEnvironment [I] Printing-Environment or NULL (Default)
7686 * Level [I] Structure-Level (Only 1 is allowed)
7687 * pPPInfo [O] PTR to Buffer that receives the Result
7688 * cbBuf [I] Size of Buffer at pPPInfo
7689 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7690 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7694 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7697 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7698 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7701 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7702 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7704 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7706 if (!pcbNeeded
|| !pcReturned
) {
7707 SetLastError(RPC_X_NULL_REF_POINTER
);
7711 if (!pPPInfo
&& (cbBuf
> 0)) {
7712 SetLastError(ERROR_INVALID_USER_BUFFER
);
7716 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7717 cbBuf
, pcbNeeded
, pcReturned
);
7720 /*****************************************************************************
7721 * ExtDeviceMode [WINSPOOL.@]
7724 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7725 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7728 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7729 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7730 debugstr_a(pProfile
), fMode
);
7734 /*****************************************************************************
7735 * FindClosePrinterChangeNotification [WINSPOOL.@]
7738 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7740 FIXME("Stub: %p\n", hChange
);
7744 /*****************************************************************************
7745 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7748 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7749 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7751 FIXME("Stub: %p %x %x %p\n",
7752 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7753 return INVALID_HANDLE_VALUE
;
7756 /*****************************************************************************
7757 * FindNextPrinterChangeNotification [WINSPOOL.@]
7760 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7761 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7763 FIXME("Stub: %p %p %p %p\n",
7764 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7768 /*****************************************************************************
7769 * FreePrinterNotifyInfo [WINSPOOL.@]
7772 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7774 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7778 /*****************************************************************************
7781 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7782 * ansi depending on the unicode parameter.
7784 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7794 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7797 memcpy(ptr
, str
, *size
);
7804 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7807 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7814 /*****************************************************************************
7817 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7818 LPDWORD pcbNeeded
, BOOL unicode
)
7820 DWORD size
, left
= cbBuf
;
7821 BOOL space
= (cbBuf
> 0);
7828 ji1
->JobId
= job
->job_id
;
7831 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7832 if(space
&& size
<= left
)
7834 ji1
->pDocument
= (LPWSTR
)ptr
;
7842 if (job
->printer_name
)
7844 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7845 if(space
&& size
<= left
)
7847 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7859 /*****************************************************************************
7862 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7863 LPDWORD pcbNeeded
, BOOL unicode
)
7865 DWORD size
, left
= cbBuf
;
7867 BOOL space
= (cbBuf
> 0);
7869 LPDEVMODEA dmA
= NULL
;
7876 ji2
->JobId
= job
->job_id
;
7879 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7880 if(space
&& size
<= left
)
7882 ji2
->pDocument
= (LPWSTR
)ptr
;
7890 if (job
->printer_name
)
7892 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7893 if(space
&& size
<= left
)
7895 ji2
->pPrinterName
= (LPWSTR
)ptr
;
7908 dmA
= DEVMODEdupWtoA(job
->devmode
);
7909 devmode
= (LPDEVMODEW
) dmA
;
7910 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
7914 devmode
= job
->devmode
;
7915 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
7919 FIXME("Can't convert DEVMODE W to A\n");
7922 /* align DEVMODE to a DWORD boundary */
7923 shift
= (4 - (*pcbNeeded
& 3)) & 3;
7929 memcpy(ptr
, devmode
, size
-shift
);
7930 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
7931 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
7944 /*****************************************************************************
7947 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7948 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7951 DWORD needed
= 0, size
;
7955 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7957 EnterCriticalSection(&printer_handles_cs
);
7958 job
= get_job(hPrinter
, JobId
);
7965 size
= sizeof(JOB_INFO_1W
);
7970 memset(pJob
, 0, size
);
7974 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7979 size
= sizeof(JOB_INFO_2W
);
7984 memset(pJob
, 0, size
);
7988 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7993 size
= sizeof(JOB_INFO_3
);
7997 memset(pJob
, 0, size
);
8006 SetLastError(ERROR_INVALID_LEVEL
);
8010 *pcbNeeded
= needed
;
8012 LeaveCriticalSection(&printer_handles_cs
);
8016 /*****************************************************************************
8017 * GetJobA [WINSPOOL.@]
8020 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8021 DWORD cbBuf
, LPDWORD pcbNeeded
)
8023 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
8026 /*****************************************************************************
8027 * GetJobW [WINSPOOL.@]
8030 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
8031 DWORD cbBuf
, LPDWORD pcbNeeded
)
8033 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
8036 /*****************************************************************************
8039 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
8042 char *unixname
, *cmdA
;
8044 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
8050 if(!(unixname
= wine_get_unix_file_name(filename
)))
8053 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
8054 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
8055 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
8057 TRACE("printing with: %s\n", cmdA
);
8059 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
8064 ERR("pipe() failed!\n");
8068 if ((pid
= fork()) == 0)
8074 /* reset signals that we previously set to SIG_IGN */
8075 signal(SIGPIPE
, SIG_DFL
);
8077 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
8082 ERR("fork() failed!\n");
8088 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
8089 write(fds
[1], buf
, no_read
);
8096 wret
= waitpid(pid
, &status
, 0);
8097 } while (wret
< 0 && errno
== EINTR
);
8100 ERR("waitpid() failed!\n");
8103 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
8105 ERR("child process failed! %d\n", status
);
8112 if(file_fd
!= -1) close(file_fd
);
8113 if(fds
[0] != -1) close(fds
[0]);
8114 if(fds
[1] != -1) close(fds
[1]);
8116 HeapFree(GetProcessHeap(), 0, cmdA
);
8117 HeapFree(GetProcessHeap(), 0, unixname
);
8124 /*****************************************************************************
8127 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
8130 const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
8133 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
8134 sprintfW(cmd
, fmtW
, printer_name
);
8136 r
= schedule_pipe(cmd
, filename
);
8138 HeapFree(GetProcessHeap(), 0, cmd
);
8142 #ifdef SONAME_LIBCUPS
8143 /*****************************************************************************
8144 * get_cups_jobs_ticket_options
8146 * Explicitly set CUPS options based on any %cupsJobTicket lines.
8147 * The CUPS scheduler only looks for these in Print-File requests, and since
8148 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
8151 static int get_cups_job_ticket_options( const char *file
, int num_options
, cups_option_t
**options
)
8153 FILE *fp
= fopen( file
, "r" );
8154 char buf
[257]; /* DSC max of 256 + '\0' */
8155 const char *ps_adobe
= "%!PS-Adobe-";
8156 const char *cups_job
= "%cupsJobTicket:";
8158 if (!fp
) return num_options
;
8159 if (!fgets( buf
, sizeof(buf
), fp
)) goto end
;
8160 if (strncmp( buf
, ps_adobe
, strlen( ps_adobe
) )) goto end
;
8161 while (fgets( buf
, sizeof(buf
), fp
))
8163 if (strncmp( buf
, cups_job
, strlen( cups_job
) )) break;
8164 num_options
= pcupsParseOptions( buf
+ strlen( cups_job
), num_options
, options
);
8172 static int get_cups_default_options( const char *printer
, int num_options
, cups_option_t
**options
)
8177 if (!pcupsGetNamedDest
) return num_options
;
8179 dest
= pcupsGetNamedDest( NULL
, printer
, NULL
);
8180 if (!dest
) return num_options
;
8182 for (i
= 0; i
< dest
->num_options
; i
++)
8184 if (!pcupsGetOption( dest
->options
[i
].name
, num_options
, *options
))
8185 num_options
= pcupsAddOption( dest
->options
[i
].name
, dest
->options
[i
].value
,
8186 num_options
, options
);
8189 pcupsFreeDests( 1, dest
);
8194 /*****************************************************************************
8197 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
8199 #ifdef SONAME_LIBCUPS
8202 char *unixname
, *queue
, *unix_doc_title
;
8205 int num_options
= 0, i
;
8206 cups_option_t
*options
= NULL
;
8208 if(!(unixname
= wine_get_unix_file_name(filename
)))
8211 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
8212 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
8213 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
8215 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
8216 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
8217 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
8219 num_options
= get_cups_job_ticket_options( unixname
, num_options
, &options
);
8220 num_options
= get_cups_default_options( queue
, num_options
, &options
);
8222 TRACE( "printing via cups with options:\n" );
8223 for (i
= 0; i
< num_options
; i
++)
8224 TRACE( "\t%d: %s = %s\n", i
, options
[i
].name
, options
[i
].value
);
8226 ret
= pcupsPrintFile( queue
, unixname
, unix_doc_title
, num_options
, options
);
8228 pcupsFreeOptions( num_options
, options
);
8230 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
8231 HeapFree(GetProcessHeap(), 0, queue
);
8232 HeapFree(GetProcessHeap(), 0, unixname
);
8238 return schedule_lpr(printer_name
, filename
);
8242 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
8249 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
8253 if(HIWORD(wparam
) == BN_CLICKED
)
8255 if(LOWORD(wparam
) == IDOK
)
8258 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
8261 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
8262 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
8264 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
8266 WCHAR caption
[200], message
[200];
8269 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
8270 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
8271 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
8272 if(mb_ret
== IDCANCEL
)
8274 HeapFree(GetProcessHeap(), 0, filename
);
8278 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
8279 if(hf
== INVALID_HANDLE_VALUE
)
8281 WCHAR caption
[200], message
[200];
8283 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
8284 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
8285 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
8286 HeapFree(GetProcessHeap(), 0, filename
);
8290 DeleteFileW(filename
);
8291 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
8293 EndDialog(hwnd
, IDOK
);
8296 if(LOWORD(wparam
) == IDCANCEL
)
8298 EndDialog(hwnd
, IDCANCEL
);
8307 /*****************************************************************************
8310 static BOOL
get_filename(LPWSTR
*filename
)
8312 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
8313 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
8316 /*****************************************************************************
8319 static BOOL
schedule_file(LPCWSTR filename
)
8321 LPWSTR output
= NULL
;
8323 if(get_filename(&output
))
8326 TRACE("copy to %s\n", debugstr_w(output
));
8327 r
= CopyFileW(filename
, output
, FALSE
);
8328 HeapFree(GetProcessHeap(), 0, output
);
8334 /*****************************************************************************
8337 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
8339 int in_fd
, out_fd
, no_read
;
8342 char *unixname
, *outputA
;
8345 if(!(unixname
= wine_get_unix_file_name(filename
)))
8348 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
8349 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
8350 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
8352 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
8353 in_fd
= open(unixname
, O_RDONLY
);
8354 if(out_fd
== -1 || in_fd
== -1)
8357 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
8358 write(out_fd
, buf
, no_read
);
8362 if(in_fd
!= -1) close(in_fd
);
8363 if(out_fd
!= -1) close(out_fd
);
8364 HeapFree(GetProcessHeap(), 0, outputA
);
8365 HeapFree(GetProcessHeap(), 0, unixname
);
8369 /*****************************************************************************
8370 * ScheduleJob [WINSPOOL.@]
8373 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
8375 opened_printer_t
*printer
;
8377 struct list
*cursor
, *cursor2
;
8379 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
8380 EnterCriticalSection(&printer_handles_cs
);
8381 printer
= get_opened_printer(hPrinter
);
8385 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
8387 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
8390 if(job
->job_id
!= dwJobID
) continue;
8392 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
8393 if(hf
!= INVALID_HANDLE_VALUE
)
8395 PRINTER_INFO_5W
*pi5
= NULL
;
8396 LPWSTR portname
= job
->portname
;
8400 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8401 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8405 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
8406 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
8407 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
8408 portname
= pi5
->pPortName
;
8410 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
8411 debugstr_w(portname
));
8415 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8416 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
8418 DWORD type
, count
= sizeof(output
);
8419 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
8422 if(output
[0] == '|')
8424 ret
= schedule_pipe(output
+ 1, job
->filename
);
8428 ret
= schedule_unixfile(output
, job
->filename
);
8430 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
8432 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
8434 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
8436 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
8438 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
8440 ret
= schedule_file(job
->filename
);
8444 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
8446 HeapFree(GetProcessHeap(), 0, pi5
);
8448 DeleteFileW(job
->filename
);
8450 list_remove(cursor
);
8451 HeapFree(GetProcessHeap(), 0, job
->document_title
);
8452 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
8453 HeapFree(GetProcessHeap(), 0, job
->portname
);
8454 HeapFree(GetProcessHeap(), 0, job
->filename
);
8455 HeapFree(GetProcessHeap(), 0, job
->devmode
);
8456 HeapFree(GetProcessHeap(), 0, job
);
8460 LeaveCriticalSection(&printer_handles_cs
);
8464 /*****************************************************************************
8465 * StartDocDlgA [WINSPOOL.@]
8467 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
8469 UNICODE_STRING usBuffer
;
8472 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
8475 docW
.cbSize
= sizeof(docW
);
8476 if (doc
->lpszDocName
)
8478 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
8479 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
8481 if (doc
->lpszOutput
)
8483 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
8484 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
8486 if (doc
->lpszDatatype
)
8488 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
8489 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
8491 docW
.fwType
= doc
->fwType
;
8493 retW
= StartDocDlgW(hPrinter
, &docW
);
8497 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
8498 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
8499 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
8500 HeapFree(GetProcessHeap(), 0, retW
);
8503 HeapFree(GetProcessHeap(), 0, datatypeW
);
8504 HeapFree(GetProcessHeap(), 0, outputW
);
8505 HeapFree(GetProcessHeap(), 0, docnameW
);
8510 /*****************************************************************************
8511 * StartDocDlgW [WINSPOOL.@]
8513 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8514 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8515 * port is "FILE:". Also returns the full path if passed a relative path.
8517 * The caller should free the returned string from the process heap.
8519 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
8524 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
8526 PRINTER_INFO_5W
*pi5
;
8527 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
8528 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
8530 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
8531 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
8532 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
8534 HeapFree(GetProcessHeap(), 0, pi5
);
8537 HeapFree(GetProcessHeap(), 0, pi5
);
8540 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
8544 if (get_filename(&name
))
8546 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
8548 HeapFree(GetProcessHeap(), 0, name
);
8551 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8552 GetFullPathNameW(name
, len
, ret
, NULL
);
8553 HeapFree(GetProcessHeap(), 0, name
);
8558 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8561 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8562 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8564 attr
= GetFileAttributesW(ret
);
8565 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8567 HeapFree(GetProcessHeap(), 0, ret
);