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 #define NONAMELESSUNION
49 #define NONAMELESSSTRUCT
50 #include "wine/library.h"
59 #include "wine/windef16.h"
60 #include "wine/unicode.h"
61 #include "wine/debug.h"
62 #include "wine/list.h"
65 #include "ddk/winsplp.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
70 /* ############################### */
72 static CRITICAL_SECTION printer_handles_cs
;
73 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
75 0, 0, &printer_handles_cs
,
76 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
77 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
79 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
81 /* ############################### */
96 HANDLE backend_printer
;
107 WCHAR
*document_title
;
117 LPCWSTR versionregpath
;
118 LPCWSTR versionsubdir
;
121 /* ############################### */
123 static opened_printer_t
**printer_handles
;
124 static UINT nb_printer_handles
;
125 static LONG next_job_id
= 1;
127 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
128 WORD fwCapability
, LPSTR lpszOutput
,
130 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
131 LPSTR lpszDevice
, LPSTR lpszPort
,
132 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
135 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
136 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
137 'c','o','n','t','r','o','l','\\',
138 'P','r','i','n','t','\\',
139 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
140 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
142 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
143 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
144 'C','o','n','t','r','o','l','\\',
145 'P','r','i','n','t','\\',
146 'P','r','i','n','t','e','r','s',0};
148 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
150 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
151 'M','i','c','r','o','s','o','f','t','\\',
152 'W','i','n','d','o','w','s',' ','N','T','\\',
153 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
154 'W','i','n','d','o','w','s',0};
156 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
157 'M','i','c','r','o','s','o','f','t','\\',
158 'W','i','n','d','o','w','s',' ','N','T','\\',
159 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
160 'D','e','v','i','c','e','s',0};
162 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
163 'M','i','c','r','o','s','o','f','t','\\',
164 'W','i','n','d','o','w','s',' ','N','T','\\',
165 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
166 'P','o','r','t','s',0};
168 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
169 'M','i','c','r','o','s','o','f','t','\\',
170 'W','i','n','d','o','w','s',' ','N','T','\\',
171 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
172 'P','r','i','n','t','e','r','P','o','r','t','s',0};
174 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
175 static WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
176 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
177 static WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
178 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
179 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
180 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
181 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
182 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
183 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
184 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
186 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
188 static const WCHAR AttributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0};
189 static const WCHAR backslashW
[] = {'\\',0};
190 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
191 'i','o','n',' ','F','i','l','e',0};
192 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
193 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
194 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
195 static const WCHAR Default_PriorityW
[] = {'D','e','f','a','u','l','t',' ','P','r','i','o','r','i','t','y',0};
196 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
197 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
198 static const WCHAR dnsTimeoutW
[] = {'d','n','s','T','i','m','e','o','u','t',0};
199 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
200 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
201 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
202 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
203 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
204 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
205 static const WCHAR NameW
[] = {'N','a','m','e',0};
206 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
207 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
208 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
209 static const WCHAR PortW
[] = {'P','o','r','t',0};
210 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
211 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
212 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
213 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
214 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
215 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
216 static const WCHAR PriorityW
[] = {'P','r','i','o','r','i','t','y',0};
217 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
218 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
219 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
220 static const WCHAR StartTimeW
[] = {'S','t','a','r','t','T','i','m','e',0};
221 static const WCHAR StatusW
[] = {'S','t','a','t','u','s',0};
222 static const WCHAR txTimeoutW
[] = {'t','x','T','i','m','e','o','u','t',0};
223 static const WCHAR UntilTimeW
[] = {'U','n','t','i','l','T','i','m','e',0};
224 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
225 static WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
226 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
227 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
228 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
229 static WCHAR generic_ppdW
[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
230 static WCHAR rawW
[] = {'R','A','W',0};
231 static WCHAR driver_9x
[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
232 static WCHAR driver_nt
[] = {'w','i','n','e','p','s','.','d','r','v',0};
233 static const WCHAR timeout_15_45
[] = {',','1','5',',','4','5',0};
234 static const WCHAR commaW
[] = {',',0};
235 static WCHAR emptyStringW
[] = {0};
237 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
239 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
240 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
241 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
243 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
244 'D','o','c','u','m','e','n','t',0};
246 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
247 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
248 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
249 0, sizeof(DRIVER_INFO_8W
)};
252 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
253 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
254 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
255 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
256 sizeof(PRINTER_INFO_9W
)};
258 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
259 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
260 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
262 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
264 /******************************************************************
265 * validate the user-supplied printing-environment [internal]
268 * env [I] PTR to Environment-String or NULL
272 * Success: PTR to printenv_t
275 * An empty string is handled the same way as NULL.
276 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
280 static const printenv_t
* validate_envW(LPCWSTR env
)
282 const printenv_t
*result
= NULL
;
285 TRACE("testing %s\n", debugstr_w(env
));
288 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
290 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
292 result
= all_printenv
[i
];
297 if (result
== NULL
) {
298 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
299 SetLastError(ERROR_INVALID_ENVIRONMENT
);
301 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
305 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
307 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
313 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
314 if passed a NULL string. This returns NULLs to the result.
316 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
320 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
321 return usBufferPtr
->Buffer
;
323 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
327 static LPWSTR
strdupW(LPCWSTR p
)
333 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
334 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
339 static LPSTR
strdupWtoA( LPCWSTR str
)
344 if (!str
) return NULL
;
345 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
346 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
347 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
351 static DEVMODEW
*dup_devmode( const DEVMODEW
*dm
)
355 if (!dm
) return NULL
;
356 ret
= HeapAlloc( GetProcessHeap(), 0, dm
->dmSize
+ dm
->dmDriverExtra
);
357 if (ret
) memcpy( ret
, dm
, dm
->dmSize
+ dm
->dmDriverExtra
);
361 /***********************************************************
363 * Creates an ansi copy of supplied devmode
365 static DEVMODEA
*DEVMODEdupWtoA( const DEVMODEW
*dmW
)
370 if (!dmW
) return NULL
;
371 size
= dmW
->dmSize
- CCHDEVICENAME
-
372 ((dmW
->dmSize
> FIELD_OFFSET( DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
374 dmA
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
375 if (!dmA
) return NULL
;
377 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmDeviceName
, -1,
378 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
380 if (FIELD_OFFSET( DEVMODEW
, dmFormName
) >= dmW
->dmSize
)
382 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
383 dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
387 memcpy( &dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
388 FIELD_OFFSET( DEVMODEW
, dmFormName
) - FIELD_OFFSET( DEVMODEW
, dmSpecVersion
) );
389 WideCharToMultiByte( CP_ACP
, 0, dmW
->dmFormName
, -1,
390 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
392 memcpy( &dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET( DEVMODEW
, dmLogPixels
) );
396 memcpy( (char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
401 /******************************************************************
402 * verify, that the filename is a local file
405 static inline BOOL
is_local_file(LPWSTR name
)
407 return (name
[0] && (name
[1] == ':') && (name
[2] == '\\'));
410 /* ################################ */
412 static int multi_sz_lenA(const char *str
)
414 const char *ptr
= str
;
418 ptr
+= lstrlenA(ptr
) + 1;
421 return ptr
- str
+ 1;
425 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
428 /* If forcing, or no profile string entry for device yet, set the entry
430 * The always change entry if not WINEPS yet is discussable.
433 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
435 !strstr(qbuf
,"WINEPS.DRV")
437 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
440 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
441 WriteProfileStringA("windows","device",buf
);
442 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
443 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
446 HeapFree(GetProcessHeap(),0,buf
);
450 static BOOL
add_printer_driver(WCHAR
*name
)
454 ZeroMemory(&di3
, sizeof(DRIVER_INFO_3W
));
457 di3
.pEnvironment
= envname_x86W
;
458 di3
.pDriverPath
= driver_nt
;
459 di3
.pDataFile
= generic_ppdW
;
460 di3
.pConfigFile
= driver_nt
;
461 di3
.pDefaultDataType
= rawW
;
463 if (AddPrinterDriverW(NULL
, 3, (LPBYTE
)&di3
) ||
464 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
467 di3
.pEnvironment
= envname_win40W
;
468 di3
.pDriverPath
= driver_9x
;
469 di3
.pConfigFile
= driver_9x
;
470 if (AddPrinterDriverW(NULL
, 3, (LPBYTE
)&di3
) ||
471 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
476 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3
.pDriverPath
), debugstr_w(di3
.pEnvironment
));
480 #ifdef SONAME_LIBCUPS
482 static void *cupshandle
;
485 DO_FUNC(cupsFreeDests); \
486 DO_FUNC(cupsFreeOptions); \
487 DO_FUNC(cupsGetDests); \
488 DO_FUNC(cupsGetPPD); \
489 DO_FUNC(cupsParseOptions); \
490 DO_FUNC(cupsPrintFile);
492 #define DO_FUNC(f) static typeof(f) *p##f
496 static BOOL
CUPS_LoadPrinters(void)
499 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
503 HKEY hkeyPrinter
, hkeyPrinters
;
505 WCHAR nameW
[MAX_PATH
];
506 HANDLE added_printer
;
508 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
510 TRACE("%s\n", loaderror
);
513 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
515 #define DO_FUNC(x) p##x = wine_dlsym( cupshandle, #x, NULL, 0 ); if (!p##x) return FALSE;
519 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
521 ERR("Can't create Printers key\n");
525 nrofdests
= pcupsGetDests(&dests
);
526 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
527 for (i
=0;i
<nrofdests
;i
++) {
528 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[i
].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
530 port
= HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port
) + lstrlenW(nameW
) * sizeof(WCHAR
));
531 lstrcpyW(port
, CUPS_Port
);
532 lstrcatW(port
, nameW
);
534 TRACE("Printer %d: %s\n", i
, debugstr_w(nameW
));
535 if(RegOpenKeyW(hkeyPrinters
, nameW
, &hkeyPrinter
) == ERROR_SUCCESS
) {
536 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
538 TRACE("Printer already exists\n");
539 /* overwrite old LPR:* port */
540 RegSetValueExW(hkeyPrinter
, PortW
, 0, REG_SZ
, (LPBYTE
)port
, (lstrlenW(port
) + 1) * sizeof(WCHAR
));
541 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
542 RegCloseKey(hkeyPrinter
);
544 static WCHAR comment_cups
[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
545 ' ','u','s','i','n','g',' ','C','U','P','S',0};
547 add_printer_driver(nameW
);
549 memset(&pi2
, 0, sizeof(PRINTER_INFO_2W
));
550 pi2
.pPrinterName
= nameW
;
551 pi2
.pDatatype
= rawW
;
552 pi2
.pPrintProcessor
= WinPrintW
;
553 pi2
.pDriverName
= nameW
;
554 pi2
.pComment
= comment_cups
;
555 pi2
.pLocation
= emptyStringW
;
556 pi2
.pPortName
= port
;
557 pi2
.pParameters
= emptyStringW
;
558 pi2
.pShareName
= emptyStringW
;
559 pi2
.pSepFile
= emptyStringW
;
561 added_printer
= AddPrinterW( NULL
, 2, (LPBYTE
)&pi2
);
562 if (added_printer
) ClosePrinter( added_printer
);
563 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
564 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW
), GetLastError() );
566 HeapFree(GetProcessHeap(),0,port
);
569 if (dests
[i
].is_default
) {
570 SetDefaultPrinterW(nameW
);
574 if (hadprinter
&& !haddefault
) {
575 MultiByteToWideChar(CP_UNIXCP
, 0, dests
[0].name
, -1, nameW
, sizeof(nameW
) / sizeof(WCHAR
));
576 SetDefaultPrinterW(nameW
);
578 pcupsFreeDests(nrofdests
, dests
);
579 RegCloseKey(hkeyPrinters
);
584 static BOOL
PRINTCAP_ParseEntry( const char *pent
, BOOL isfirst
)
586 PRINTER_INFO_2A pinfo2a
;
589 char *e
,*s
,*name
,*prettyname
,*devname
;
590 BOOL ret
= FALSE
, set_default
= FALSE
;
591 char *port
= NULL
, *env_default
;
592 HKEY hkeyPrinter
, hkeyPrinters
;
593 WCHAR devnameW
[MAX_PATH
];
594 HANDLE added_printer
;
596 while (isspace(*pent
)) pent
++;
597 r
= strchr(pent
,':');
601 name_len
= strlen(pent
);
602 name
= HeapAlloc(GetProcessHeap(), 0, name_len
+ 1);
603 memcpy(name
, pent
, name_len
);
604 name
[name_len
] = '\0';
610 TRACE("name=%s entry=%s\n",name
, pent
);
612 if(ispunct(*name
)) { /* a tc entry, not a real printer */
613 TRACE("skipping tc entry\n");
617 if(strstr(pent
,":server")) { /* server only version so skip */
618 TRACE("skipping server entry\n");
622 /* Determine whether this is a postscript printer. */
625 env_default
= getenv("PRINTER");
627 /* Get longest name, usually the one at the right for later display. */
628 while((s
=strchr(prettyname
,'|'))) {
631 while(isspace(*--e
)) *e
= '\0';
632 TRACE("\t%s\n", debugstr_a(prettyname
));
633 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
634 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
637 e
= prettyname
+ strlen(prettyname
);
638 while(isspace(*--e
)) *e
= '\0';
639 TRACE("\t%s\n", debugstr_a(prettyname
));
640 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
642 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
643 * if it is too long, we use it as comment below. */
644 devname
= prettyname
;
645 if (strlen(devname
)>=CCHDEVICENAME
-1)
647 if (strlen(devname
)>=CCHDEVICENAME
-1) {
652 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
653 sprintf(port
,"LPR:%s",name
);
655 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
657 ERR("Can't create Printers key\n");
662 MultiByteToWideChar(CP_ACP
, 0, devname
, -1, devnameW
, sizeof(devnameW
) / sizeof(WCHAR
));
664 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
665 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
667 TRACE("Printer already exists\n");
668 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
669 RegCloseKey(hkeyPrinter
);
671 static CHAR data_type
[] = "RAW",
672 print_proc
[] = "WinPrint",
673 comment
[] = "WINEPS Printer using LPR",
674 params
[] = "<parameters?>",
675 share_name
[] = "<share name?>",
676 sep_file
[] = "<sep file?>";
678 add_printer_driver(devnameW
);
680 memset(&pinfo2a
,0,sizeof(pinfo2a
));
681 pinfo2a
.pPrinterName
= devname
;
682 pinfo2a
.pDatatype
= data_type
;
683 pinfo2a
.pPrintProcessor
= print_proc
;
684 pinfo2a
.pDriverName
= devname
;
685 pinfo2a
.pComment
= comment
;
686 pinfo2a
.pLocation
= prettyname
;
687 pinfo2a
.pPortName
= port
;
688 pinfo2a
.pParameters
= params
;
689 pinfo2a
.pShareName
= share_name
;
690 pinfo2a
.pSepFile
= sep_file
;
692 added_printer
= AddPrinterA( NULL
, 2, (LPBYTE
)&pinfo2a
);
693 if (added_printer
) ClosePrinter( added_printer
);
694 else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
695 ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_a(name
), GetLastError() );
697 RegCloseKey(hkeyPrinters
);
699 if (isfirst
|| set_default
)
700 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
703 HeapFree(GetProcessHeap(), 0, port
);
704 HeapFree(GetProcessHeap(), 0, name
);
709 PRINTCAP_LoadPrinters(void) {
710 BOOL hadprinter
= FALSE
;
714 BOOL had_bash
= FALSE
;
716 f
= fopen("/etc/printcap","r");
720 while(fgets(buf
,sizeof(buf
),f
)) {
723 end
=strchr(buf
,'\n');
727 while(isspace(*start
)) start
++;
728 if(*start
== '#' || *start
== '\0')
731 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
732 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
733 HeapFree(GetProcessHeap(),0,pent
);
737 if (end
&& *--end
== '\\') {
744 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
747 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
753 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
754 HeapFree(GetProcessHeap(),0,pent
);
760 static inline DWORD
set_reg_DWORD(HKEY hkey
, const WCHAR
*keyname
, const DWORD value
)
762 return RegSetValueExW(hkey
, keyname
, 0, REG_DWORD
, (const BYTE
*)&value
, sizeof(value
));
765 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
768 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
769 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
771 return ERROR_FILE_NOT_FOUND
;
774 static inline DWORD
set_reg_devmode( HKEY key
, const WCHAR
*name
, const DEVMODEW
*dm
)
776 DEVMODEA
*dmA
= DEVMODEdupWtoA( dm
);
777 DWORD ret
= ERROR_FILE_NOT_FOUND
;
779 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
780 and we support these drivers. NT writes DEVMODEW so somehow
781 we'll need to distinguish between these when we support NT
786 ret
= RegSetValueExW( key
, name
, 0, REG_BINARY
,
787 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
788 HeapFree( GetProcessHeap(), 0, dmA
);
794 /******************************************************************
795 * get_servername_from_name (internal)
797 * for an external server, a copy of the serverpart from the full name is returned
800 static LPWSTR
get_servername_from_name(LPCWSTR name
)
804 WCHAR buffer
[MAX_PATH
];
807 if (name
== NULL
) return NULL
;
808 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
810 server
= strdupW(&name
[2]); /* skip over both backslash */
811 if (server
== NULL
) return NULL
;
813 /* strip '\' and the printername */
814 ptr
= strchrW(server
, '\\');
815 if (ptr
) ptr
[0] = '\0';
817 TRACE("found %s\n", debugstr_w(server
));
819 len
= sizeof(buffer
)/sizeof(buffer
[0]);
820 if (GetComputerNameW(buffer
, &len
)) {
821 if (lstrcmpW(buffer
, server
) == 0) {
822 /* The requested Servername is our computername */
823 HeapFree(GetProcessHeap(), 0, server
);
830 /******************************************************************
831 * get_basename_from_name (internal)
833 * skip over the serverpart from the full name
836 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
838 if (name
== NULL
) return NULL
;
839 if ((name
[0] == '\\') && (name
[1] == '\\')) {
840 /* skip over the servername and search for the following '\' */
841 name
= strchrW(&name
[2], '\\');
842 if ((name
) && (name
[1])) {
843 /* found a separator ('\') followed by a name:
844 skip over the separator and return the rest */
849 /* no basename present (we found only a servername) */
856 static void free_printer_entry( opened_printer_t
*printer
)
858 /* the queue is shared, so don't free that here */
859 HeapFree( GetProcessHeap(), 0, printer
->printername
);
860 HeapFree( GetProcessHeap(), 0, printer
->name
);
861 HeapFree( GetProcessHeap(), 0, printer
->devmode
);
862 HeapFree( GetProcessHeap(), 0, printer
);
865 /******************************************************************
866 * get_opened_printer_entry
867 * Get the first place empty in the opened printer table
870 * - pDefault is ignored
872 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
874 UINT_PTR handle
= nb_printer_handles
, i
;
875 jobqueue_t
*queue
= NULL
;
876 opened_printer_t
*printer
= NULL
;
880 if ((backend
== NULL
) && !load_backend()) return NULL
;
882 servername
= get_servername_from_name(name
);
884 FIXME("server %s not supported\n", debugstr_w(servername
));
885 HeapFree(GetProcessHeap(), 0, servername
);
886 SetLastError(ERROR_INVALID_PRINTER_NAME
);
890 printername
= get_basename_from_name(name
);
891 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
893 /* an empty printername is invalid */
894 if (printername
&& (!printername
[0])) {
895 SetLastError(ERROR_INVALID_PARAMETER
);
899 EnterCriticalSection(&printer_handles_cs
);
901 for (i
= 0; i
< nb_printer_handles
; i
++)
903 if (!printer_handles
[i
])
905 if(handle
== nb_printer_handles
)
910 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
911 queue
= printer_handles
[i
]->queue
;
915 if (handle
>= nb_printer_handles
)
917 opened_printer_t
**new_array
;
919 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
920 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
922 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
923 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
930 printer_handles
= new_array
;
931 nb_printer_handles
+= 16;
934 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
940 /* get a printer handle from the backend */
941 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
946 /* clone the base name. This is NULL for the printserver */
947 printer
->printername
= strdupW(printername
);
949 /* clone the full name */
950 printer
->name
= strdupW(name
);
951 if (name
&& (!printer
->name
)) {
956 if (pDefault
&& pDefault
->pDevMode
)
957 printer
->devmode
= dup_devmode( pDefault
->pDevMode
);
960 printer
->queue
= queue
;
963 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
964 if (!printer
->queue
) {
968 list_init(&printer
->queue
->jobs
);
969 printer
->queue
->ref
= 0;
971 InterlockedIncrement(&printer
->queue
->ref
);
973 printer_handles
[handle
] = printer
;
976 LeaveCriticalSection(&printer_handles_cs
);
977 if (!handle
&& printer
) {
978 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
979 free_printer_entry( printer
);
982 return (HANDLE
)handle
;
985 /******************************************************************
987 * Get the pointer to the opened printer referred by the handle
989 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
991 UINT_PTR idx
= (UINT_PTR
)hprn
;
992 opened_printer_t
*ret
= NULL
;
994 EnterCriticalSection(&printer_handles_cs
);
996 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
997 ret
= printer_handles
[idx
- 1];
999 LeaveCriticalSection(&printer_handles_cs
);
1003 /******************************************************************
1004 * get_opened_printer_name
1005 * Get the pointer to the opened printer name referred by the handle
1007 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
1009 opened_printer_t
*printer
= get_opened_printer(hprn
);
1010 if(!printer
) return NULL
;
1011 return printer
->name
;
1014 static DWORD
open_printer_reg_key( const WCHAR
*name
, HKEY
*key
)
1020 err
= RegCreateKeyW( HKEY_LOCAL_MACHINE
, PrintersW
, &printers
);
1021 if (err
) return err
;
1023 err
= RegOpenKeyW( printers
, name
, key
);
1024 if (err
) err
= ERROR_INVALID_PRINTER_NAME
;
1025 RegCloseKey( printers
);
1029 /******************************************************************
1030 * WINSPOOL_GetOpenedPrinterRegKey
1033 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
1035 LPCWSTR name
= get_opened_printer_name(hPrinter
);
1037 if(!name
) return ERROR_INVALID_HANDLE
;
1038 return open_printer_reg_key( name
, phkey
);
1041 static void old_printer_check( BOOL delete_phase
)
1043 PRINTER_INFO_5W
* pi
;
1044 DWORD needed
, type
, num
, delete, i
, size
;
1045 const DWORD one
= 1;
1049 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1050 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return;
1052 pi
= HeapAlloc( GetProcessHeap(), 0, needed
);
1053 EnumPrintersW( PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
);
1054 for (i
= 0; i
< num
; i
++)
1056 if (strncmpW( pi
[i
].pPortName
, CUPS_Port
, strlenW(CUPS_Port
) ) &&
1057 strncmpW( pi
[i
].pPortName
, LPR_Port
, strlenW(LPR_Port
) ))
1060 if (open_printer_reg_key( pi
[i
].pPrinterName
, &key
)) continue;
1064 RegSetValueExW( key
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&one
, sizeof(one
) );
1070 size
= sizeof( delete );
1071 RegQueryValueExW( key
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&delete, &size
);
1075 TRACE( "Deleting old printer %s\n", debugstr_w(pi
[i
].pPrinterName
) );
1076 if (OpenPrinterW( pi
[i
].pPrinterName
, &hprn
, NULL
))
1078 DeletePrinter( hprn
);
1079 ClosePrinter( hprn
);
1081 DeletePrinterDriverExW( NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0 );
1085 HeapFree(GetProcessHeap(), 0, pi
);
1088 static const WCHAR winspool_mutex_name
[] = {'_','_','W','I','N','E','_','W','I','N','S','P','O','O','L','_',
1089 'M','U','T','E','X','_','_','\0'};
1091 void WINSPOOL_LoadSystemPrinters(void)
1093 HKEY hkey
, hkeyPrinters
;
1094 DWORD needed
, num
, i
;
1095 WCHAR PrinterName
[256];
1099 /* FIXME: The init code should be moved to spoolsv.exe */
1100 mutex
= CreateMutexW( NULL
, TRUE
, winspool_mutex_name
);
1103 ERR( "Failed to create mutex\n" );
1106 if (GetLastError() == ERROR_ALREADY_EXISTS
)
1108 WaitForSingleObject( mutex
, INFINITE
);
1109 ReleaseMutex( mutex
);
1110 TRACE( "Init already done\n" );
1114 /* This ensures that all printer entries have a valid Name value. If causes
1115 problems later if they don't. If one is found to be missed we create one
1116 and set it equal to the name of the key */
1117 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1118 if(RegQueryInfoKeyW(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1119 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1120 for(i
= 0; i
< num
; i
++) {
1121 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1122 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1123 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1124 set_reg_szW(hkey
, NameW
, PrinterName
);
1131 RegCloseKey(hkeyPrinters
);
1134 old_printer_check( FALSE
);
1136 #ifdef SONAME_LIBCUPS
1137 done
= CUPS_LoadPrinters();
1140 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1141 PRINTCAP_LoadPrinters();
1143 old_printer_check( TRUE
);
1145 ReleaseMutex( mutex
);
1149 /******************************************************************
1152 * Get the pointer to the specified job.
1153 * Should hold the printer_handles_cs before calling.
1155 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1157 opened_printer_t
*printer
= get_opened_printer(hprn
);
1160 if(!printer
) return NULL
;
1161 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1163 if(job
->job_id
== JobId
)
1169 /***********************************************************
1172 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1175 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1178 Formname
= (dmA
->dmSize
> off_formname
);
1179 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1180 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1181 dmW
->dmDeviceName
, CCHDEVICENAME
);
1183 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1184 dmA
->dmSize
- CCHDEVICENAME
);
1186 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1187 off_formname
- CCHDEVICENAME
);
1188 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1189 dmW
->dmFormName
, CCHFORMNAME
);
1190 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1191 (off_formname
+ CCHFORMNAME
));
1194 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1195 dmA
->dmDriverExtra
);
1199 /******************************************************************
1200 * convert_printerinfo_W_to_A [internal]
1203 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1204 DWORD level
, DWORD outlen
, DWORD numentries
)
1210 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1212 len
= pi_sizeof
[level
] * numentries
;
1213 ptr
= (LPSTR
) out
+ len
;
1216 /* copy the numbers of all PRINTER_INFO_* first */
1217 memcpy(out
, pPrintersW
, len
);
1219 while (id
< numentries
) {
1223 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1224 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1226 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1227 if (piW
->pDescription
) {
1228 piA
->pDescription
= ptr
;
1229 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1230 ptr
, outlen
, NULL
, NULL
);
1236 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1237 ptr
, outlen
, NULL
, NULL
);
1241 if (piW
->pComment
) {
1242 piA
->pComment
= ptr
;
1243 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1244 ptr
, outlen
, NULL
, NULL
);
1253 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1254 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1257 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1258 if (piW
->pServerName
) {
1259 piA
->pServerName
= ptr
;
1260 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1261 ptr
, outlen
, NULL
, NULL
);
1265 if (piW
->pPrinterName
) {
1266 piA
->pPrinterName
= ptr
;
1267 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1268 ptr
, outlen
, NULL
, NULL
);
1272 if (piW
->pShareName
) {
1273 piA
->pShareName
= ptr
;
1274 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1275 ptr
, outlen
, NULL
, NULL
);
1279 if (piW
->pPortName
) {
1280 piA
->pPortName
= ptr
;
1281 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1282 ptr
, outlen
, NULL
, NULL
);
1286 if (piW
->pDriverName
) {
1287 piA
->pDriverName
= ptr
;
1288 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1289 ptr
, outlen
, NULL
, NULL
);
1293 if (piW
->pComment
) {
1294 piA
->pComment
= ptr
;
1295 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1296 ptr
, outlen
, NULL
, NULL
);
1300 if (piW
->pLocation
) {
1301 piA
->pLocation
= ptr
;
1302 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1303 ptr
, outlen
, NULL
, NULL
);
1308 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1310 /* align DEVMODEA to a DWORD boundary */
1311 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1315 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1316 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1317 memcpy(ptr
, dmA
, len
);
1318 HeapFree(GetProcessHeap(), 0, dmA
);
1324 if (piW
->pSepFile
) {
1325 piA
->pSepFile
= ptr
;
1326 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1327 ptr
, outlen
, NULL
, NULL
);
1331 if (piW
->pPrintProcessor
) {
1332 piA
->pPrintProcessor
= ptr
;
1333 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1334 ptr
, outlen
, NULL
, NULL
);
1338 if (piW
->pDatatype
) {
1339 piA
->pDatatype
= ptr
;
1340 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1341 ptr
, outlen
, NULL
, NULL
);
1345 if (piW
->pParameters
) {
1346 piA
->pParameters
= ptr
;
1347 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1348 ptr
, outlen
, NULL
, NULL
);
1352 if (piW
->pSecurityDescriptor
) {
1353 piA
->pSecurityDescriptor
= NULL
;
1354 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1361 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1362 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1364 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1366 if (piW
->pPrinterName
) {
1367 piA
->pPrinterName
= ptr
;
1368 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1369 ptr
, outlen
, NULL
, NULL
);
1373 if (piW
->pServerName
) {
1374 piA
->pServerName
= ptr
;
1375 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1376 ptr
, outlen
, NULL
, NULL
);
1385 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1386 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1388 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1390 if (piW
->pPrinterName
) {
1391 piA
->pPrinterName
= ptr
;
1392 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1393 ptr
, outlen
, NULL
, NULL
);
1397 if (piW
->pPortName
) {
1398 piA
->pPortName
= ptr
;
1399 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1400 ptr
, outlen
, NULL
, NULL
);
1407 case 6: /* 6A and 6W are the same structure */
1412 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1413 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1415 TRACE("(%u) #%u\n", level
, id
);
1416 if (piW
->pszObjectGUID
) {
1417 piA
->pszObjectGUID
= ptr
;
1418 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1419 ptr
, outlen
, NULL
, NULL
);
1429 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1430 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1433 TRACE("(%u) #%u\n", level
, id
);
1434 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1436 /* align DEVMODEA to a DWORD boundary */
1437 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1441 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1442 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1443 memcpy(ptr
, dmA
, len
);
1444 HeapFree(GetProcessHeap(), 0, dmA
);
1454 FIXME("for level %u\n", level
);
1456 pPrintersW
+= pi_sizeof
[level
];
1457 out
+= pi_sizeof
[level
];
1462 /******************************************************************
1463 * convert_driverinfo_W_to_A [internal]
1466 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1467 DWORD level
, DWORD outlen
, DWORD numentries
)
1473 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1475 len
= di_sizeof
[level
] * numentries
;
1476 ptr
= (LPSTR
) out
+ len
;
1479 /* copy the numbers of all PRINTER_INFO_* first */
1480 memcpy(out
, pDriversW
, len
);
1482 #define COPY_STRING(fld) \
1485 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1486 ptr += len; outlen -= len;\
1488 #define COPY_MULTIZ_STRING(fld) \
1489 { LPWSTR p = diW->fld; if (p){ \
1492 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1493 ptr += len; outlen -= len; p += len;\
1495 while(len > 1 && outlen > 0); \
1498 while (id
< numentries
)
1504 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
1505 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
1507 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1514 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
1515 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
1517 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1520 COPY_STRING(pEnvironment
);
1521 COPY_STRING(pDriverPath
);
1522 COPY_STRING(pDataFile
);
1523 COPY_STRING(pConfigFile
);
1528 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
1529 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
1531 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1534 COPY_STRING(pEnvironment
);
1535 COPY_STRING(pDriverPath
);
1536 COPY_STRING(pDataFile
);
1537 COPY_STRING(pConfigFile
);
1538 COPY_STRING(pHelpFile
);
1539 COPY_MULTIZ_STRING(pDependentFiles
);
1540 COPY_STRING(pMonitorName
);
1541 COPY_STRING(pDefaultDataType
);
1546 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
1547 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
1549 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1552 COPY_STRING(pEnvironment
);
1553 COPY_STRING(pDriverPath
);
1554 COPY_STRING(pDataFile
);
1555 COPY_STRING(pConfigFile
);
1556 COPY_STRING(pHelpFile
);
1557 COPY_MULTIZ_STRING(pDependentFiles
);
1558 COPY_STRING(pMonitorName
);
1559 COPY_STRING(pDefaultDataType
);
1560 COPY_MULTIZ_STRING(pszzPreviousNames
);
1565 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
1566 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
1568 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1571 COPY_STRING(pEnvironment
);
1572 COPY_STRING(pDriverPath
);
1573 COPY_STRING(pDataFile
);
1574 COPY_STRING(pConfigFile
);
1579 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
1580 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
1582 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1585 COPY_STRING(pEnvironment
);
1586 COPY_STRING(pDriverPath
);
1587 COPY_STRING(pDataFile
);
1588 COPY_STRING(pConfigFile
);
1589 COPY_STRING(pHelpFile
);
1590 COPY_MULTIZ_STRING(pDependentFiles
);
1591 COPY_STRING(pMonitorName
);
1592 COPY_STRING(pDefaultDataType
);
1593 COPY_MULTIZ_STRING(pszzPreviousNames
);
1594 COPY_STRING(pszMfgName
);
1595 COPY_STRING(pszOEMUrl
);
1596 COPY_STRING(pszHardwareID
);
1597 COPY_STRING(pszProvider
);
1602 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
1603 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
1605 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1608 COPY_STRING(pEnvironment
);
1609 COPY_STRING(pDriverPath
);
1610 COPY_STRING(pDataFile
);
1611 COPY_STRING(pConfigFile
);
1612 COPY_STRING(pHelpFile
);
1613 COPY_MULTIZ_STRING(pDependentFiles
);
1614 COPY_STRING(pMonitorName
);
1615 COPY_STRING(pDefaultDataType
);
1616 COPY_MULTIZ_STRING(pszzPreviousNames
);
1617 COPY_STRING(pszMfgName
);
1618 COPY_STRING(pszOEMUrl
);
1619 COPY_STRING(pszHardwareID
);
1620 COPY_STRING(pszProvider
);
1621 COPY_STRING(pszPrintProcessor
);
1622 COPY_STRING(pszVendorSetup
);
1623 COPY_MULTIZ_STRING(pszzColorProfiles
);
1624 COPY_STRING(pszInfPath
);
1625 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
1631 FIXME("for level %u\n", level
);
1634 pDriversW
+= di_sizeof
[level
];
1635 out
+= di_sizeof
[level
];
1640 #undef COPY_MULTIZ_STRING
1644 /***********************************************************
1647 static void *printer_info_AtoW( const void *data
, DWORD level
)
1650 UNICODE_STRING usBuffer
;
1652 if (!data
) return NULL
;
1654 if (level
< 1 || level
> 9) return NULL
;
1656 ret
= HeapAlloc( GetProcessHeap(), 0, pi_sizeof
[level
] );
1657 if (!ret
) return NULL
;
1659 memcpy( ret
, data
, pi_sizeof
[level
] ); /* copy everything first */
1665 const PRINTER_INFO_2A
*piA
= (const PRINTER_INFO_2A
*)data
;
1666 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)ret
;
1668 piW
->pServerName
= asciitounicode( &usBuffer
, piA
->pServerName
);
1669 piW
->pPrinterName
= asciitounicode( &usBuffer
, piA
->pPrinterName
);
1670 piW
->pShareName
= asciitounicode( &usBuffer
, piA
->pShareName
);
1671 piW
->pPortName
= asciitounicode( &usBuffer
, piA
->pPortName
);
1672 piW
->pDriverName
= asciitounicode( &usBuffer
, piA
->pDriverName
);
1673 piW
->pComment
= asciitounicode( &usBuffer
, piA
->pComment
);
1674 piW
->pLocation
= asciitounicode( &usBuffer
, piA
->pLocation
);
1675 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
1676 piW
->pSepFile
= asciitounicode( &usBuffer
, piA
->pSepFile
);
1677 piW
->pPrintProcessor
= asciitounicode( &usBuffer
, piA
->pPrintProcessor
);
1678 piW
->pDatatype
= asciitounicode( &usBuffer
, piA
->pDatatype
);
1679 piW
->pParameters
= asciitounicode( &usBuffer
, piA
->pParameters
);
1686 const PRINTER_INFO_9A
*piA
= (const PRINTER_INFO_9A
*)data
;
1687 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)ret
;
1689 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW( piA
->pDevMode
) : NULL
;
1694 FIXME( "Unhandled level %d\n", level
);
1695 HeapFree( GetProcessHeap(), 0, ret
);
1702 /***********************************************************
1705 static void free_printer_info( void *data
, DWORD level
)
1713 PRINTER_INFO_2W
*piW
= (PRINTER_INFO_2W
*)data
;
1715 HeapFree( GetProcessHeap(), 0, piW
->pServerName
);
1716 HeapFree( GetProcessHeap(), 0, piW
->pPrinterName
);
1717 HeapFree( GetProcessHeap(), 0, piW
->pShareName
);
1718 HeapFree( GetProcessHeap(), 0, piW
->pPortName
);
1719 HeapFree( GetProcessHeap(), 0, piW
->pDriverName
);
1720 HeapFree( GetProcessHeap(), 0, piW
->pComment
);
1721 HeapFree( GetProcessHeap(), 0, piW
->pLocation
);
1722 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
1723 HeapFree( GetProcessHeap(), 0, piW
->pSepFile
);
1724 HeapFree( GetProcessHeap(), 0, piW
->pPrintProcessor
);
1725 HeapFree( GetProcessHeap(), 0, piW
->pDatatype
);
1726 HeapFree( GetProcessHeap(), 0, piW
->pParameters
);
1733 PRINTER_INFO_9W
*piW
= (PRINTER_INFO_9W
*)data
;
1735 HeapFree( GetProcessHeap(), 0, piW
->pDevMode
);
1740 FIXME( "Unhandled level %d\n", level
);
1743 HeapFree( GetProcessHeap(), 0, data
);
1747 /******************************************************************
1748 * DeviceCapabilities [WINSPOOL.@]
1749 * DeviceCapabilitiesA [WINSPOOL.@]
1752 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1753 LPSTR pOutput
, LPDEVMODEA lpdm
)
1757 if (!GDI_CallDeviceCapabilities16
)
1759 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1761 if (!GDI_CallDeviceCapabilities16
) return -1;
1763 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1765 /* If DC_PAPERSIZE map POINT16s to POINTs */
1766 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1767 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1768 POINT
*pt
= (POINT
*)pOutput
;
1770 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1771 for(i
= 0; i
< ret
; i
++, pt
++)
1776 HeapFree( GetProcessHeap(), 0, tmp
);
1782 /*****************************************************************************
1783 * DeviceCapabilitiesW [WINSPOOL.@]
1785 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1788 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1789 WORD fwCapability
, LPWSTR pOutput
,
1790 const DEVMODEW
*pDevMode
)
1792 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
1793 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1794 LPSTR pPortA
= strdupWtoA(pPort
);
1797 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1798 fwCapability
== DC_FILEDEPENDENCIES
||
1799 fwCapability
== DC_PAPERNAMES
)) {
1800 /* These need A -> W translation */
1803 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1807 switch(fwCapability
) {
1812 case DC_FILEDEPENDENCIES
:
1816 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1817 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1819 for(i
= 0; i
< ret
; i
++)
1820 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1821 pOutput
+ (i
* size
), size
);
1822 HeapFree(GetProcessHeap(), 0, pOutputA
);
1824 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1825 (LPSTR
)pOutput
, dmA
);
1827 HeapFree(GetProcessHeap(),0,pPortA
);
1828 HeapFree(GetProcessHeap(),0,pDeviceA
);
1829 HeapFree(GetProcessHeap(),0,dmA
);
1833 /******************************************************************
1834 * DocumentPropertiesA [WINSPOOL.@]
1836 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1838 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1839 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1840 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1842 LPSTR lpName
= pDeviceName
;
1843 static CHAR port
[] = "LPT1:";
1846 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1847 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1851 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1853 ERR("no name from hPrinter?\n");
1854 SetLastError(ERROR_INVALID_HANDLE
);
1857 lpName
= strdupWtoA(lpNameW
);
1860 if (!GDI_CallExtDeviceMode16
)
1862 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1864 if (!GDI_CallExtDeviceMode16
) {
1865 ERR("No CallExtDeviceMode16?\n");
1869 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1870 pDevModeInput
, NULL
, fMode
);
1873 HeapFree(GetProcessHeap(),0,lpName
);
1878 /*****************************************************************************
1879 * DocumentPropertiesW (WINSPOOL.@)
1881 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1883 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1885 LPDEVMODEW pDevModeOutput
,
1886 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1889 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1890 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
1891 LPDEVMODEA pDevModeOutputA
= NULL
;
1894 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1895 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1897 if(pDevModeOutput
) {
1898 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1899 if(ret
< 0) return ret
;
1900 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1902 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1903 pDevModeInputA
, fMode
);
1904 if(pDevModeOutput
) {
1905 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1906 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1908 if(fMode
== 0 && ret
> 0)
1909 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1910 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1911 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1915 /*****************************************************************************
1916 * IsValidDevmodeA [WINSPOOL.@]
1918 * Validate a DEVMODE structure and fix errors if possible.
1921 BOOL WINAPI
IsValidDevmodeA(PDEVMODEA
*pDevMode
, SIZE_T size
)
1923 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
1931 /*****************************************************************************
1932 * IsValidDevmodeW [WINSPOOL.@]
1934 * Validate a DEVMODE structure and fix errors if possible.
1937 BOOL WINAPI
IsValidDevmodeW(PDEVMODEW
*pDevMode
, SIZE_T size
)
1939 FIXME("(%p,%ld): stub\n", pDevMode
, size
);
1947 /******************************************************************
1948 * OpenPrinterA [WINSPOOL.@]
1953 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1954 LPPRINTER_DEFAULTSA pDefault
)
1956 UNICODE_STRING lpPrinterNameW
;
1957 UNICODE_STRING usBuffer
;
1958 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1959 PWSTR pwstrPrinterNameW
;
1962 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1965 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1966 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1967 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1968 pDefaultW
= &DefaultW
;
1970 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1972 RtlFreeUnicodeString(&usBuffer
);
1973 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1975 RtlFreeUnicodeString(&lpPrinterNameW
);
1979 /******************************************************************
1980 * OpenPrinterW [WINSPOOL.@]
1982 * Open a Printer / Printserver or a Printer-Object
1985 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1986 * phPrinter [O] The resulting Handle is stored here
1987 * pDefault [I] PTR to Default Printer Settings or NULL
1994 * lpPrinterName is one of:
1995 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1996 *| Printer: "PrinterName"
1997 *| Printer-Object: "PrinterName,Job xxx"
1998 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1999 *| XcvPort: "Servername,XcvPort PortName"
2002 *| Printer-Object not supported
2003 *| pDefaults is ignored
2006 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2009 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2012 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2013 SetLastError(ERROR_INVALID_PARAMETER
);
2017 /* Get the unique handle of the printer or Printserver */
2018 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2019 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2020 return (*phPrinter
!= 0);
2023 /******************************************************************
2024 * AddMonitorA [WINSPOOL.@]
2029 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2031 LPWSTR nameW
= NULL
;
2034 LPMONITOR_INFO_2A mi2a
;
2035 MONITOR_INFO_2W mi2w
;
2037 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2038 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2039 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2040 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2041 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2044 SetLastError(ERROR_INVALID_LEVEL
);
2048 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2054 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2055 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2056 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2059 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2061 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2062 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2063 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2065 if (mi2a
->pEnvironment
) {
2066 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2067 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2068 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2070 if (mi2a
->pDLLName
) {
2071 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2072 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2073 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2076 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2078 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2079 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2080 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2082 HeapFree(GetProcessHeap(), 0, nameW
);
2086 /******************************************************************************
2087 * AddMonitorW [WINSPOOL.@]
2089 * Install a Printmonitor
2092 * pName [I] Servername or NULL (local Computer)
2093 * Level [I] Structure-Level (Must be 2)
2094 * pMonitors [I] PTR to MONITOR_INFO_2
2101 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2104 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2106 LPMONITOR_INFO_2W mi2w
;
2108 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2109 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2110 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2111 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2112 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2114 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2117 SetLastError(ERROR_INVALID_LEVEL
);
2121 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2126 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2129 /******************************************************************
2130 * DeletePrinterDriverA [WINSPOOL.@]
2133 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2135 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2138 /******************************************************************
2139 * DeletePrinterDriverW [WINSPOOL.@]
2142 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2144 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2147 /******************************************************************
2148 * DeleteMonitorA [WINSPOOL.@]
2150 * See DeleteMonitorW.
2153 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2155 LPWSTR nameW
= NULL
;
2156 LPWSTR EnvironmentW
= NULL
;
2157 LPWSTR MonitorNameW
= NULL
;
2162 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2163 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2164 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2168 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2169 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2170 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2173 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2174 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2175 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2178 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2180 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2181 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2182 HeapFree(GetProcessHeap(), 0, nameW
);
2186 /******************************************************************
2187 * DeleteMonitorW [WINSPOOL.@]
2189 * Delete a specific Printmonitor from a Printing-Environment
2192 * pName [I] Servername or NULL (local Computer)
2193 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2194 * pMonitorName [I] Name of the Monitor, that should be deleted
2201 * pEnvironment is ignored in Windows for the local Computer.
2204 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2207 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2208 debugstr_w(pMonitorName
));
2210 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2212 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2216 /******************************************************************
2217 * DeletePortA [WINSPOOL.@]
2222 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2224 LPWSTR nameW
= NULL
;
2225 LPWSTR portW
= NULL
;
2229 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2231 /* convert servername to unicode */
2233 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2234 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2235 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2238 /* convert portname to unicode */
2240 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2241 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2242 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2245 res
= DeletePortW(nameW
, hWnd
, portW
);
2246 HeapFree(GetProcessHeap(), 0, nameW
);
2247 HeapFree(GetProcessHeap(), 0, portW
);
2251 /******************************************************************
2252 * DeletePortW [WINSPOOL.@]
2254 * Delete a specific Port
2257 * pName [I] Servername or NULL (local Computer)
2258 * hWnd [I] Handle to parent Window for the Dialog-Box
2259 * pPortName [I] Name of the Port, that should be deleted
2266 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2268 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2270 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2273 SetLastError(RPC_X_NULL_REF_POINTER
);
2277 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2280 /******************************************************************************
2281 * WritePrinter [WINSPOOL.@]
2283 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2285 opened_printer_t
*printer
;
2288 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2290 EnterCriticalSection(&printer_handles_cs
);
2291 printer
= get_opened_printer(hPrinter
);
2294 SetLastError(ERROR_INVALID_HANDLE
);
2300 SetLastError(ERROR_SPL_NO_STARTDOC
);
2304 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2306 LeaveCriticalSection(&printer_handles_cs
);
2310 /*****************************************************************************
2311 * AddFormA [WINSPOOL.@]
2313 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2315 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2319 /*****************************************************************************
2320 * AddFormW [WINSPOOL.@]
2322 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2324 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2328 /*****************************************************************************
2329 * AddJobA [WINSPOOL.@]
2331 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2334 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2338 SetLastError(ERROR_INVALID_LEVEL
);
2342 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2345 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2346 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2347 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2348 if(*pcbNeeded
> cbBuf
) {
2349 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2352 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2353 addjobA
->JobId
= addjobW
->JobId
;
2354 addjobA
->Path
= (char *)(addjobA
+ 1);
2355 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2361 /*****************************************************************************
2362 * AddJobW [WINSPOOL.@]
2364 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2366 opened_printer_t
*printer
;
2369 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2370 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2371 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2373 ADDJOB_INFO_1W
*addjob
;
2375 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2377 EnterCriticalSection(&printer_handles_cs
);
2379 printer
= get_opened_printer(hPrinter
);
2382 SetLastError(ERROR_INVALID_HANDLE
);
2387 SetLastError(ERROR_INVALID_LEVEL
);
2391 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2395 job
->job_id
= InterlockedIncrement(&next_job_id
);
2397 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2398 if(path
[len
- 1] != '\\')
2400 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2401 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2403 len
= strlenW(filename
);
2404 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2405 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2406 job
->portname
= NULL
;
2407 job
->document_title
= strdupW(default_doc_title
);
2408 job
->printer_name
= strdupW(printer
->name
);
2409 job
->devmode
= dup_devmode( printer
->devmode
);
2410 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2412 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2413 if(*pcbNeeded
<= cbBuf
) {
2414 addjob
= (ADDJOB_INFO_1W
*)pData
;
2415 addjob
->JobId
= job
->job_id
;
2416 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2417 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2420 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2423 LeaveCriticalSection(&printer_handles_cs
);
2427 /*****************************************************************************
2428 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2430 * Return the PATH for the Print-Processors
2432 * See GetPrintProcessorDirectoryW.
2436 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2437 DWORD level
, LPBYTE Info
,
2438 DWORD cbBuf
, LPDWORD pcbNeeded
)
2440 LPWSTR serverW
= NULL
;
2445 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2446 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2450 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2451 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2452 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2456 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2457 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2458 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2461 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2462 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2464 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2467 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2468 cbBuf
, NULL
, NULL
) > 0;
2471 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2472 HeapFree(GetProcessHeap(), 0, envW
);
2473 HeapFree(GetProcessHeap(), 0, serverW
);
2477 /*****************************************************************************
2478 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2480 * Return the PATH for the Print-Processors
2483 * server [I] Servername (NT only) or NULL (local Computer)
2484 * env [I] Printing-Environment (see below) or NULL (Default)
2485 * level [I] Structure-Level (must be 1)
2486 * Info [O] PTR to Buffer that receives the Result
2487 * cbBuf [I] Size of Buffer at "Info"
2488 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2489 * required for the Buffer at "Info"
2492 * Success: TRUE and in pcbNeeded the Bytes used in Info
2493 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2494 * if cbBuf is too small
2496 * Native Values returned in Info on Success:
2497 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2498 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2499 *| win9x(Windows 4.0): "%winsysdir%"
2501 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2504 * Only NULL or "" is supported for server
2507 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2508 DWORD level
, LPBYTE Info
,
2509 DWORD cbBuf
, LPDWORD pcbNeeded
)
2512 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
2513 Info
, cbBuf
, pcbNeeded
);
2515 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2518 /* (Level != 1) is ignored in win9x */
2519 SetLastError(ERROR_INVALID_LEVEL
);
2523 if (pcbNeeded
== NULL
) {
2524 /* (pcbNeeded == NULL) is ignored in win9x */
2525 SetLastError(RPC_X_NULL_REF_POINTER
);
2529 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
2532 /*****************************************************************************
2533 * WINSPOOL_OpenDriverReg [internal]
2535 * opens the registry for the printer drivers depending on the given input
2536 * variable pEnvironment
2539 * the opened hkey on success
2542 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
2546 const printenv_t
* env
;
2548 TRACE("(%s)\n", debugstr_w(pEnvironment
));
2550 env
= validate_envW(pEnvironment
);
2551 if (!env
) return NULL
;
2553 buffer
= HeapAlloc( GetProcessHeap(), 0,
2554 (strlenW(DriversW
) + strlenW(env
->envname
) +
2555 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2557 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2558 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2559 HeapFree(GetProcessHeap(), 0, buffer
);
2564 /*****************************************************************************
2565 * set_devices_and_printerports [internal]
2567 * set the [Devices] and [PrinterPorts] entries for a printer.
2570 static void set_devices_and_printerports(PRINTER_INFO_2W
*pi
)
2572 DWORD portlen
= lstrlenW(pi
->pPortName
) * sizeof(WCHAR
);
2576 TRACE("(%p) %s\n", pi
, debugstr_w(pi
->pPrinterName
));
2578 /* FIXME: the driver must change to "winspool" */
2579 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt
) + portlen
+ sizeof(timeout_15_45
));
2581 lstrcpyW(devline
, driver_nt
);
2582 lstrcatW(devline
, commaW
);
2583 lstrcatW(devline
, pi
->pPortName
);
2585 TRACE("using %s\n", debugstr_w(devline
));
2586 WriteProfileStringW(devicesW
, pi
->pPrinterName
, devline
);
2587 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
)) {
2588 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2589 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2593 lstrcatW(devline
, timeout_15_45
);
2594 WriteProfileStringW(PrinterPortsW
, pi
->pPrinterName
, devline
);
2595 if (!RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
)) {
2596 RegSetValueExW(hkey
, pi
->pPrinterName
, 0, REG_SZ
, (LPBYTE
)devline
,
2597 (lstrlenW(devline
) + 1) * sizeof(WCHAR
));
2600 HeapFree(GetProcessHeap(), 0, devline
);
2604 /*****************************************************************************
2605 * AddPrinterW [WINSPOOL.@]
2607 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2609 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2612 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2615 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2618 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2619 SetLastError(ERROR_INVALID_PARAMETER
);
2623 ERR("Level = %d, unsupported!\n", Level
);
2624 SetLastError(ERROR_INVALID_LEVEL
);
2628 SetLastError(ERROR_INVALID_PARAMETER
);
2631 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2633 ERR("Can't create Printers key\n");
2636 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2637 if (!RegQueryValueW(hkeyPrinter
, AttributesW
, NULL
, NULL
)) {
2638 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2639 RegCloseKey(hkeyPrinter
);
2640 RegCloseKey(hkeyPrinters
);
2643 RegCloseKey(hkeyPrinter
);
2645 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
2647 ERR("Can't create Drivers key\n");
2648 RegCloseKey(hkeyPrinters
);
2651 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2653 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2654 RegCloseKey(hkeyPrinters
);
2655 RegCloseKey(hkeyDrivers
);
2656 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2659 RegCloseKey(hkeyDriver
);
2660 RegCloseKey(hkeyDrivers
);
2662 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2663 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2664 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2665 RegCloseKey(hkeyPrinters
);
2669 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2671 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2672 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2673 RegCloseKey(hkeyPrinters
);
2677 set_devices_and_printerports(pi
);
2678 RegSetValueExW(hkeyPrinter
, AttributesW
, 0, REG_DWORD
,
2679 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2680 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2682 /* See if we can load the driver. We may need the devmode structure anyway
2685 * Note that DocumentPropertiesW will briefly try to open the printer we
2686 * just create to find a DEVMODE struct (it will use the WINEPS default
2687 * one in case it is not there, so we are ok).
2689 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2692 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2693 size
= sizeof(DEVMODEW
);
2699 dm
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2701 if (DocumentPropertiesW(0, 0, pi
->pPrinterName
, dm
, NULL
, DM_OUT_BUFFER
) < 0)
2703 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2704 HeapFree( GetProcessHeap(), 0, dm
);
2709 /* set devmode to printer name */
2710 lstrcpynW( dm
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2714 set_reg_devmode( hkeyPrinter
, Default_DevModeW
, dm
);
2715 if (!pi
->pDevMode
) HeapFree( GetProcessHeap(), 0, dm
);
2717 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2718 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2719 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2720 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2722 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2723 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2724 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2725 RegSetValueExW(hkeyPrinter
, PriorityW
, 0, REG_DWORD
,
2726 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2727 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2728 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2729 RegSetValueExW(hkeyPrinter
, StartTimeW
, 0, REG_DWORD
,
2730 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2731 RegSetValueExW(hkeyPrinter
, StatusW
, 0, REG_DWORD
,
2732 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2733 RegSetValueExW(hkeyPrinter
, UntilTimeW
, 0, REG_DWORD
,
2734 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2736 RegCloseKey(hkeyPrinter
);
2737 RegCloseKey(hkeyPrinters
);
2738 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2739 ERR("OpenPrinter failing\n");
2745 /*****************************************************************************
2746 * AddPrinterA [WINSPOOL.@]
2748 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2750 UNICODE_STRING pNameW
;
2752 PRINTER_INFO_2W
*piW
;
2753 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2756 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), Level
, pPrinter
);
2758 ERR("Level = %d, unsupported!\n", Level
);
2759 SetLastError(ERROR_INVALID_LEVEL
);
2762 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2763 piW
= printer_info_AtoW( piA
, Level
);
2765 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2767 free_printer_info( piW
, Level
);
2768 RtlFreeUnicodeString(&pNameW
);
2773 /*****************************************************************************
2774 * ClosePrinter [WINSPOOL.@]
2776 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2778 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2779 opened_printer_t
*printer
= NULL
;
2782 TRACE("(%p)\n", hPrinter
);
2784 EnterCriticalSection(&printer_handles_cs
);
2786 if ((i
> 0) && (i
<= nb_printer_handles
))
2787 printer
= printer_handles
[i
- 1];
2792 struct list
*cursor
, *cursor2
;
2794 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
2796 if (printer
->backend_printer
) {
2797 backend
->fpClosePrinter(printer
->backend_printer
);
2801 EndDocPrinter(hPrinter
);
2803 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2805 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2807 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2808 ScheduleJob(hPrinter
, job
->job_id
);
2810 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2813 free_printer_entry( printer
);
2814 printer_handles
[i
- 1] = NULL
;
2817 LeaveCriticalSection(&printer_handles_cs
);
2821 /*****************************************************************************
2822 * DeleteFormA [WINSPOOL.@]
2824 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2826 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2830 /*****************************************************************************
2831 * DeleteFormW [WINSPOOL.@]
2833 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2835 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2839 /*****************************************************************************
2840 * DeletePrinter [WINSPOOL.@]
2842 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2844 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2845 HKEY hkeyPrinters
, hkey
;
2846 WCHAR def
[MAX_PATH
];
2847 DWORD size
= sizeof( def
) / sizeof( def
[0] );
2850 SetLastError(ERROR_INVALID_HANDLE
);
2853 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
2854 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
2855 RegCloseKey(hkeyPrinters
);
2857 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
2858 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
2860 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2861 RegDeleteValueW(hkey
, lpNameW
);
2865 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
2866 RegDeleteValueW(hkey
, lpNameW
);
2870 if (GetDefaultPrinterW( def
, &size
) && !strcmpW( def
, lpNameW
))
2872 WriteProfileStringW( windowsW
, deviceW
, NULL
);
2873 if (!RegCreateKeyW( HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
))
2875 RegDeleteValueW( hkey
, deviceW
);
2876 RegCloseKey( hkey
);
2878 SetDefaultPrinterW( NULL
);
2884 /*****************************************************************************
2885 * SetPrinterA [WINSPOOL.@]
2887 BOOL WINAPI
SetPrinterA( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
2894 dataW
= printer_info_AtoW( data
, level
);
2895 if (!dataW
) return FALSE
;
2898 ret
= SetPrinterW( printer
, level
, dataW
, command
);
2900 if (dataW
!= data
) free_printer_info( dataW
, level
);
2905 static void set_printer_2( HKEY key
, const PRINTER_INFO_2W
*pi
)
2907 set_reg_szW( key
, NameW
, pi
->pPrinterName
);
2908 set_reg_szW( key
, Share_NameW
, pi
->pShareName
);
2909 set_reg_szW( key
, PortW
, pi
->pPortName
);
2910 set_reg_szW( key
, Printer_DriverW
, pi
->pDriverName
);
2911 set_reg_szW( key
, DescriptionW
, pi
->pComment
);
2912 set_reg_szW( key
, LocationW
, pi
->pLocation
);
2915 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
2917 set_reg_szW( key
, Separator_FileW
, pi
->pSepFile
);
2918 set_reg_szW( key
, Print_ProcessorW
, pi
->pPrintProcessor
);
2919 set_reg_szW( key
, DatatypeW
, pi
->pDatatype
);
2920 set_reg_szW( key
, ParametersW
, pi
->pParameters
);
2922 set_reg_DWORD( key
, AttributesW
, pi
->Attributes
);
2923 set_reg_DWORD( key
, PriorityW
, pi
->Priority
);
2924 set_reg_DWORD( key
, Default_PriorityW
, pi
->DefaultPriority
);
2925 set_reg_DWORD( key
, StartTimeW
, pi
->StartTime
);
2926 set_reg_DWORD( key
, UntilTimeW
, pi
->UntilTime
);
2929 static BOOL
set_printer_9( HKEY key
, const PRINTER_INFO_9W
*pi
)
2931 if (!pi
->pDevMode
) return FALSE
;
2933 set_reg_devmode( key
, Default_DevModeW
, pi
->pDevMode
);
2937 /******************************************************************************
2938 * SetPrinterW [WINSPOOL.@]
2940 BOOL WINAPI
SetPrinterW( HANDLE printer
, DWORD level
, LPBYTE data
, DWORD command
)
2945 TRACE( "(%p, %d, %p, %d)\n", printer
, level
, data
, command
);
2947 if (command
!= 0) FIXME( "Ignoring command %d\n", command
);
2949 if (WINSPOOL_GetOpenedPrinterRegKey( printer
, &key
))
2956 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)data
;
2957 set_printer_2( key
, pi2
);
2964 PRINTER_INFO_9W
*pi
= (PRINTER_INFO_9W
*)data
;
2965 ret
= set_printer_9( key
, pi
);
2970 FIXME( "Unimplemented level %d\n", level
);
2971 SetLastError( ERROR_INVALID_LEVEL
);
2978 /*****************************************************************************
2979 * SetJobA [WINSPOOL.@]
2981 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2982 LPBYTE pJob
, DWORD Command
)
2986 UNICODE_STRING usBuffer
;
2988 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
2990 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2991 are all ignored by SetJob, so we don't bother copying them */
2999 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3000 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3002 JobW
= (LPBYTE
)info1W
;
3003 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3004 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3005 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3006 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3007 info1W
->Status
= info1A
->Status
;
3008 info1W
->Priority
= info1A
->Priority
;
3009 info1W
->Position
= info1A
->Position
;
3010 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3015 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3016 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3018 JobW
= (LPBYTE
)info2W
;
3019 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3020 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3021 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3022 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3023 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3024 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3025 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3026 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3027 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3028 info2W
->Status
= info2A
->Status
;
3029 info2W
->Priority
= info2A
->Priority
;
3030 info2W
->Position
= info2A
->Position
;
3031 info2W
->StartTime
= info2A
->StartTime
;
3032 info2W
->UntilTime
= info2A
->UntilTime
;
3033 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3037 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3038 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3041 SetLastError(ERROR_INVALID_LEVEL
);
3045 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3051 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3052 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3053 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3054 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3055 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3060 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3061 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3062 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3063 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3064 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3065 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3066 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3067 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3068 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3072 HeapFree(GetProcessHeap(), 0, JobW
);
3077 /*****************************************************************************
3078 * SetJobW [WINSPOOL.@]
3080 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3081 LPBYTE pJob
, DWORD Command
)
3086 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3087 FIXME("Ignoring everything other than document title\n");
3089 EnterCriticalSection(&printer_handles_cs
);
3090 job
= get_job(hPrinter
, JobId
);
3100 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3101 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3102 job
->document_title
= strdupW(info1
->pDocument
);
3107 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3108 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3109 job
->document_title
= strdupW(info2
->pDocument
);
3110 HeapFree(GetProcessHeap(), 0, job
->devmode
);
3111 job
->devmode
= dup_devmode( info2
->pDevMode
);
3117 SetLastError(ERROR_INVALID_LEVEL
);
3122 LeaveCriticalSection(&printer_handles_cs
);
3126 /*****************************************************************************
3127 * EndDocPrinter [WINSPOOL.@]
3129 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3131 opened_printer_t
*printer
;
3133 TRACE("(%p)\n", hPrinter
);
3135 EnterCriticalSection(&printer_handles_cs
);
3137 printer
= get_opened_printer(hPrinter
);
3140 SetLastError(ERROR_INVALID_HANDLE
);
3146 SetLastError(ERROR_SPL_NO_STARTDOC
);
3150 CloseHandle(printer
->doc
->hf
);
3151 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3152 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3153 printer
->doc
= NULL
;
3156 LeaveCriticalSection(&printer_handles_cs
);
3160 /*****************************************************************************
3161 * EndPagePrinter [WINSPOOL.@]
3163 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3165 FIXME("(%p): stub\n", hPrinter
);
3169 /*****************************************************************************
3170 * StartDocPrinterA [WINSPOOL.@]
3172 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3174 UNICODE_STRING usBuffer
;
3176 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3179 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3180 or one (DOC_INFO_3) extra DWORDs */
3184 doc2W
.JobId
= doc2
->JobId
;
3187 doc2W
.dwMode
= doc2
->dwMode
;
3190 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3191 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3192 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3196 SetLastError(ERROR_INVALID_LEVEL
);
3200 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3202 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3203 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3204 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3209 /*****************************************************************************
3210 * StartDocPrinterW [WINSPOOL.@]
3212 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3214 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3215 opened_printer_t
*printer
;
3216 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3217 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3218 JOB_INFO_1W job_info
;
3219 DWORD needed
, ret
= 0;
3224 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3225 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3226 debugstr_w(doc
->pDatatype
));
3228 if(Level
< 1 || Level
> 3)
3230 SetLastError(ERROR_INVALID_LEVEL
);
3234 EnterCriticalSection(&printer_handles_cs
);
3235 printer
= get_opened_printer(hPrinter
);
3238 SetLastError(ERROR_INVALID_HANDLE
);
3244 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3248 /* Even if we're printing to a file we still add a print job, we'll
3249 just ignore the spool file name */
3251 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3253 ERR("AddJob failed gle %u\n", GetLastError());
3257 /* use pOutputFile only, when it is a real filename */
3258 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3259 filename
= doc
->pOutputFile
;
3261 filename
= addjob
->Path
;
3263 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3264 if(hf
== INVALID_HANDLE_VALUE
)
3267 memset(&job_info
, 0, sizeof(job_info
));
3268 job_info
.pDocument
= doc
->pDocName
;
3269 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3271 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3272 printer
->doc
->hf
= hf
;
3273 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3274 job
= get_job(hPrinter
, ret
);
3275 job
->portname
= strdupW(doc
->pOutputFile
);
3278 LeaveCriticalSection(&printer_handles_cs
);
3283 /*****************************************************************************
3284 * StartPagePrinter [WINSPOOL.@]
3286 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3288 FIXME("(%p): stub\n", hPrinter
);
3292 /*****************************************************************************
3293 * GetFormA [WINSPOOL.@]
3295 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3296 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3298 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3299 Level
,pForm
,cbBuf
,pcbNeeded
);
3303 /*****************************************************************************
3304 * GetFormW [WINSPOOL.@]
3306 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3307 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3309 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3310 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3314 /*****************************************************************************
3315 * SetFormA [WINSPOOL.@]
3317 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3320 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3324 /*****************************************************************************
3325 * SetFormW [WINSPOOL.@]
3327 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3330 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3334 /*****************************************************************************
3335 * ReadPrinter [WINSPOOL.@]
3337 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3338 LPDWORD pNoBytesRead
)
3340 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3344 /*****************************************************************************
3345 * ResetPrinterA [WINSPOOL.@]
3347 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3349 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3353 /*****************************************************************************
3354 * ResetPrinterW [WINSPOOL.@]
3356 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3358 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3362 /*****************************************************************************
3363 * get_dword_from_reg
3365 * Return DWORD associated with name from hkey.
3367 static DWORD
get_dword_from_reg( HKEY hkey
, const WCHAR
*name
)
3369 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3372 ret
= RegQueryValueExW( hkey
, name
, 0, &type
, (LPBYTE
)&value
, &sz
);
3374 if(ret
!= ERROR_SUCCESS
) {
3375 WARN("Got ret = %d on name %s\n", ret
, debugstr_w(name
));
3378 if(type
!= REG_DWORD
) {
3379 ERR("Got type %d\n", type
);
3385 /*****************************************************************************
3386 * get_filename_from_reg [internal]
3388 * Get ValueName from hkey storing result in out
3389 * when the Value in the registry has only a filename, use driverdir as prefix
3390 * outlen is space left in out
3391 * String is stored either as unicode or ascii
3395 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3396 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3398 WCHAR filename
[MAX_PATH
];
3402 LPWSTR buffer
= filename
;
3406 size
= sizeof(filename
);
3408 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3409 if (ret
== ERROR_MORE_DATA
) {
3410 TRACE("need dynamic buffer: %u\n", size
);
3411 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3413 /* No Memory is bad */
3417 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3420 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3421 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3427 /* do we have a full path ? */
3428 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3429 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3432 /* we must build the full Path */
3434 if ((out
) && (outlen
> dirlen
)) {
3435 lstrcpyW((LPWSTR
)out
, driverdir
);
3443 /* write the filename */
3444 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3445 if ((out
) && (outlen
>= size
)) {
3446 lstrcpyW((LPWSTR
)out
, ptr
);
3453 ptr
+= lstrlenW(ptr
)+1;
3454 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3457 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3459 /* write the multisz-termination */
3460 if (type
== REG_MULTI_SZ
) {
3461 size
= sizeof(WCHAR
);
3464 if (out
&& (outlen
>= size
)) {
3465 memset (out
, 0, size
);
3471 /*****************************************************************************
3472 * WINSPOOL_GetStringFromReg
3474 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3475 * String is stored as unicode.
3477 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3478 DWORD buflen
, DWORD
*needed
)
3480 DWORD sz
= buflen
, type
;
3483 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3484 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3485 WARN("Got ret = %d\n", ret
);
3489 /* add space for terminating '\0' */
3490 sz
+= sizeof(WCHAR
);
3494 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
3499 /*****************************************************************************
3500 * WINSPOOL_GetDefaultDevMode
3502 * Get a default DevMode values for wineps.
3506 static void WINSPOOL_GetDefaultDevMode(
3508 DWORD buflen
, DWORD
*needed
)
3511 static const WCHAR szWwps
[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3513 /* fill default DEVMODE - should be read from ppd... */
3514 ZeroMemory( &dm
, sizeof(dm
) );
3515 memcpy(dm
.dmDeviceName
,szWwps
,sizeof szWwps
);
3516 dm
.dmSpecVersion
= DM_SPECVERSION
;
3517 dm
.dmDriverVersion
= 1;
3518 dm
.dmSize
= sizeof(DEVMODEW
);
3519 dm
.dmDriverExtra
= 0;
3521 DM_ORIENTATION
| DM_PAPERSIZE
|
3522 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3525 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3526 DM_YRESOLUTION
| DM_TTOPTION
;
3528 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3529 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3530 dm
.u1
.s1
.dmPaperLength
= 2970;
3531 dm
.u1
.s1
.dmPaperWidth
= 2100;
3533 dm
.u1
.s1
.dmScale
= 100;
3534 dm
.u1
.s1
.dmCopies
= 1;
3535 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3536 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3539 dm
.dmYResolution
= 300; /* 300dpi */
3540 dm
.dmTTOption
= DMTT_BITMAP
;
3543 /* dm.dmLogPixels */
3544 /* dm.dmBitsPerPel */
3545 /* dm.dmPelsWidth */
3546 /* dm.dmPelsHeight */
3547 /* dm.u2.dmDisplayFlags */
3548 /* dm.dmDisplayFrequency */
3549 /* dm.dmICMMethod */
3550 /* dm.dmICMIntent */
3551 /* dm.dmMediaType */
3552 /* dm.dmDitherType */
3553 /* dm.dmReserved1 */
3554 /* dm.dmReserved2 */
3555 /* dm.dmPanningWidth */
3556 /* dm.dmPanningHeight */
3558 if(buflen
>= sizeof(DEVMODEW
))
3559 memcpy(ptr
, &dm
, sizeof(DEVMODEW
));
3560 *needed
= sizeof(DEVMODEW
);
3563 /*****************************************************************************
3564 * WINSPOOL_GetDevModeFromReg
3566 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3567 * DevMode is stored either as unicode or ascii.
3569 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3571 DWORD buflen
, DWORD
*needed
)
3573 DWORD sz
= buflen
, type
;
3576 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3577 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3578 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3579 if (sz
< sizeof(DEVMODEA
))
3581 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3584 /* ensures that dmSize is not erratically bogus if registry is invalid */
3585 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3586 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3587 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3588 if (ptr
&& (buflen
>= sz
)) {
3589 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3590 memcpy(ptr
, dmW
, sz
);
3591 HeapFree(GetProcessHeap(),0,dmW
);
3597 /*********************************************************************
3598 * WINSPOOL_GetPrinter_1
3600 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3602 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3603 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3605 DWORD size
, left
= cbBuf
;
3606 BOOL space
= (cbBuf
> 0);
3611 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3612 if(space
&& size
<= left
) {
3613 pi1
->pName
= (LPWSTR
)ptr
;
3621 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3622 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3623 if(space
&& size
<= left
) {
3624 pi1
->pDescription
= (LPWSTR
)ptr
;
3632 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3633 if(space
&& size
<= left
) {
3634 pi1
->pComment
= (LPWSTR
)ptr
;
3642 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3644 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3645 memset(pi1
, 0, sizeof(*pi1
));
3649 /*********************************************************************
3650 * WINSPOOL_GetPrinter_2
3652 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3654 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3655 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3657 DWORD size
, left
= cbBuf
;
3658 BOOL space
= (cbBuf
> 0);
3663 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3664 if(space
&& size
<= left
) {
3665 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3672 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
3673 if(space
&& size
<= left
) {
3674 pi2
->pShareName
= (LPWSTR
)ptr
;
3681 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3682 if(space
&& size
<= left
) {
3683 pi2
->pPortName
= (LPWSTR
)ptr
;
3690 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
3691 if(space
&& size
<= left
) {
3692 pi2
->pDriverName
= (LPWSTR
)ptr
;
3699 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3700 if(space
&& size
<= left
) {
3701 pi2
->pComment
= (LPWSTR
)ptr
;
3708 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
3709 if(space
&& size
<= left
) {
3710 pi2
->pLocation
= (LPWSTR
)ptr
;
3717 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
3718 if(space
&& size
<= left
) {
3719 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3728 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
3729 if(space
&& size
<= left
) {
3730 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3737 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
3738 if(space
&& size
<= left
) {
3739 pi2
->pSepFile
= (LPWSTR
)ptr
;
3746 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
3747 if(space
&& size
<= left
) {
3748 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3755 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
3756 if(space
&& size
<= left
) {
3757 pi2
->pDatatype
= (LPWSTR
)ptr
;
3764 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
3765 if(space
&& size
<= left
) {
3766 pi2
->pParameters
= (LPWSTR
)ptr
;
3774 pi2
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
3775 pi2
->Priority
= get_dword_from_reg( hkeyPrinter
, PriorityW
);
3776 pi2
->DefaultPriority
= get_dword_from_reg( hkeyPrinter
, Default_PriorityW
);
3777 pi2
->StartTime
= get_dword_from_reg( hkeyPrinter
, StartTimeW
);
3778 pi2
->UntilTime
= get_dword_from_reg( hkeyPrinter
, UntilTimeW
);
3781 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3782 memset(pi2
, 0, sizeof(*pi2
));
3787 /*********************************************************************
3788 * WINSPOOL_GetPrinter_4
3790 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3792 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3793 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3795 DWORD size
, left
= cbBuf
;
3796 BOOL space
= (cbBuf
> 0);
3801 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3802 if(space
&& size
<= left
) {
3803 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3811 pi4
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
3814 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3815 memset(pi4
, 0, sizeof(*pi4
));
3820 /*********************************************************************
3821 * WINSPOOL_GetPrinter_5
3823 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3825 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3826 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3828 DWORD size
, left
= cbBuf
;
3829 BOOL space
= (cbBuf
> 0);
3834 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3835 if(space
&& size
<= left
) {
3836 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3843 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3844 if(space
&& size
<= left
) {
3845 pi5
->pPortName
= (LPWSTR
)ptr
;
3853 pi5
->Attributes
= get_dword_from_reg( hkeyPrinter
, AttributesW
);
3854 pi5
->DeviceNotSelectedTimeout
= get_dword_from_reg( hkeyPrinter
, dnsTimeoutW
);
3855 pi5
->TransmissionRetryTimeout
= get_dword_from_reg( hkeyPrinter
, txTimeoutW
);
3858 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3859 memset(pi5
, 0, sizeof(*pi5
));
3864 /*********************************************************************
3865 * WINSPOOL_GetPrinter_7
3867 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3869 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
3870 DWORD cbBuf
, LPDWORD pcbNeeded
)
3872 DWORD size
, left
= cbBuf
;
3873 BOOL space
= (cbBuf
> 0);
3878 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
3881 size
= sizeof(pi7
->pszObjectGUID
);
3883 if (space
&& size
<= left
) {
3884 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
3891 /* We do not have a Directory Service */
3892 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
3895 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
3896 memset(pi7
, 0, sizeof(*pi7
));
3901 /*********************************************************************
3902 * WINSPOOL_GetPrinter_9
3904 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3906 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
3907 DWORD cbBuf
, LPDWORD pcbNeeded
)
3910 BOOL space
= (cbBuf
> 0);
3914 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
3915 if(space
&& size
<= cbBuf
) {
3916 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3923 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
3924 if(space
&& size
<= cbBuf
) {
3925 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3931 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
3932 memset(pi9
, 0, sizeof(*pi9
));
3937 /*****************************************************************************
3938 * GetPrinterW [WINSPOOL.@]
3940 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3941 DWORD cbBuf
, LPDWORD pcbNeeded
)
3943 DWORD size
, needed
= 0, err
;
3948 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3950 err
= WINSPOOL_GetOpenedPrinterRegKey( hPrinter
, &hkeyPrinter
);
3953 SetLastError( err
);
3960 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3962 size
= sizeof(PRINTER_INFO_2W
);
3964 ptr
= pPrinter
+ size
;
3966 memset(pPrinter
, 0, size
);
3971 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
3978 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3980 size
= sizeof(PRINTER_INFO_4W
);
3982 ptr
= pPrinter
+ size
;
3984 memset(pPrinter
, 0, size
);
3989 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
3997 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3999 size
= sizeof(PRINTER_INFO_5W
);
4001 ptr
= pPrinter
+ size
;
4003 memset(pPrinter
, 0, size
);
4009 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
4017 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4019 size
= sizeof(PRINTER_INFO_6
);
4020 if (size
<= cbBuf
) {
4021 /* FIXME: We do not update the status yet */
4022 pi6
->dwStatus
= get_dword_from_reg( hkeyPrinter
, StatusW
);
4034 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4036 size
= sizeof(PRINTER_INFO_7W
);
4037 if (size
<= cbBuf
) {
4038 ptr
= pPrinter
+ size
;
4040 memset(pPrinter
, 0, size
);
4046 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
4053 /* 8 is the global default printer info and 9 already gets it instead of the per-user one */
4054 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
4058 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4060 size
= sizeof(PRINTER_INFO_9W
);
4062 ptr
= pPrinter
+ size
;
4064 memset(pPrinter
, 0, size
);
4070 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
4077 FIXME("Unimplemented level %d\n", Level
);
4078 SetLastError(ERROR_INVALID_LEVEL
);
4079 RegCloseKey(hkeyPrinter
);
4083 RegCloseKey(hkeyPrinter
);
4085 TRACE("returning %d needed = %d\n", ret
, needed
);
4086 if(pcbNeeded
) *pcbNeeded
= needed
;
4088 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4092 /*****************************************************************************
4093 * GetPrinterA [WINSPOOL.@]
4095 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4096 DWORD cbBuf
, LPDWORD pcbNeeded
)
4102 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4104 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
4106 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
4107 HeapFree(GetProcessHeap(), 0, buf
);
4112 /*****************************************************************************
4113 * WINSPOOL_EnumPrintersW
4115 * Implementation of EnumPrintersW
4117 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
4118 DWORD dwLevel
, LPBYTE lpbPrinters
,
4119 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4120 LPDWORD lpdwReturned
)
4123 HKEY hkeyPrinters
, hkeyPrinter
;
4124 WCHAR PrinterName
[255];
4125 DWORD needed
= 0, number
= 0;
4126 DWORD used
, i
, left
;
4130 memset(lpbPrinters
, 0, cbBuf
);
4136 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4137 if(dwType
== PRINTER_ENUM_DEFAULT
)
4140 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4141 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4142 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4144 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4150 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4151 FIXME("dwType = %08x\n", dwType
);
4152 SetLastError(ERROR_INVALID_FLAGS
);
4156 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4158 ERR("Can't create Printers key\n");
4162 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4163 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4164 RegCloseKey(hkeyPrinters
);
4165 ERR("Can't query Printers key\n");
4168 TRACE("Found %d printers\n", number
);
4172 used
= number
* sizeof(PRINTER_INFO_1W
);
4175 used
= number
* sizeof(PRINTER_INFO_2W
);
4178 used
= number
* sizeof(PRINTER_INFO_4W
);
4181 used
= number
* sizeof(PRINTER_INFO_5W
);
4185 SetLastError(ERROR_INVALID_LEVEL
);
4186 RegCloseKey(hkeyPrinters
);
4189 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4191 for(i
= 0; i
< number
; i
++) {
4192 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4194 ERR("Can't enum key number %d\n", i
);
4195 RegCloseKey(hkeyPrinters
);
4198 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4199 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4201 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4202 RegCloseKey(hkeyPrinters
);
4207 buf
= lpbPrinters
+ used
;
4208 left
= cbBuf
- used
;
4216 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4219 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4222 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4225 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4228 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4231 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4234 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4237 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4240 ERR("Shouldn't be here!\n");
4241 RegCloseKey(hkeyPrinter
);
4242 RegCloseKey(hkeyPrinters
);
4245 RegCloseKey(hkeyPrinter
);
4247 RegCloseKey(hkeyPrinters
);
4254 memset(lpbPrinters
, 0, cbBuf
);
4255 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4259 *lpdwReturned
= number
;
4260 SetLastError(ERROR_SUCCESS
);
4265 /******************************************************************
4266 * EnumPrintersW [WINSPOOL.@]
4268 * Enumerates the available printers, print servers and print
4269 * providers, depending on the specified flags, name and level.
4273 * If level is set to 1:
4274 * Returns an array of PRINTER_INFO_1 data structures in the
4275 * lpbPrinters buffer.
4277 * If level is set to 2:
4278 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4279 * Returns an array of PRINTER_INFO_2 data structures in the
4280 * lpbPrinters buffer. Note that according to MSDN also an
4281 * OpenPrinter should be performed on every remote printer.
4283 * If level is set to 4 (officially WinNT only):
4284 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4285 * Fast: Only the registry is queried to retrieve printer names,
4286 * no connection to the driver is made.
4287 * Returns an array of PRINTER_INFO_4 data structures in the
4288 * lpbPrinters buffer.
4290 * If level is set to 5 (officially WinNT4/Win9x only):
4291 * Fast: Only the registry is queried to retrieve printer names,
4292 * no connection to the driver is made.
4293 * Returns an array of PRINTER_INFO_5 data structures in the
4294 * lpbPrinters buffer.
4296 * If level set to 3 or 6+:
4297 * returns zero (failure!)
4299 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4303 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4304 * - Only levels 2, 4 and 5 are implemented at the moment.
4305 * - 16-bit printer drivers are not enumerated.
4306 * - Returned amount of bytes used/needed does not match the real Windoze
4307 * implementation (as in this implementation, all strings are part
4308 * of the buffer, whereas Win32 keeps them somewhere else)
4309 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4312 * - In a regular Wine installation, no registry settings for printers
4313 * exist, which makes this function return an empty list.
4315 BOOL WINAPI
EnumPrintersW(
4316 DWORD dwType
, /* [in] Types of print objects to enumerate */
4317 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4318 DWORD dwLevel
, /* [in] type of printer info structure */
4319 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4320 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4321 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4322 LPDWORD lpdwReturned
/* [out] number of entries returned */
4325 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4326 lpdwNeeded
, lpdwReturned
);
4329 /******************************************************************
4330 * EnumPrintersA [WINSPOOL.@]
4335 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4336 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4339 UNICODE_STRING pNameU
;
4343 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4344 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4346 pNameW
= asciitounicode(&pNameU
, pName
);
4348 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4349 MS Office need this */
4350 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4352 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4354 RtlFreeUnicodeString(&pNameU
);
4356 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4358 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4362 /*****************************************************************************
4363 * WINSPOOL_GetDriverInfoFromReg [internal]
4365 * Enters the information from the registry into the DRIVER_INFO struct
4368 * zero if the printer driver does not exist in the registry
4369 * (only if Level > 1) otherwise nonzero
4371 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4374 const printenv_t
* env
,
4376 LPBYTE ptr
, /* DRIVER_INFO */
4377 LPBYTE pDriverStrings
, /* strings buffer */
4378 DWORD cbBuf
, /* size of string buffer */
4379 LPDWORD pcbNeeded
) /* space needed for str. */
4383 WCHAR driverdir
[MAX_PATH
];
4385 LPBYTE strPtr
= pDriverStrings
;
4386 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4388 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4389 debugstr_w(DriverName
), env
,
4390 Level
, di
, pDriverStrings
, cbBuf
);
4392 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4394 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4395 if (*pcbNeeded
<= cbBuf
)
4396 strcpyW((LPWSTR
)strPtr
, DriverName
);
4398 /* pName for level 1 has a different offset! */
4400 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4404 /* .cVersion and .pName for level > 1 */
4406 di
->cVersion
= env
->driverversion
;
4407 di
->pName
= (LPWSTR
) strPtr
;
4408 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4411 /* Reserve Space for the largest subdir and a Backslash*/
4412 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4413 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4414 /* Should never Fail */
4417 lstrcatW(driverdir
, env
->versionsubdir
);
4418 lstrcatW(driverdir
, backslashW
);
4420 /* dirlen must not include the terminating zero */
4421 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4423 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4424 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4425 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4430 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4433 if (*pcbNeeded
<= cbBuf
) {
4434 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4435 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4436 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4439 /* .pDriverPath is the Graphics rendering engine.
4440 The full Path is required to avoid a crash in some apps */
4441 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4443 if (*pcbNeeded
<= cbBuf
)
4444 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4446 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4447 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4450 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4451 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4453 if (*pcbNeeded
<= cbBuf
)
4454 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4456 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4457 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4460 /* .pConfigFile is the Driver user Interface */
4461 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4463 if (*pcbNeeded
<= cbBuf
)
4464 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4466 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4467 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4471 RegCloseKey(hkeyDriver
);
4472 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4477 RegCloseKey(hkeyDriver
);
4478 FIXME("level 5: incomplete\n");
4483 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4485 if (*pcbNeeded
<= cbBuf
)
4486 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4488 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4489 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4492 /* .pDependentFiles */
4493 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4495 if (*pcbNeeded
<= cbBuf
)
4496 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4498 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4499 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4501 else if (GetVersion() & 0x80000000) {
4502 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4503 size
= 2 * sizeof(WCHAR
);
4505 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4507 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4508 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4511 /* .pMonitorName is the optional Language Monitor */
4512 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4514 if (*pcbNeeded
<= cbBuf
)
4515 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4517 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4518 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4521 /* .pDefaultDataType */
4522 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
4524 if(*pcbNeeded
<= cbBuf
)
4525 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
4527 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4528 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4532 RegCloseKey(hkeyDriver
);
4533 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4537 /* .pszzPreviousNames */
4538 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
4540 if(*pcbNeeded
<= cbBuf
)
4541 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
4543 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4544 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4548 RegCloseKey(hkeyDriver
);
4549 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4553 /* support is missing, but not important enough for a FIXME */
4554 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4557 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
4559 if(*pcbNeeded
<= cbBuf
)
4560 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
4562 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4563 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4567 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
4569 if(*pcbNeeded
<= cbBuf
)
4570 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
4572 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4573 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4576 /* .pszHardwareID */
4577 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
4579 if(*pcbNeeded
<= cbBuf
)
4580 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
4582 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4583 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4587 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
4589 if(*pcbNeeded
<= cbBuf
)
4590 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
4592 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4593 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4597 RegCloseKey(hkeyDriver
);
4601 /* support is missing, but not important enough for a FIXME */
4602 TRACE("level 8: incomplete\n");
4604 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4605 RegCloseKey(hkeyDriver
);
4609 /*****************************************************************************
4610 * GetPrinterDriverW [WINSPOOL.@]
4612 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4613 DWORD Level
, LPBYTE pDriverInfo
,
4614 DWORD cbBuf
, LPDWORD pcbNeeded
)
4617 WCHAR DriverName
[100];
4618 DWORD ret
, type
, size
, needed
= 0;
4620 HKEY hkeyPrinter
, hkeyDrivers
;
4621 const printenv_t
* env
;
4623 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4624 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4627 ZeroMemory(pDriverInfo
, cbBuf
);
4629 if (!(name
= get_opened_printer_name(hPrinter
))) {
4630 SetLastError(ERROR_INVALID_HANDLE
);
4634 if (Level
< 1 || Level
== 7 || Level
> 8) {
4635 SetLastError(ERROR_INVALID_LEVEL
);
4639 env
= validate_envW(pEnvironment
);
4640 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4642 ret
= open_printer_reg_key( name
, &hkeyPrinter
);
4645 ERR( "Can't find opened printer %s in registry\n", debugstr_w(name
) );
4646 SetLastError( ret
);
4650 size
= sizeof(DriverName
);
4652 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4653 (LPBYTE
)DriverName
, &size
);
4654 RegCloseKey(hkeyPrinter
);
4655 if(ret
!= ERROR_SUCCESS
) {
4656 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4660 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4662 ERR("Can't create Drivers key\n");
4666 size
= di_sizeof
[Level
];
4667 if ((size
<= cbBuf
) && pDriverInfo
)
4668 ptr
= pDriverInfo
+ size
;
4670 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4671 env
, Level
, pDriverInfo
, ptr
,
4672 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4674 RegCloseKey(hkeyDrivers
);
4678 RegCloseKey(hkeyDrivers
);
4680 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4681 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4682 if(cbBuf
>= size
+ needed
) return TRUE
;
4683 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4687 /*****************************************************************************
4688 * GetPrinterDriverA [WINSPOOL.@]
4690 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4691 DWORD Level
, LPBYTE pDriverInfo
,
4692 DWORD cbBuf
, LPDWORD pcbNeeded
)
4695 UNICODE_STRING pEnvW
;
4701 ZeroMemory(pDriverInfo
, cbBuf
);
4702 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4705 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4706 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
4709 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
4711 HeapFree(GetProcessHeap(), 0, buf
);
4713 RtlFreeUnicodeString(&pEnvW
);
4717 /*****************************************************************************
4718 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4720 * Return the PATH for the Printer-Drivers (UNICODE)
4723 * pName [I] Servername (NT only) or NULL (local Computer)
4724 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4725 * Level [I] Structure-Level (must be 1)
4726 * pDriverDirectory [O] PTR to Buffer that receives the Result
4727 * cbBuf [I] Size of Buffer at pDriverDirectory
4728 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4729 * required for pDriverDirectory
4732 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4733 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4734 * if cbBuf is too small
4736 * Native Values returned in pDriverDirectory on Success:
4737 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4738 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4739 *| win9x(Windows 4.0): "%winsysdir%"
4741 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4744 *- Only NULL or "" is supported for pName
4747 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4748 DWORD Level
, LPBYTE pDriverDirectory
,
4749 DWORD cbBuf
, LPDWORD pcbNeeded
)
4751 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4752 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4754 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4757 /* (Level != 1) is ignored in win9x */
4758 SetLastError(ERROR_INVALID_LEVEL
);
4761 if (pcbNeeded
== NULL
) {
4762 /* (pcbNeeded == NULL) is ignored in win9x */
4763 SetLastError(RPC_X_NULL_REF_POINTER
);
4767 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
4768 pDriverDirectory
, cbBuf
, pcbNeeded
);
4773 /*****************************************************************************
4774 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4776 * Return the PATH for the Printer-Drivers (ANSI)
4778 * See GetPrinterDriverDirectoryW.
4781 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4784 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4785 DWORD Level
, LPBYTE pDriverDirectory
,
4786 DWORD cbBuf
, LPDWORD pcbNeeded
)
4788 UNICODE_STRING nameW
, environmentW
;
4791 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4792 WCHAR
*driverDirectoryW
= NULL
;
4794 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4795 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4797 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4799 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4800 else nameW
.Buffer
= NULL
;
4801 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4802 else environmentW
.Buffer
= NULL
;
4804 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4805 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4808 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4809 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4811 *pcbNeeded
= needed
;
4812 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4814 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4816 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4818 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4819 RtlFreeUnicodeString(&environmentW
);
4820 RtlFreeUnicodeString(&nameW
);
4825 /*****************************************************************************
4826 * AddPrinterDriverA [WINSPOOL.@]
4828 * See AddPrinterDriverW.
4831 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4833 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4834 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4837 /******************************************************************************
4838 * AddPrinterDriverW (WINSPOOL.@)
4840 * Install a Printer Driver
4843 * pName [I] Servername or NULL (local Computer)
4844 * level [I] Level for the supplied DRIVER_INFO_*W struct
4845 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4852 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4854 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
4855 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4858 /*****************************************************************************
4859 * AddPrintProcessorA [WINSPOOL.@]
4861 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4862 LPSTR pPrintProcessorName
)
4864 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4865 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4869 /*****************************************************************************
4870 * AddPrintProcessorW [WINSPOOL.@]
4872 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4873 LPWSTR pPrintProcessorName
)
4875 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4876 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4880 /*****************************************************************************
4881 * AddPrintProvidorA [WINSPOOL.@]
4883 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4885 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4889 /*****************************************************************************
4890 * AddPrintProvidorW [WINSPOOL.@]
4892 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4894 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4898 /*****************************************************************************
4899 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4901 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4902 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4904 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4905 pDevModeOutput
, pDevModeInput
);
4909 /*****************************************************************************
4910 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4912 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4913 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4915 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4916 pDevModeOutput
, pDevModeInput
);
4920 /*****************************************************************************
4921 * PrinterProperties [WINSPOOL.@]
4923 * Displays a dialog to set the properties of the printer.
4926 * nonzero on success or zero on failure
4929 * implemented as stub only
4931 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4932 HANDLE hPrinter
/* [in] handle to printer object */
4934 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4935 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4939 /*****************************************************************************
4940 * EnumJobsA [WINSPOOL.@]
4943 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4944 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4947 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4948 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4950 if(pcbNeeded
) *pcbNeeded
= 0;
4951 if(pcReturned
) *pcReturned
= 0;
4956 /*****************************************************************************
4957 * EnumJobsW [WINSPOOL.@]
4960 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4961 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4964 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4965 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4967 if(pcbNeeded
) *pcbNeeded
= 0;
4968 if(pcReturned
) *pcReturned
= 0;
4972 /*****************************************************************************
4973 * WINSPOOL_EnumPrinterDrivers [internal]
4975 * Delivers information about all printer drivers installed on the
4976 * localhost or a given server
4979 * nonzero on success or zero on failure. If the buffer for the returned
4980 * information is too small the function will return an error
4983 * - only implemented for localhost, foreign hosts will return an error
4985 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
4986 DWORD Level
, LPBYTE pDriverInfo
,
4988 DWORD cbBuf
, LPDWORD pcbNeeded
,
4989 LPDWORD pcFound
, DWORD data_offset
)
4993 const printenv_t
* env
;
4995 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4996 debugstr_w(pName
), debugstr_w(pEnvironment
),
4997 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
4999 env
= validate_envW(pEnvironment
);
5000 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5004 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
5006 ERR("Can't open Drivers key\n");
5010 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
5011 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5012 RegCloseKey(hkeyDrivers
);
5013 ERR("Can't query Drivers key\n");
5016 TRACE("Found %d Drivers\n", *pcFound
);
5018 /* get size of single struct
5019 * unicode and ascii structure have the same size
5021 size
= di_sizeof
[Level
];
5023 if (data_offset
== 0)
5024 data_offset
= size
* (*pcFound
);
5025 *pcbNeeded
= data_offset
;
5027 for( i
= 0; i
< *pcFound
; i
++) {
5028 WCHAR DriverNameW
[255];
5029 PBYTE table_ptr
= NULL
;
5030 PBYTE data_ptr
= NULL
;
5033 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
5035 ERR("Can't enum key number %d\n", i
);
5036 RegCloseKey(hkeyDrivers
);
5040 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
5041 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
5042 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
5043 data_ptr
= pDriverInfo
+ *pcbNeeded
;
5045 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5046 env
, Level
, table_ptr
, data_ptr
,
5047 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5049 RegCloseKey(hkeyDrivers
);
5053 *pcbNeeded
+= needed
;
5056 RegCloseKey(hkeyDrivers
);
5058 if(cbBuf
< *pcbNeeded
){
5059 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5066 /*****************************************************************************
5067 * EnumPrinterDriversW [WINSPOOL.@]
5069 * see function EnumPrinterDrivers for RETURNS, BUGS
5071 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5072 LPBYTE pDriverInfo
, DWORD cbBuf
,
5073 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5075 static const WCHAR allW
[] = {'a','l','l',0};
5079 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
5081 SetLastError(RPC_X_NULL_REF_POINTER
);
5085 /* check for local drivers */
5086 if((pName
) && (pName
[0])) {
5087 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5088 SetLastError(ERROR_ACCESS_DENIED
);
5092 /* check input parameter */
5093 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5094 SetLastError(ERROR_INVALID_LEVEL
);
5098 if(pDriverInfo
&& cbBuf
> 0)
5099 memset( pDriverInfo
, 0, cbBuf
);
5101 /* Exception: pull all printers */
5102 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
5104 DWORD i
, needed
, bufsize
= cbBuf
;
5105 DWORD total_needed
= 0;
5106 DWORD total_found
= 0;
5109 /* Precompute the overall total; we need this to know
5110 where pointers end and data begins (i.e. data_offset) */
5111 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5114 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5115 NULL
, 0, 0, &needed
, &found
, 0);
5116 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5117 total_needed
+= needed
;
5118 total_found
+= found
;
5121 data_offset
= di_sizeof
[Level
] * total_found
;
5126 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5129 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5130 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
5131 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5133 *pcReturned
+= found
;
5134 *pcbNeeded
= needed
;
5135 data_offset
= needed
;
5136 total_found
+= found
;
5141 /* Normal behavior */
5142 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5143 0, cbBuf
, pcbNeeded
, &found
, 0);
5145 *pcReturned
= found
;
5150 /*****************************************************************************
5151 * EnumPrinterDriversA [WINSPOOL.@]
5153 * see function EnumPrinterDrivers for RETURNS, BUGS
5155 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5156 LPBYTE pDriverInfo
, DWORD cbBuf
,
5157 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5160 UNICODE_STRING pNameW
, pEnvironmentW
;
5161 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5165 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
5167 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5168 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5170 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
5171 buf
, cbBuf
, pcbNeeded
, pcReturned
);
5173 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
5175 HeapFree(GetProcessHeap(), 0, buf
);
5177 RtlFreeUnicodeString(&pNameW
);
5178 RtlFreeUnicodeString(&pEnvironmentW
);
5183 /******************************************************************************
5184 * EnumPortsA (WINSPOOL.@)
5189 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5190 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5193 LPBYTE bufferW
= NULL
;
5194 LPWSTR nameW
= NULL
;
5196 DWORD numentries
= 0;
5199 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5200 cbBuf
, pcbNeeded
, pcReturned
);
5202 /* convert servername to unicode */
5204 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5205 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5206 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5208 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5209 needed
= cbBuf
* sizeof(WCHAR
);
5210 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5211 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5213 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5214 if (pcbNeeded
) needed
= *pcbNeeded
;
5215 /* HeapReAlloc return NULL, when bufferW was NULL */
5216 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5217 HeapAlloc(GetProcessHeap(), 0, needed
);
5219 /* Try again with the large Buffer */
5220 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5222 needed
= pcbNeeded
? *pcbNeeded
: 0;
5223 numentries
= pcReturned
? *pcReturned
: 0;
5226 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5227 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5230 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5231 DWORD entrysize
= 0;
5234 LPPORT_INFO_2W pi2w
;
5235 LPPORT_INFO_2A pi2a
;
5238 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5240 /* First pass: calculate the size for all Entries */
5241 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5242 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5244 while (index
< numentries
) {
5246 needed
+= entrysize
; /* PORT_INFO_?A */
5247 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5249 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5250 NULL
, 0, NULL
, NULL
);
5252 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5253 NULL
, 0, NULL
, NULL
);
5254 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5255 NULL
, 0, NULL
, NULL
);
5257 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5258 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5259 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5262 /* check for errors and quit on failure */
5263 if (cbBuf
< needed
) {
5264 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5268 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5269 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5270 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5271 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5272 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5274 /* Second Pass: Fill the User Buffer (if we have one) */
5275 while ((index
< numentries
) && pPorts
) {
5277 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5278 pi2a
->pPortName
= ptr
;
5279 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5280 ptr
, cbBuf
, NULL
, NULL
);
5284 pi2a
->pMonitorName
= ptr
;
5285 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5286 ptr
, cbBuf
, NULL
, NULL
);
5290 pi2a
->pDescription
= ptr
;
5291 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5292 ptr
, cbBuf
, NULL
, NULL
);
5296 pi2a
->fPortType
= pi2w
->fPortType
;
5297 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5300 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5301 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5302 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5307 if (pcbNeeded
) *pcbNeeded
= needed
;
5308 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5310 HeapFree(GetProcessHeap(), 0, nameW
);
5311 HeapFree(GetProcessHeap(), 0, bufferW
);
5313 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5314 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5320 /******************************************************************************
5321 * EnumPortsW (WINSPOOL.@)
5323 * Enumerate available Ports
5326 * pName [I] Servername or NULL (local Computer)
5327 * Level [I] Structure-Level (1 or 2)
5328 * pPorts [O] PTR to Buffer that receives the Result
5329 * cbBuf [I] Size of Buffer at pPorts
5330 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5331 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5335 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5338 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5341 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5342 cbBuf
, pcbNeeded
, pcReturned
);
5344 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5346 /* Level is not checked in win9x */
5347 if (!Level
|| (Level
> 2)) {
5348 WARN("level (%d) is ignored in win9x\n", Level
);
5349 SetLastError(ERROR_INVALID_LEVEL
);
5352 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5353 SetLastError(RPC_X_NULL_REF_POINTER
);
5357 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5360 /******************************************************************************
5361 * GetDefaultPrinterW (WINSPOOL.@)
5364 * This function must read the value from data 'device' of key
5365 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5367 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5371 WCHAR
*buffer
, *ptr
;
5375 SetLastError(ERROR_INVALID_PARAMETER
);
5379 /* make the buffer big enough for the stuff from the profile/registry,
5380 * the content must fit into the local buffer to compute the correct
5381 * size even if the extern buffer is too small or not given.
5382 * (20 for ,driver,port) */
5384 len
= max(100, (insize
+ 20));
5385 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5387 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5389 SetLastError (ERROR_FILE_NOT_FOUND
);
5393 TRACE("%s\n", debugstr_w(buffer
));
5395 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5397 SetLastError(ERROR_INVALID_NAME
);
5403 *namesize
= strlenW(buffer
) + 1;
5404 if(!name
|| (*namesize
> insize
))
5406 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5410 strcpyW(name
, buffer
);
5413 HeapFree( GetProcessHeap(), 0, buffer
);
5418 /******************************************************************************
5419 * GetDefaultPrinterA (WINSPOOL.@)
5421 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5425 WCHAR
*bufferW
= NULL
;
5429 SetLastError(ERROR_INVALID_PARAMETER
);
5433 if(name
&& *namesize
) {
5435 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5438 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5443 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5447 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5450 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5453 HeapFree( GetProcessHeap(), 0, bufferW
);
5458 /******************************************************************************
5459 * SetDefaultPrinterW (WINSPOOL.204)
5461 * Set the Name of the Default Printer
5464 * pszPrinter [I] Name of the Printer or NULL
5471 * When the Parameter is NULL or points to an Empty String and
5472 * a Default Printer was already present, then this Function changes nothing.
5473 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5474 * the First enumerated local Printer is used.
5477 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5479 WCHAR default_printer
[MAX_PATH
];
5480 LPWSTR buffer
= NULL
;
5486 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5487 if ((pszPrinter
== NULL
) || (pszPrinter
[0] == '\0')) {
5489 default_printer
[0] = '\0';
5490 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5492 /* if we have a default Printer, do nothing. */
5493 if (GetDefaultPrinterW(default_printer
, &size
))
5497 /* we have no default Printer: search local Printers and use the first */
5498 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE
, PrintersW
, 0, KEY_READ
, &hreg
)) {
5500 default_printer
[0] = '\0';
5501 size
= sizeof(default_printer
)/sizeof(WCHAR
);
5502 if (!RegEnumKeyExW(hreg
, 0, default_printer
, &size
, NULL
, NULL
, NULL
, NULL
)) {
5504 pszPrinter
= default_printer
;
5505 TRACE("using %s\n", debugstr_w(pszPrinter
));
5510 if (pszPrinter
== NULL
) {
5511 TRACE("no local printer found\n");
5512 SetLastError(ERROR_FILE_NOT_FOUND
);
5517 /* "pszPrinter" is never empty or NULL here. */
5518 namelen
= lstrlenW(pszPrinter
);
5519 size
= namelen
+ (MAX_PATH
* 2) + 3; /* printer,driver,port and a 0 */
5520 buffer
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WCHAR
));
5522 (RegOpenKeyExW(HKEY_CURRENT_USER
, user_printers_reg_key
, 0, KEY_READ
, &hreg
) != ERROR_SUCCESS
)) {
5523 HeapFree(GetProcessHeap(), 0, buffer
);
5524 SetLastError(ERROR_FILE_NOT_FOUND
);
5528 /* read the devices entry for the printer (driver,port) to build the string for the
5529 default device entry (printer,driver,port) */
5530 memcpy(buffer
, pszPrinter
, namelen
* sizeof(WCHAR
));
5531 buffer
[namelen
] = ',';
5532 namelen
++; /* move index to the start of the driver */
5534 size
= ((MAX_PATH
* 2) + 2) * sizeof(WCHAR
); /* driver,port and a 0 */
5535 lres
= RegQueryValueExW(hreg
, pszPrinter
, NULL
, NULL
, (LPBYTE
) (&buffer
[namelen
]), &size
);
5537 TRACE("set device to %s\n", debugstr_w(buffer
));
5539 if (!WriteProfileStringW(windowsW
, deviceW
, buffer
)) {
5540 TRACE("failed to set the device entry: %d\n", GetLastError());
5541 lres
= ERROR_INVALID_PRINTER_NAME
;
5544 /* remove the next section, when INIFileMapping is implemented */
5547 if (!RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hdev
)) {
5548 RegSetValueExW(hdev
, deviceW
, 0, REG_SZ
, (LPBYTE
)buffer
, (lstrlenW(buffer
) + 1) * sizeof(WCHAR
));
5555 if (lres
!= ERROR_FILE_NOT_FOUND
)
5556 FIXME("RegQueryValueExW failed with %d for %s\n", lres
, debugstr_w(pszPrinter
));
5558 SetLastError(ERROR_INVALID_PRINTER_NAME
);
5562 HeapFree(GetProcessHeap(), 0, buffer
);
5563 return (lres
== ERROR_SUCCESS
);
5566 /******************************************************************************
5567 * SetDefaultPrinterA (WINSPOOL.202)
5569 * See SetDefaultPrinterW.
5572 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5574 LPWSTR bufferW
= NULL
;
5577 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5579 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, NULL
, 0);
5580 bufferW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5581 if (bufferW
) MultiByteToWideChar(CP_ACP
, 0, pszPrinter
, -1, bufferW
, len
);
5583 res
= SetDefaultPrinterW(bufferW
);
5584 HeapFree(GetProcessHeap(), 0, bufferW
);
5588 /******************************************************************************
5589 * SetPrinterDataExA (WINSPOOL.@)
5591 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5592 LPCSTR pValueName
, DWORD Type
,
5593 LPBYTE pData
, DWORD cbData
)
5595 HKEY hkeyPrinter
, hkeySubkey
;
5598 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5599 debugstr_a(pValueName
), Type
, pData
, cbData
);
5601 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5605 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5607 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5608 RegCloseKey(hkeyPrinter
);
5611 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5612 RegCloseKey(hkeySubkey
);
5613 RegCloseKey(hkeyPrinter
);
5617 /******************************************************************************
5618 * SetPrinterDataExW (WINSPOOL.@)
5620 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5621 LPCWSTR pValueName
, DWORD Type
,
5622 LPBYTE pData
, DWORD cbData
)
5624 HKEY hkeyPrinter
, hkeySubkey
;
5627 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5628 debugstr_w(pValueName
), Type
, pData
, cbData
);
5630 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5634 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5636 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5637 RegCloseKey(hkeyPrinter
);
5640 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5641 RegCloseKey(hkeySubkey
);
5642 RegCloseKey(hkeyPrinter
);
5646 /******************************************************************************
5647 * SetPrinterDataA (WINSPOOL.@)
5649 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5650 LPBYTE pData
, DWORD cbData
)
5652 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5656 /******************************************************************************
5657 * SetPrinterDataW (WINSPOOL.@)
5659 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5660 LPBYTE pData
, DWORD cbData
)
5662 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5666 /******************************************************************************
5667 * GetPrinterDataExA (WINSPOOL.@)
5669 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5670 LPCSTR pValueName
, LPDWORD pType
,
5671 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5673 opened_printer_t
*printer
;
5674 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5677 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
5678 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5680 printer
= get_opened_printer(hPrinter
);
5681 if(!printer
) return ERROR_INVALID_HANDLE
;
5683 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5684 if (ret
) return ret
;
5686 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5688 if (printer
->name
) {
5690 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5692 RegCloseKey(hkeyPrinters
);
5695 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5696 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
5697 RegCloseKey(hkeyPrinter
);
5698 RegCloseKey(hkeyPrinters
);
5703 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5704 0, pType
, pData
, pcbNeeded
);
5706 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5708 RegCloseKey(hkeySubkey
);
5709 RegCloseKey(hkeyPrinter
);
5710 RegCloseKey(hkeyPrinters
);
5712 TRACE("--> %d\n", ret
);
5716 /******************************************************************************
5717 * GetPrinterDataExW (WINSPOOL.@)
5719 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5720 LPCWSTR pValueName
, LPDWORD pType
,
5721 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5723 opened_printer_t
*printer
;
5724 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5727 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
5728 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5730 printer
= get_opened_printer(hPrinter
);
5731 if(!printer
) return ERROR_INVALID_HANDLE
;
5733 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5734 if (ret
) return ret
;
5736 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5738 if (printer
->name
) {
5740 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5742 RegCloseKey(hkeyPrinters
);
5745 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5746 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
5747 RegCloseKey(hkeyPrinter
);
5748 RegCloseKey(hkeyPrinters
);
5753 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5754 0, pType
, pData
, pcbNeeded
);
5756 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5758 RegCloseKey(hkeySubkey
);
5759 RegCloseKey(hkeyPrinter
);
5760 RegCloseKey(hkeyPrinters
);
5762 TRACE("--> %d\n", ret
);
5766 /******************************************************************************
5767 * GetPrinterDataA (WINSPOOL.@)
5769 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5770 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5772 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5773 pData
, nSize
, pcbNeeded
);
5776 /******************************************************************************
5777 * GetPrinterDataW (WINSPOOL.@)
5779 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5780 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5782 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5783 pData
, nSize
, pcbNeeded
);
5786 /*******************************************************************************
5787 * EnumPrinterDataExW [WINSPOOL.@]
5789 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5790 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5791 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5793 HKEY hkPrinter
, hkSubKey
;
5794 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5795 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5800 PPRINTER_ENUM_VALUESW ppev
;
5802 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5804 if (pKeyName
== NULL
|| *pKeyName
== 0)
5805 return ERROR_INVALID_PARAMETER
;
5807 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5808 if (ret
!= ERROR_SUCCESS
)
5810 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5815 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5816 if (ret
!= ERROR_SUCCESS
)
5818 r
= RegCloseKey (hkPrinter
);
5819 if (r
!= ERROR_SUCCESS
)
5820 WARN ("RegCloseKey returned %i\n", r
);
5821 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5822 debugstr_w (pKeyName
), ret
);
5826 ret
= RegCloseKey (hkPrinter
);
5827 if (ret
!= ERROR_SUCCESS
)
5829 ERR ("RegCloseKey returned %i\n", ret
);
5830 r
= RegCloseKey (hkSubKey
);
5831 if (r
!= ERROR_SUCCESS
)
5832 WARN ("RegCloseKey returned %i\n", r
);
5836 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5837 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5838 if (ret
!= ERROR_SUCCESS
)
5840 r
= RegCloseKey (hkSubKey
);
5841 if (r
!= ERROR_SUCCESS
)
5842 WARN ("RegCloseKey returned %i\n", r
);
5843 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5847 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5848 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5850 if (cValues
== 0) /* empty key */
5852 r
= RegCloseKey (hkSubKey
);
5853 if (r
!= ERROR_SUCCESS
)
5854 WARN ("RegCloseKey returned %i\n", r
);
5855 *pcbEnumValues
= *pnEnumValues
= 0;
5856 return ERROR_SUCCESS
;
5859 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5861 hHeap
= GetProcessHeap ();
5864 ERR ("GetProcessHeap failed\n");
5865 r
= RegCloseKey (hkSubKey
);
5866 if (r
!= ERROR_SUCCESS
)
5867 WARN ("RegCloseKey returned %i\n", r
);
5868 return ERROR_OUTOFMEMORY
;
5871 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5872 if (lpValueName
== NULL
)
5874 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5875 r
= RegCloseKey (hkSubKey
);
5876 if (r
!= ERROR_SUCCESS
)
5877 WARN ("RegCloseKey returned %i\n", r
);
5878 return ERROR_OUTOFMEMORY
;
5881 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5882 if (lpValue
== NULL
)
5884 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5885 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5886 WARN ("HeapFree failed with code %i\n", GetLastError ());
5887 r
= RegCloseKey (hkSubKey
);
5888 if (r
!= ERROR_SUCCESS
)
5889 WARN ("RegCloseKey returned %i\n", r
);
5890 return ERROR_OUTOFMEMORY
;
5893 TRACE ("pass 1: calculating buffer required for all names and values\n");
5895 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5897 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5899 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5901 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5902 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5903 NULL
, NULL
, lpValue
, &cbValueLen
);
5904 if (ret
!= ERROR_SUCCESS
)
5906 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5907 WARN ("HeapFree failed with code %i\n", GetLastError ());
5908 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5909 WARN ("HeapFree failed with code %i\n", GetLastError ());
5910 r
= RegCloseKey (hkSubKey
);
5911 if (r
!= ERROR_SUCCESS
)
5912 WARN ("RegCloseKey returned %i\n", r
);
5913 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5917 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5918 debugstr_w (lpValueName
), dwIndex
,
5919 cbValueNameLen
+ 1, cbValueLen
);
5921 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5922 cbBufSize
+= cbValueLen
;
5925 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5927 *pcbEnumValues
= cbBufSize
;
5928 *pnEnumValues
= cValues
;
5930 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5932 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5933 WARN ("HeapFree failed with code %i\n", GetLastError ());
5934 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5935 WARN ("HeapFree failed with code %i\n", GetLastError ());
5936 r
= RegCloseKey (hkSubKey
);
5937 if (r
!= ERROR_SUCCESS
)
5938 WARN ("RegCloseKey returned %i\n", r
);
5939 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5940 return ERROR_MORE_DATA
;
5943 TRACE ("pass 2: copying all names and values to buffer\n");
5945 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5946 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5948 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5950 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5951 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5952 NULL
, &dwType
, lpValue
, &cbValueLen
);
5953 if (ret
!= ERROR_SUCCESS
)
5955 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5956 WARN ("HeapFree failed with code %i\n", GetLastError ());
5957 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5958 WARN ("HeapFree failed with code %i\n", GetLastError ());
5959 r
= RegCloseKey (hkSubKey
);
5960 if (r
!= ERROR_SUCCESS
)
5961 WARN ("RegCloseKey returned %i\n", r
);
5962 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5966 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5967 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5968 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5969 pEnumValues
+= cbValueNameLen
;
5971 /* return # of *bytes* (including trailing \0), not # of chars */
5972 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5974 ppev
[dwIndex
].dwType
= dwType
;
5976 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5977 ppev
[dwIndex
].pData
= pEnumValues
;
5978 pEnumValues
+= cbValueLen
;
5980 ppev
[dwIndex
].cbData
= cbValueLen
;
5982 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5983 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5986 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5988 ret
= GetLastError ();
5989 ERR ("HeapFree failed with code %i\n", ret
);
5990 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5991 WARN ("HeapFree failed with code %i\n", GetLastError ());
5992 r
= RegCloseKey (hkSubKey
);
5993 if (r
!= ERROR_SUCCESS
)
5994 WARN ("RegCloseKey returned %i\n", r
);
5998 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6000 ret
= GetLastError ();
6001 ERR ("HeapFree failed with code %i\n", ret
);
6002 r
= RegCloseKey (hkSubKey
);
6003 if (r
!= ERROR_SUCCESS
)
6004 WARN ("RegCloseKey returned %i\n", r
);
6008 ret
= RegCloseKey (hkSubKey
);
6009 if (ret
!= ERROR_SUCCESS
)
6011 ERR ("RegCloseKey returned %i\n", ret
);
6015 return ERROR_SUCCESS
;
6018 /*******************************************************************************
6019 * EnumPrinterDataExA [WINSPOOL.@]
6021 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6022 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6023 * what Windows 2000 SP1 does.
6026 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6027 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6028 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6032 DWORD ret
, dwIndex
, dwBufSize
;
6036 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6038 if (pKeyName
== NULL
|| *pKeyName
== 0)
6039 return ERROR_INVALID_PARAMETER
;
6041 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6044 ret
= GetLastError ();
6045 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6049 hHeap
= GetProcessHeap ();
6052 ERR ("GetProcessHeap failed\n");
6053 return ERROR_OUTOFMEMORY
;
6056 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6057 if (pKeyNameW
== NULL
)
6059 ERR ("Failed to allocate %i bytes from process heap\n",
6060 (LONG
)(len
* sizeof (WCHAR
)));
6061 return ERROR_OUTOFMEMORY
;
6064 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6066 ret
= GetLastError ();
6067 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6068 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6069 WARN ("HeapFree failed with code %i\n", GetLastError ());
6073 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6074 pcbEnumValues
, pnEnumValues
);
6075 if (ret
!= ERROR_SUCCESS
)
6077 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6078 WARN ("HeapFree failed with code %i\n", GetLastError ());
6079 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6083 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6085 ret
= GetLastError ();
6086 ERR ("HeapFree failed with code %i\n", ret
);
6090 if (*pnEnumValues
== 0) /* empty key */
6091 return ERROR_SUCCESS
;
6094 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6096 PPRINTER_ENUM_VALUESW ppev
=
6097 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6099 if (dwBufSize
< ppev
->cbValueName
)
6100 dwBufSize
= ppev
->cbValueName
;
6102 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6103 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6104 dwBufSize
= ppev
->cbData
;
6107 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6109 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6110 if (pBuffer
== NULL
)
6112 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6113 return ERROR_OUTOFMEMORY
;
6116 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6118 PPRINTER_ENUM_VALUESW ppev
=
6119 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6121 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6122 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6126 ret
= GetLastError ();
6127 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6128 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6129 WARN ("HeapFree failed with code %i\n", GetLastError ());
6133 memcpy (ppev
->pValueName
, pBuffer
, len
);
6135 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6137 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6138 ppev
->dwType
!= REG_MULTI_SZ
)
6141 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6142 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6145 ret
= GetLastError ();
6146 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6147 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6148 WARN ("HeapFree failed with code %i\n", GetLastError ());
6152 memcpy (ppev
->pData
, pBuffer
, len
);
6154 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6155 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6158 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6160 ret
= GetLastError ();
6161 ERR ("HeapFree failed with code %i\n", ret
);
6165 return ERROR_SUCCESS
;
6168 /******************************************************************************
6169 * AbortPrinter (WINSPOOL.@)
6171 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6173 FIXME("(%p), stub!\n", hPrinter
);
6177 /******************************************************************************
6178 * AddPortA (WINSPOOL.@)
6183 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6185 LPWSTR nameW
= NULL
;
6186 LPWSTR monitorW
= NULL
;
6190 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6193 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6194 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6195 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6199 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6200 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6201 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6203 res
= AddPortW(nameW
, hWnd
, monitorW
);
6204 HeapFree(GetProcessHeap(), 0, nameW
);
6205 HeapFree(GetProcessHeap(), 0, monitorW
);
6209 /******************************************************************************
6210 * AddPortW (WINSPOOL.@)
6212 * Add a Port for a specific Monitor
6215 * pName [I] Servername or NULL (local Computer)
6216 * hWnd [I] Handle to parent Window for the Dialog-Box
6217 * pMonitorName [I] Name of the Monitor that manage the Port
6224 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6226 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6228 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6230 if (!pMonitorName
) {
6231 SetLastError(RPC_X_NULL_REF_POINTER
);
6235 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
6238 /******************************************************************************
6239 * AddPortExA (WINSPOOL.@)
6244 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6247 PORT_INFO_2A
* pi2A
;
6248 LPWSTR nameW
= NULL
;
6249 LPWSTR monitorW
= NULL
;
6253 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6255 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6256 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6258 if ((level
< 1) || (level
> 2)) {
6259 SetLastError(ERROR_INVALID_LEVEL
);
6264 SetLastError(ERROR_INVALID_PARAMETER
);
6269 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6270 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6271 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6275 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6276 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6277 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6280 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6282 if (pi2A
->pPortName
) {
6283 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6284 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6285 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6289 if (pi2A
->pMonitorName
) {
6290 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6291 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6292 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6295 if (pi2A
->pDescription
) {
6296 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6297 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6298 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6300 pi2W
.fPortType
= pi2A
->fPortType
;
6301 pi2W
.Reserved
= pi2A
->Reserved
;
6304 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6306 HeapFree(GetProcessHeap(), 0, nameW
);
6307 HeapFree(GetProcessHeap(), 0, monitorW
);
6308 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6309 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6310 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6315 /******************************************************************************
6316 * AddPortExW (WINSPOOL.@)
6318 * Add a Port for a specific Monitor, without presenting a user interface
6321 * pName [I] Servername or NULL (local Computer)
6322 * level [I] Structure-Level (1 or 2) for pBuffer
6323 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6324 * pMonitorName [I] Name of the Monitor that manage the Port
6331 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6335 pi2
= (PORT_INFO_2W
*) pBuffer
;
6337 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6338 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6339 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6340 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6342 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6344 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6345 SetLastError(ERROR_INVALID_PARAMETER
);
6349 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6352 /******************************************************************************
6353 * AddPrinterConnectionA (WINSPOOL.@)
6355 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6357 FIXME("%s\n", debugstr_a(pName
));
6361 /******************************************************************************
6362 * AddPrinterConnectionW (WINSPOOL.@)
6364 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6366 FIXME("%s\n", debugstr_w(pName
));
6370 /******************************************************************************
6371 * AddPrinterDriverExW (WINSPOOL.@)
6373 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6376 * pName [I] Servername or NULL (local Computer)
6377 * level [I] Level for the supplied DRIVER_INFO_*W struct
6378 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6379 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6386 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6388 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6390 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6392 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6393 SetLastError(ERROR_INVALID_LEVEL
);
6398 SetLastError(ERROR_INVALID_PARAMETER
);
6402 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6405 /******************************************************************************
6406 * AddPrinterDriverExA (WINSPOOL.@)
6408 * See AddPrinterDriverExW.
6411 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6413 DRIVER_INFO_8A
*diA
;
6415 LPWSTR nameW
= NULL
;
6420 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6422 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6423 ZeroMemory(&diW
, sizeof(diW
));
6425 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6426 SetLastError(ERROR_INVALID_LEVEL
);
6431 SetLastError(ERROR_INVALID_PARAMETER
);
6435 /* convert servername to unicode */
6437 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6438 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6439 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6443 diW
.cVersion
= diA
->cVersion
;
6446 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6447 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6448 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6451 if (diA
->pEnvironment
) {
6452 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6453 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6454 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6457 if (diA
->pDriverPath
) {
6458 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6459 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6460 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6463 if (diA
->pDataFile
) {
6464 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6465 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6466 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6469 if (diA
->pConfigFile
) {
6470 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6471 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6472 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6475 if ((Level
> 2) && diA
->pDependentFiles
) {
6476 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6477 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6478 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6479 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6482 if ((Level
> 2) && diA
->pMonitorName
) {
6483 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6484 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6485 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6488 if ((Level
> 3) && diA
->pDefaultDataType
) {
6489 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6490 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6491 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6494 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6495 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6496 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6497 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6498 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6501 if ((Level
> 5) && diA
->pszMfgName
) {
6502 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6503 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6504 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6507 if ((Level
> 5) && diA
->pszOEMUrl
) {
6508 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6509 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6510 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6513 if ((Level
> 5) && diA
->pszHardwareID
) {
6514 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6515 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6516 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6519 if ((Level
> 5) && diA
->pszProvider
) {
6520 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6521 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6522 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6526 FIXME("level %u is incomplete\n", Level
);
6529 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6530 TRACE("got %u with %u\n", res
, GetLastError());
6531 HeapFree(GetProcessHeap(), 0, nameW
);
6532 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6533 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6534 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6535 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6536 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6537 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6538 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6539 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6540 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6541 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6542 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6543 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6544 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6546 TRACE("=> %u with %u\n", res
, GetLastError());
6550 /******************************************************************************
6551 * ConfigurePortA (WINSPOOL.@)
6553 * See ConfigurePortW.
6556 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6558 LPWSTR nameW
= NULL
;
6559 LPWSTR portW
= NULL
;
6563 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6565 /* convert servername to unicode */
6567 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6568 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6569 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6572 /* convert portname to unicode */
6574 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6575 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6576 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6579 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6580 HeapFree(GetProcessHeap(), 0, nameW
);
6581 HeapFree(GetProcessHeap(), 0, portW
);
6585 /******************************************************************************
6586 * ConfigurePortW (WINSPOOL.@)
6588 * Display the Configuration-Dialog for a specific Port
6591 * pName [I] Servername or NULL (local Computer)
6592 * hWnd [I] Handle to parent Window for the Dialog-Box
6593 * pPortName [I] Name of the Port, that should be configured
6600 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6603 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6605 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6608 SetLastError(RPC_X_NULL_REF_POINTER
);
6612 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
6615 /******************************************************************************
6616 * ConnectToPrinterDlg (WINSPOOL.@)
6618 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6620 FIXME("%p %x\n", hWnd
, Flags
);
6624 /******************************************************************************
6625 * DeletePrinterConnectionA (WINSPOOL.@)
6627 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6629 FIXME("%s\n", debugstr_a(pName
));
6633 /******************************************************************************
6634 * DeletePrinterConnectionW (WINSPOOL.@)
6636 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6638 FIXME("%s\n", debugstr_w(pName
));
6642 /******************************************************************************
6643 * DeletePrinterDriverExW (WINSPOOL.@)
6645 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6646 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6651 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6652 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6654 if(pName
&& pName
[0])
6656 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6657 SetLastError(ERROR_INVALID_PARAMETER
);
6663 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6664 SetLastError(ERROR_INVALID_PARAMETER
);
6668 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
6672 ERR("Can't open drivers key\n");
6676 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6679 RegCloseKey(hkey_drivers
);
6684 /******************************************************************************
6685 * DeletePrinterDriverExA (WINSPOOL.@)
6687 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6688 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6690 UNICODE_STRING NameW
, EnvW
, DriverW
;
6693 asciitounicode(&NameW
, pName
);
6694 asciitounicode(&EnvW
, pEnvironment
);
6695 asciitounicode(&DriverW
, pDriverName
);
6697 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6699 RtlFreeUnicodeString(&DriverW
);
6700 RtlFreeUnicodeString(&EnvW
);
6701 RtlFreeUnicodeString(&NameW
);
6706 /******************************************************************************
6707 * DeletePrinterDataExW (WINSPOOL.@)
6709 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6712 FIXME("%p %s %s\n", hPrinter
,
6713 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6714 return ERROR_INVALID_PARAMETER
;
6717 /******************************************************************************
6718 * DeletePrinterDataExA (WINSPOOL.@)
6720 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6723 FIXME("%p %s %s\n", hPrinter
,
6724 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6725 return ERROR_INVALID_PARAMETER
;
6728 /******************************************************************************
6729 * DeletePrintProcessorA (WINSPOOL.@)
6731 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6733 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6734 debugstr_a(pPrintProcessorName
));
6738 /******************************************************************************
6739 * DeletePrintProcessorW (WINSPOOL.@)
6741 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6743 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6744 debugstr_w(pPrintProcessorName
));
6748 /******************************************************************************
6749 * DeletePrintProvidorA (WINSPOOL.@)
6751 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6753 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6754 debugstr_a(pPrintProviderName
));
6758 /******************************************************************************
6759 * DeletePrintProvidorW (WINSPOOL.@)
6761 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6763 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6764 debugstr_w(pPrintProviderName
));
6768 /******************************************************************************
6769 * EnumFormsA (WINSPOOL.@)
6771 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6772 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6774 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6775 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6779 /******************************************************************************
6780 * EnumFormsW (WINSPOOL.@)
6782 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6783 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6785 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6786 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6790 /*****************************************************************************
6791 * EnumMonitorsA [WINSPOOL.@]
6793 * See EnumMonitorsW.
6796 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6797 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6800 LPBYTE bufferW
= NULL
;
6801 LPWSTR nameW
= NULL
;
6803 DWORD numentries
= 0;
6806 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6807 cbBuf
, pcbNeeded
, pcReturned
);
6809 /* convert servername to unicode */
6811 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6812 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6813 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6815 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6816 needed
= cbBuf
* sizeof(WCHAR
);
6817 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6818 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6820 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6821 if (pcbNeeded
) needed
= *pcbNeeded
;
6822 /* HeapReAlloc return NULL, when bufferW was NULL */
6823 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6824 HeapAlloc(GetProcessHeap(), 0, needed
);
6826 /* Try again with the large Buffer */
6827 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6829 numentries
= pcReturned
? *pcReturned
: 0;
6832 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6833 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6836 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6837 DWORD entrysize
= 0;
6840 LPMONITOR_INFO_2W mi2w
;
6841 LPMONITOR_INFO_2A mi2a
;
6843 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6844 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6846 /* First pass: calculate the size for all Entries */
6847 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6848 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6850 while (index
< numentries
) {
6852 needed
+= entrysize
; /* MONITOR_INFO_?A */
6853 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6855 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6856 NULL
, 0, NULL
, NULL
);
6858 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6859 NULL
, 0, NULL
, NULL
);
6860 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6861 NULL
, 0, NULL
, NULL
);
6863 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6864 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6865 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6868 /* check for errors and quit on failure */
6869 if (cbBuf
< needed
) {
6870 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6874 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6875 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6876 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6877 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6878 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6880 /* Second Pass: Fill the User Buffer (if we have one) */
6881 while ((index
< numentries
) && pMonitors
) {
6883 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6885 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6886 ptr
, cbBuf
, NULL
, NULL
);
6890 mi2a
->pEnvironment
= ptr
;
6891 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6892 ptr
, cbBuf
, NULL
, NULL
);
6896 mi2a
->pDLLName
= ptr
;
6897 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6898 ptr
, cbBuf
, NULL
, NULL
);
6902 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6903 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6904 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6908 if (pcbNeeded
) *pcbNeeded
= needed
;
6909 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6911 HeapFree(GetProcessHeap(), 0, nameW
);
6912 HeapFree(GetProcessHeap(), 0, bufferW
);
6914 TRACE("returning %d with %d (%d byte for %d entries)\n",
6915 (res
), GetLastError(), needed
, numentries
);
6921 /*****************************************************************************
6922 * EnumMonitorsW [WINSPOOL.@]
6924 * Enumerate available Port-Monitors
6927 * pName [I] Servername or NULL (local Computer)
6928 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6929 * pMonitors [O] PTR to Buffer that receives the Result
6930 * cbBuf [I] Size of Buffer at pMonitors
6931 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6932 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6936 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6939 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6940 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6943 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6944 cbBuf
, pcbNeeded
, pcReturned
);
6946 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6948 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
6949 SetLastError(RPC_X_NULL_REF_POINTER
);
6953 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
6956 /******************************************************************************
6957 * SpoolerInit (WINSPOOL.@)
6959 * Initialize the Spooler
6966 * The function fails on windows, when the spooler service is not running
6969 BOOL WINAPI
SpoolerInit(void)
6972 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6976 /******************************************************************************
6977 * XcvDataW (WINSPOOL.@)
6979 * Execute commands in the Printmonitor DLL
6982 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6983 * pszDataName [i] Name of the command to execute
6984 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6985 * cbInputData [i] Size in Bytes of Buffer at pInputData
6986 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6987 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6988 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6989 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6996 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6997 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6999 * Minimal List of commands, that a Printmonitor DLL should support:
7001 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7002 *| "AddPort" : Add a Port
7003 *| "DeletePort": Delete a Port
7005 * Many Printmonitors support additional commands. Examples for localspl.dll:
7006 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7007 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7010 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7011 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7012 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7014 opened_printer_t
*printer
;
7016 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7017 pInputData
, cbInputData
, pOutputData
,
7018 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7020 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7022 printer
= get_opened_printer(hXcv
);
7023 if (!printer
|| (!printer
->backend_printer
)) {
7024 SetLastError(ERROR_INVALID_HANDLE
);
7028 if (!pcbOutputNeeded
) {
7029 SetLastError(ERROR_INVALID_PARAMETER
);
7033 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7034 SetLastError(RPC_X_NULL_REF_POINTER
);
7038 *pcbOutputNeeded
= 0;
7040 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
7041 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7045 /*****************************************************************************
7046 * EnumPrinterDataA [WINSPOOL.@]
7049 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7050 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7051 DWORD cbData
, LPDWORD pcbData
)
7053 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7054 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7055 return ERROR_NO_MORE_ITEMS
;
7058 /*****************************************************************************
7059 * EnumPrinterDataW [WINSPOOL.@]
7062 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7063 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7064 DWORD cbData
, LPDWORD pcbData
)
7066 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7067 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7068 return ERROR_NO_MORE_ITEMS
;
7071 /*****************************************************************************
7072 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7075 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7076 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7077 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7079 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7080 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7081 pcbNeeded
, pcReturned
);
7085 /*****************************************************************************
7086 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7089 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7090 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7091 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7093 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7094 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7095 pcbNeeded
, pcReturned
);
7099 /*****************************************************************************
7100 * EnumPrintProcessorsA [WINSPOOL.@]
7102 * See EnumPrintProcessorsW.
7105 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7106 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7109 LPBYTE bufferW
= NULL
;
7110 LPWSTR nameW
= NULL
;
7113 DWORD numentries
= 0;
7116 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
7117 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7119 /* convert names to unicode */
7121 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7122 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7123 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7126 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
7127 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7128 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
7131 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7132 needed
= cbBuf
* sizeof(WCHAR
);
7133 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7134 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7136 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7137 if (pcbNeeded
) needed
= *pcbNeeded
;
7138 /* HeapReAlloc return NULL, when bufferW was NULL */
7139 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7140 HeapAlloc(GetProcessHeap(), 0, needed
);
7142 /* Try again with the large Buffer */
7143 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7145 numentries
= pcReturned
? *pcReturned
: 0;
7149 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7152 PPRINTPROCESSOR_INFO_1W ppiw
;
7153 PPRINTPROCESSOR_INFO_1A ppia
;
7155 /* First pass: calculate the size for all Entries */
7156 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7157 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7159 while (index
< numentries
) {
7161 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
7162 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
7164 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7165 NULL
, 0, NULL
, NULL
);
7167 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7168 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7171 /* check for errors and quit on failure */
7172 if (cbBuf
< needed
) {
7173 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7178 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
7179 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
7180 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7181 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
7182 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
7184 /* Second Pass: Fill the User Buffer (if we have one) */
7185 while ((index
< numentries
) && pPPInfo
) {
7187 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
7189 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
7190 ptr
, cbBuf
, NULL
, NULL
);
7194 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
7195 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
7200 if (pcbNeeded
) *pcbNeeded
= needed
;
7201 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7203 HeapFree(GetProcessHeap(), 0, nameW
);
7204 HeapFree(GetProcessHeap(), 0, envW
);
7205 HeapFree(GetProcessHeap(), 0, bufferW
);
7207 TRACE("returning %d with %d (%d byte for %d entries)\n",
7208 (res
), GetLastError(), needed
, numentries
);
7213 /*****************************************************************************
7214 * EnumPrintProcessorsW [WINSPOOL.@]
7216 * Enumerate available Print Processors
7219 * pName [I] Servername or NULL (local Computer)
7220 * pEnvironment [I] Printing-Environment or NULL (Default)
7221 * Level [I] Structure-Level (Only 1 is allowed)
7222 * pPPInfo [O] PTR to Buffer that receives the Result
7223 * cbBuf [I] Size of Buffer at pPPInfo
7224 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7225 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7229 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7232 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7233 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7236 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
7237 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
7239 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7241 if (!pcbNeeded
|| !pcReturned
) {
7242 SetLastError(RPC_X_NULL_REF_POINTER
);
7246 if (!pPPInfo
&& (cbBuf
> 0)) {
7247 SetLastError(ERROR_INVALID_USER_BUFFER
);
7251 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
7252 cbBuf
, pcbNeeded
, pcReturned
);
7255 /*****************************************************************************
7256 * ExtDeviceMode [WINSPOOL.@]
7259 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7260 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7263 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7264 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7265 debugstr_a(pProfile
), fMode
);
7269 /*****************************************************************************
7270 * FindClosePrinterChangeNotification [WINSPOOL.@]
7273 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7275 FIXME("Stub: %p\n", hChange
);
7279 /*****************************************************************************
7280 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7283 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7284 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7286 FIXME("Stub: %p %x %x %p\n",
7287 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7288 return INVALID_HANDLE_VALUE
;
7291 /*****************************************************************************
7292 * FindNextPrinterChangeNotification [WINSPOOL.@]
7295 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7296 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7298 FIXME("Stub: %p %p %p %p\n",
7299 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7303 /*****************************************************************************
7304 * FreePrinterNotifyInfo [WINSPOOL.@]
7307 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7309 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7313 /*****************************************************************************
7316 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7317 * ansi depending on the unicode parameter.
7319 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7329 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7332 memcpy(ptr
, str
, *size
);
7339 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7342 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7349 /*****************************************************************************
7352 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7353 LPDWORD pcbNeeded
, BOOL unicode
)
7355 DWORD size
, left
= cbBuf
;
7356 BOOL space
= (cbBuf
> 0);
7363 ji1
->JobId
= job
->job_id
;
7366 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7367 if(space
&& size
<= left
)
7369 ji1
->pDocument
= (LPWSTR
)ptr
;
7377 if (job
->printer_name
)
7379 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7380 if(space
&& size
<= left
)
7382 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7394 /*****************************************************************************
7397 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7398 LPDWORD pcbNeeded
, BOOL unicode
)
7400 DWORD size
, left
= cbBuf
;
7402 BOOL space
= (cbBuf
> 0);
7404 LPDEVMODEA dmA
= NULL
;
7411 ji2
->JobId
= job
->job_id
;
7414 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7415 if(space
&& size
<= left
)
7417 ji2
->pDocument
= (LPWSTR
)ptr
;
7425 if (job
->printer_name
)
7427 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7428 if(space
&& size
<= left
)
7430 ji2
->pPrinterName
= (LPWSTR
)ptr
;
7443 dmA
= DEVMODEdupWtoA(job
->devmode
);
7444 devmode
= (LPDEVMODEW
) dmA
;
7445 if (dmA
) size
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
7449 devmode
= job
->devmode
;
7450 size
= devmode
->dmSize
+ devmode
->dmDriverExtra
;
7454 FIXME("Can't convert DEVMODE W to A\n");
7457 /* align DEVMODE to a DWORD boundary */
7458 shift
= (4 - (*pcbNeeded
& 3)) & 3;
7464 memcpy(ptr
, devmode
, size
-shift
);
7465 ji2
->pDevMode
= (LPDEVMODEW
)ptr
;
7466 if (!unicode
) HeapFree(GetProcessHeap(), 0, dmA
);
7479 /*****************************************************************************
7482 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7483 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7486 DWORD needed
= 0, size
;
7490 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7492 EnterCriticalSection(&printer_handles_cs
);
7493 job
= get_job(hPrinter
, JobId
);
7500 size
= sizeof(JOB_INFO_1W
);
7505 memset(pJob
, 0, size
);
7509 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7514 size
= sizeof(JOB_INFO_2W
);
7519 memset(pJob
, 0, size
);
7523 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7528 size
= sizeof(JOB_INFO_3
);
7532 memset(pJob
, 0, size
);
7541 SetLastError(ERROR_INVALID_LEVEL
);
7545 *pcbNeeded
= needed
;
7547 LeaveCriticalSection(&printer_handles_cs
);
7551 /*****************************************************************************
7552 * GetJobA [WINSPOOL.@]
7555 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7556 DWORD cbBuf
, LPDWORD pcbNeeded
)
7558 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7561 /*****************************************************************************
7562 * GetJobW [WINSPOOL.@]
7565 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7566 DWORD cbBuf
, LPDWORD pcbNeeded
)
7568 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7571 /*****************************************************************************
7574 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7577 char *unixname
, *cmdA
;
7579 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7585 if(!(unixname
= wine_get_unix_file_name(filename
)))
7588 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7589 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7590 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7592 TRACE("printing with: %s\n", cmdA
);
7594 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7599 ERR("pipe() failed!\n");
7603 if ((pid
= fork()) == 0)
7609 /* reset signals that we previously set to SIG_IGN */
7610 signal(SIGPIPE
, SIG_DFL
);
7612 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
7617 ERR("fork() failed!\n");
7621 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7622 write(fds
[1], buf
, no_read
);
7629 wret
= waitpid(pid
, &status
, 0);
7630 } while (wret
< 0 && errno
== EINTR
);
7633 ERR("waitpid() failed!\n");
7636 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
7638 ERR("child process failed! %d\n", status
);
7645 if(file_fd
!= -1) close(file_fd
);
7646 if(fds
[0] != -1) close(fds
[0]);
7647 if(fds
[1] != -1) close(fds
[1]);
7649 HeapFree(GetProcessHeap(), 0, cmdA
);
7650 HeapFree(GetProcessHeap(), 0, unixname
);
7657 /*****************************************************************************
7660 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7663 const WCHAR fmtW
[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7666 cmd
= HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name
) * sizeof(WCHAR
) + sizeof(fmtW
));
7667 sprintfW(cmd
, fmtW
, printer_name
);
7669 r
= schedule_pipe(cmd
, filename
);
7671 HeapFree(GetProcessHeap(), 0, cmd
);
7675 #ifdef SONAME_LIBCUPS
7676 /*****************************************************************************
7677 * get_cups_jobs_ticket_options
7679 * Explicitly set CUPS options based on any %cupsJobTicket lines.
7680 * The CUPS scheduler only looks for these in Print-File requests, and since
7681 * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
7684 static int get_cups_job_ticket_options( const char *file
, int num_options
, cups_option_t
**options
)
7686 FILE *fp
= fopen( file
, "r" );
7687 char buf
[257]; /* DSC max of 256 + '\0' */
7688 const char *ps_adobe
= "%!PS-Adobe-";
7689 const char *cups_job
= "%cupsJobTicket:";
7691 if (!fp
) return num_options
;
7692 if (!fgets( buf
, sizeof(buf
), fp
)) goto end
;
7693 if (strncmp( buf
, ps_adobe
, strlen( ps_adobe
) )) goto end
;
7694 while (fgets( buf
, sizeof(buf
), fp
))
7696 if (strncmp( buf
, cups_job
, strlen( cups_job
) )) break;
7697 num_options
= pcupsParseOptions( buf
+ strlen( cups_job
), num_options
, options
);
7706 /*****************************************************************************
7709 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7711 #ifdef SONAME_LIBCUPS
7714 char *unixname
, *queue
, *unix_doc_title
;
7717 int num_options
= 0, i
;
7718 cups_option_t
*options
= NULL
;
7720 if(!(unixname
= wine_get_unix_file_name(filename
)))
7723 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7724 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7725 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7727 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7728 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
7729 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
7731 num_options
= get_cups_job_ticket_options( unixname
, num_options
, &options
);
7733 TRACE( "printing via cups with options:\n" );
7734 for (i
= 0; i
< num_options
; i
++)
7735 TRACE( "\t%d: %s = %s\n", i
, options
[i
].name
, options
[i
].value
);
7737 ret
= pcupsPrintFile( queue
, unixname
, unix_doc_title
, num_options
, options
);
7739 pcupsFreeOptions( num_options
, options
);
7741 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
7742 HeapFree(GetProcessHeap(), 0, queue
);
7743 HeapFree(GetProcessHeap(), 0, unixname
);
7749 return schedule_lpr(printer_name
, filename
);
7753 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7760 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7764 if(HIWORD(wparam
) == BN_CLICKED
)
7766 if(LOWORD(wparam
) == IDOK
)
7769 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7772 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7773 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7775 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7777 WCHAR caption
[200], message
[200];
7780 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7781 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7782 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7783 if(mb_ret
== IDCANCEL
)
7785 HeapFree(GetProcessHeap(), 0, filename
);
7789 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7790 if(hf
== INVALID_HANDLE_VALUE
)
7792 WCHAR caption
[200], message
[200];
7794 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7795 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7796 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7797 HeapFree(GetProcessHeap(), 0, filename
);
7801 DeleteFileW(filename
);
7802 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7804 EndDialog(hwnd
, IDOK
);
7807 if(LOWORD(wparam
) == IDCANCEL
)
7809 EndDialog(hwnd
, IDCANCEL
);
7818 /*****************************************************************************
7821 static BOOL
get_filename(LPWSTR
*filename
)
7823 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7824 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7827 /*****************************************************************************
7830 static BOOL
schedule_file(LPCWSTR filename
)
7832 LPWSTR output
= NULL
;
7834 if(get_filename(&output
))
7837 TRACE("copy to %s\n", debugstr_w(output
));
7838 r
= CopyFileW(filename
, output
, FALSE
);
7839 HeapFree(GetProcessHeap(), 0, output
);
7845 /*****************************************************************************
7848 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7850 int in_fd
, out_fd
, no_read
;
7853 char *unixname
, *outputA
;
7856 if(!(unixname
= wine_get_unix_file_name(filename
)))
7859 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7860 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7861 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7863 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7864 in_fd
= open(unixname
, O_RDONLY
);
7865 if(out_fd
== -1 || in_fd
== -1)
7868 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7869 write(out_fd
, buf
, no_read
);
7873 if(in_fd
!= -1) close(in_fd
);
7874 if(out_fd
!= -1) close(out_fd
);
7875 HeapFree(GetProcessHeap(), 0, outputA
);
7876 HeapFree(GetProcessHeap(), 0, unixname
);
7880 /*****************************************************************************
7881 * ScheduleJob [WINSPOOL.@]
7884 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7886 opened_printer_t
*printer
;
7888 struct list
*cursor
, *cursor2
;
7890 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7891 EnterCriticalSection(&printer_handles_cs
);
7892 printer
= get_opened_printer(hPrinter
);
7896 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7898 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7901 if(job
->job_id
!= dwJobID
) continue;
7903 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7904 if(hf
!= INVALID_HANDLE_VALUE
)
7906 PRINTER_INFO_5W
*pi5
= NULL
;
7907 LPWSTR portname
= job
->portname
;
7911 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7912 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7916 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7917 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7918 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7919 portname
= pi5
->pPortName
;
7921 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7922 debugstr_w(portname
));
7926 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7927 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7929 DWORD type
, count
= sizeof(output
);
7930 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
7933 if(output
[0] == '|')
7935 ret
= schedule_pipe(output
+ 1, job
->filename
);
7939 ret
= schedule_unixfile(output
, job
->filename
);
7941 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
7943 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
7945 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
7947 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7949 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
7951 ret
= schedule_file(job
->filename
);
7955 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
7957 HeapFree(GetProcessHeap(), 0, pi5
);
7959 DeleteFileW(job
->filename
);
7961 list_remove(cursor
);
7962 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7963 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
7964 HeapFree(GetProcessHeap(), 0, job
->portname
);
7965 HeapFree(GetProcessHeap(), 0, job
->filename
);
7966 HeapFree(GetProcessHeap(), 0, job
->devmode
);
7967 HeapFree(GetProcessHeap(), 0, job
);
7971 LeaveCriticalSection(&printer_handles_cs
);
7975 /*****************************************************************************
7976 * StartDocDlgA [WINSPOOL.@]
7978 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7980 UNICODE_STRING usBuffer
;
7983 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7986 docW
.cbSize
= sizeof(docW
);
7987 if (doc
->lpszDocName
)
7989 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7990 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7992 if (doc
->lpszOutput
)
7994 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7995 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7997 if (doc
->lpszDatatype
)
7999 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
8000 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
8002 docW
.fwType
= doc
->fwType
;
8004 retW
= StartDocDlgW(hPrinter
, &docW
);
8008 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
8009 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
8010 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
8011 HeapFree(GetProcessHeap(), 0, retW
);
8014 HeapFree(GetProcessHeap(), 0, datatypeW
);
8015 HeapFree(GetProcessHeap(), 0, outputW
);
8016 HeapFree(GetProcessHeap(), 0, docnameW
);
8021 /*****************************************************************************
8022 * StartDocDlgW [WINSPOOL.@]
8024 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8025 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8026 * port is "FILE:". Also returns the full path if passed a relative path.
8028 * The caller should free the returned string from the process heap.
8030 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
8035 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
8037 PRINTER_INFO_5W
*pi5
;
8038 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
8039 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
8041 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
8042 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
8043 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
8045 HeapFree(GetProcessHeap(), 0, pi5
);
8048 HeapFree(GetProcessHeap(), 0, pi5
);
8051 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
8055 if (get_filename(&name
))
8057 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
8059 HeapFree(GetProcessHeap(), 0, name
);
8062 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8063 GetFullPathNameW(name
, len
, ret
, NULL
);
8064 HeapFree(GetProcessHeap(), 0, name
);
8069 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8072 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8073 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8075 attr
= GetFileAttributesW(ret
);
8076 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8078 HeapFree(GetProcessHeap(), 0, ret
);