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-2008 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
60 #include "ddk/winsplp.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
65 /* ############################### */
67 static CRITICAL_SECTION monitor_handles_cs
;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug
=
70 0, 0, &monitor_handles_cs
,
71 { &monitor_handles_cs_debug
.ProcessLocksList
, &monitor_handles_cs_debug
.ProcessLocksList
},
72 0, 0, { (DWORD_PTR
)(__FILE__
": monitor_handles_cs") }
74 static CRITICAL_SECTION monitor_handles_cs
= { &monitor_handles_cs_debug
, -1, 0, 0, 0, 0 };
77 static CRITICAL_SECTION printer_handles_cs
;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
80 0, 0, &printer_handles_cs
,
81 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
82 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
84 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
86 /* ############################### */
122 WCHAR
*document_title
;
130 LPCWSTR versionregpath
;
131 LPCWSTR versionsubdir
;
134 /* ############################### */
136 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
137 static monitor_t
* pm_localport
;
139 static opened_printer_t
**printer_handles
;
140 static UINT nb_printer_handles
;
141 static LONG next_job_id
= 1;
143 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
144 WORD fwCapability
, LPSTR lpszOutput
,
146 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
147 LPSTR lpszDevice
, LPSTR lpszPort
,
148 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
151 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
152 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
153 'c','o','n','t','r','o','l','\\',
154 'P','r','i','n','t','\\',
155 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
156 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
158 static const WCHAR MonitorsW
[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'C','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'M','o','n','i','t','o','r','s','\\',0};
164 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
165 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
166 'C','o','n','t','r','o','l','\\',
167 'P','r','i','n','t','\\',
168 'P','r','i','n','t','e','r','s',0};
170 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
172 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s',' ','N','T','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'W','i','n','d','o','w','s',0};
178 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'D','e','v','i','c','e','s',0};
184 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
185 'M','i','c','r','o','s','o','f','t','\\',
186 'W','i','n','d','o','w','s',' ','N','T','\\',
187 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
188 'P','o','r','t','s',0};
190 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
191 'M','i','c','r','o','s','o','f','t','\\',
192 'W','i','n','d','o','w','s',' ','N','T','\\',
193 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
194 'P','r','i','n','t','e','r','P','o','r','t','s',0};
196 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
197 static const WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
198 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
199 static const WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
200 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
201 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
202 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
203 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
204 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
205 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
206 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
208 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
209 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
211 static const WCHAR backslashW
[] = {'\\',0};
212 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
213 'i','o','n',' ','F','i','l','e',0};
214 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
215 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
216 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
217 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
218 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
219 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
220 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
221 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
222 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
223 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
224 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
225 static const WCHAR MonitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
226 static const WCHAR NameW
[] = {'N','a','m','e',0};
227 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
228 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
229 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
230 static const WCHAR PortW
[] = {'P','o','r','t',0};
231 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
232 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
233 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
234 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
235 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
236 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
237 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
238 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
239 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
240 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
241 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
242 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
243 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
244 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
245 static const WCHAR emptyStringW
[] = {0};
246 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
247 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
249 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
251 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
252 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
253 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
255 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
256 'D','o','c','u','m','e','n','t',0};
258 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
259 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
260 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
261 0, sizeof(DRIVER_INFO_8W
)};
264 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
265 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
266 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
267 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
268 sizeof(PRINTER_INFO_9W
)};
270 /******************************************************************
271 * validate the user-supplied printing-environment [internal]
274 * env [I] PTR to Environment-String or NULL
278 * Success: PTR to printenv_t
281 * An empty string is handled the same way as NULL.
282 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
286 static const printenv_t
* validate_envW(LPCWSTR env
)
288 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
,
289 3, Version3_RegPathW
, Version3_SubdirW
};
290 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
,
291 3, Version3_RegPathW
, Version3_SubdirW
};
292 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
,
293 0, Version0_RegPathW
, Version0_SubdirW
};
295 static const printenv_t
* const all_printenv
[]={&env_x86
, &env_x64
, &env_win40
};
297 const printenv_t
*result
= NULL
;
300 TRACE("testing %s\n", debugstr_w(env
));
303 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
305 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
307 result
= all_printenv
[i
];
312 if (result
== NULL
) {
313 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
314 SetLastError(ERROR_INVALID_ENVIRONMENT
);
316 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
320 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
322 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
328 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
329 if passed a NULL string. This returns NULLs to the result.
331 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
335 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
336 return usBufferPtr
->Buffer
;
338 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
342 static LPWSTR
strdupW(LPCWSTR p
)
348 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
349 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
354 static LPSTR
strdupWtoA( LPCWSTR str
)
359 if (!str
) return NULL
;
360 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
361 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
362 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
366 /******************************************************************
367 * Return the number of bytes for an multi_sz string.
368 * The result includes all \0s
369 * (specifically the extra \0, that is needed as multi_sz terminator).
372 static int multi_sz_lenW(const WCHAR
*str
)
374 const WCHAR
*ptr
= str
;
378 ptr
+= lstrlenW(ptr
) + 1;
381 return (ptr
- str
+ 1) * sizeof(WCHAR
);
384 /* ################################ */
386 static int multi_sz_lenA(const char *str
)
388 const char *ptr
= str
;
392 ptr
+= lstrlenA(ptr
) + 1;
395 return ptr
- str
+ 1;
399 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
402 /* If forcing, or no profile string entry for device yet, set the entry
404 * The always change entry if not WINEPS yet is discussable.
407 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
409 !strstr(qbuf
,"WINEPS.DRV")
411 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
414 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
415 WriteProfileStringA("windows","device",buf
);
416 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
417 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
420 HeapFree(GetProcessHeap(),0,buf
);
424 static BOOL
add_printer_driver(const char *name
)
428 static char driver_9x
[] = "wineps16.drv",
429 driver_nt
[] = "wineps.drv",
430 env_9x
[] = "Windows 4.0",
431 env_nt
[] = "Windows NT x86",
432 data_file
[] = "generic.ppd",
433 default_data_type
[] = "RAW";
435 ZeroMemory(&di3a
, sizeof(DRIVER_INFO_3A
));
437 di3a
.pName
= (char *)name
;
438 di3a
.pEnvironment
= env_nt
;
439 di3a
.pDriverPath
= driver_nt
;
440 di3a
.pDataFile
= data_file
;
441 di3a
.pConfigFile
= driver_nt
;
442 di3a
.pDefaultDataType
= default_data_type
;
444 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
445 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
448 di3a
.pEnvironment
= env_9x
;
449 di3a
.pDriverPath
= driver_9x
;
450 di3a
.pConfigFile
= driver_9x
;
451 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
452 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
457 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a
.pDriverPath
),
458 debugstr_a(di3a
.pEnvironment
), GetLastError());
462 #ifdef SONAME_LIBCUPS
463 static typeof(cupsGetDests
) *pcupsGetDests
;
464 static typeof(cupsGetPPD
) *pcupsGetPPD
;
465 static typeof(cupsPrintFile
) *pcupsPrintFile
;
466 static void *cupshandle
;
468 static BOOL
CUPS_LoadPrinters(void)
471 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
473 PRINTER_INFO_2A pinfo2a
;
475 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
478 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
480 TRACE("%s\n", loaderror
);
483 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
486 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
487 if (!p##x) return FALSE;
490 DYNCUPS(cupsGetDests
);
491 DYNCUPS(cupsPrintFile
);
494 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
496 ERR("Can't create Printers key\n");
500 nrofdests
= pcupsGetDests(&dests
);
501 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
502 for (i
=0;i
<nrofdests
;i
++) {
503 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
504 port
= HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests
[i
].name
)+1);
505 sprintf(port
,"LPR:%s", dests
[i
].name
);
506 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
507 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port
));
508 sprintf(devline
, "WINEPS.DRV,%s", port
);
509 WriteProfileStringA("devices", dests
[i
].name
, devline
);
510 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
511 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
515 lstrcatA(devline
, ",15,45");
516 WriteProfileStringA("PrinterPorts", dests
[i
].name
, devline
);
517 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
518 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
522 HeapFree(GetProcessHeap(), 0, devline
);
524 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
525 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
526 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
528 TRACE("Printer already exists\n");
529 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
530 RegCloseKey(hkeyPrinter
);
532 static CHAR data_type
[] = "RAW",
533 print_proc
[] = "WinPrint",
534 comment
[] = "WINEPS Printer using CUPS",
535 location
[] = "<physical location of printer>",
536 params
[] = "<parameters?>",
537 share_name
[] = "<share name?>",
538 sep_file
[] = "<sep file?>";
540 add_printer_driver(dests
[i
].name
);
542 memset(&pinfo2a
,0,sizeof(pinfo2a
));
543 pinfo2a
.pPrinterName
= dests
[i
].name
;
544 pinfo2a
.pDatatype
= data_type
;
545 pinfo2a
.pPrintProcessor
= print_proc
;
546 pinfo2a
.pDriverName
= dests
[i
].name
;
547 pinfo2a
.pComment
= comment
;
548 pinfo2a
.pLocation
= location
;
549 pinfo2a
.pPortName
= port
;
550 pinfo2a
.pParameters
= params
;
551 pinfo2a
.pShareName
= share_name
;
552 pinfo2a
.pSepFile
= sep_file
;
554 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
555 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
556 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
559 HeapFree(GetProcessHeap(),0,port
);
562 if (dests
[i
].is_default
) {
563 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
567 if (hadprinter
& !haddefault
)
568 WINSPOOL_SetDefaultPrinter(dests
[0].name
, dests
[0].name
, TRUE
);
569 RegCloseKey(hkeyPrinters
);
575 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
576 PRINTER_INFO_2A pinfo2a
;
577 char *e
,*s
,*name
,*prettyname
,*devname
;
578 BOOL ret
= FALSE
, set_default
= FALSE
;
579 char *port
= NULL
, *devline
,*env_default
;
580 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
582 while (isspace(*pent
)) pent
++;
583 s
= strchr(pent
,':');
585 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
593 TRACE("name=%s entry=%s\n",name
, pent
);
595 if(ispunct(*name
)) { /* a tc entry, not a real printer */
596 TRACE("skipping tc entry\n");
600 if(strstr(pent
,":server")) { /* server only version so skip */
601 TRACE("skipping server entry\n");
605 /* Determine whether this is a postscript printer. */
608 env_default
= getenv("PRINTER");
610 /* Get longest name, usually the one at the right for later display. */
611 while((s
=strchr(prettyname
,'|'))) {
614 while(isspace(*--e
)) *e
= '\0';
615 TRACE("\t%s\n", debugstr_a(prettyname
));
616 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
617 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
620 e
= prettyname
+ strlen(prettyname
);
621 while(isspace(*--e
)) *e
= '\0';
622 TRACE("\t%s\n", debugstr_a(prettyname
));
623 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
625 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
626 * if it is too long, we use it as comment below. */
627 devname
= prettyname
;
628 if (strlen(devname
)>=CCHDEVICENAME
-1)
630 if (strlen(devname
)>=CCHDEVICENAME
-1) {
635 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
636 sprintf(port
,"LPR:%s",name
);
638 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
639 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port
));
640 sprintf(devline
, "WINEPS.DRV,%s", port
);
641 WriteProfileStringA("devices", devname
, devline
);
642 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
643 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
647 lstrcatA(devline
, ",15,45");
648 WriteProfileStringA("PrinterPorts", devname
, devline
);
649 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
650 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
654 HeapFree(GetProcessHeap(),0,devline
);
656 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
658 ERR("Can't create Printers key\n");
662 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
663 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
665 TRACE("Printer already exists\n");
666 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
667 RegCloseKey(hkeyPrinter
);
669 static CHAR data_type
[] = "RAW",
670 print_proc
[] = "WinPrint",
671 comment
[] = "WINEPS Printer using LPR",
672 params
[] = "<parameters?>",
673 share_name
[] = "<share name?>",
674 sep_file
[] = "<sep file?>";
676 add_printer_driver(devname
);
678 memset(&pinfo2a
,0,sizeof(pinfo2a
));
679 pinfo2a
.pPrinterName
= devname
;
680 pinfo2a
.pDatatype
= data_type
;
681 pinfo2a
.pPrintProcessor
= print_proc
;
682 pinfo2a
.pDriverName
= devname
;
683 pinfo2a
.pComment
= comment
;
684 pinfo2a
.pLocation
= prettyname
;
685 pinfo2a
.pPortName
= port
;
686 pinfo2a
.pParameters
= params
;
687 pinfo2a
.pShareName
= share_name
;
688 pinfo2a
.pSepFile
= sep_file
;
690 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
691 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
692 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
695 RegCloseKey(hkeyPrinters
);
697 if (isfirst
|| set_default
)
698 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
701 HeapFree(GetProcessHeap(), 0, port
);
702 HeapFree(GetProcessHeap(), 0, name
);
707 PRINTCAP_LoadPrinters(void) {
708 BOOL hadprinter
= FALSE
;
712 BOOL had_bash
= FALSE
;
714 f
= fopen("/etc/printcap","r");
718 while(fgets(buf
,sizeof(buf
),f
)) {
721 end
=strchr(buf
,'\n');
725 while(isspace(*start
)) start
++;
726 if(*start
== '#' || *start
== '\0')
729 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
730 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
731 HeapFree(GetProcessHeap(),0,pent
);
735 if (end
&& *--end
== '\\') {
742 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
745 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
751 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
752 HeapFree(GetProcessHeap(),0,pent
);
758 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
761 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
762 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
764 return ERROR_FILE_NOT_FOUND
;
767 /******************************************************************
768 * monitor_unload [internal]
770 * release a printmonitor and unload it from memory, when needed
773 static void monitor_unload(monitor_t
* pm
)
775 if (pm
== NULL
) return;
776 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
778 EnterCriticalSection(&monitor_handles_cs
);
780 if (pm
->refcount
) pm
->refcount
--;
782 if (pm
->refcount
== 0) {
783 list_remove(&pm
->entry
);
784 FreeLibrary(pm
->hdll
);
785 HeapFree(GetProcessHeap(), 0, pm
->name
);
786 HeapFree(GetProcessHeap(), 0, pm
->dllname
);
787 HeapFree(GetProcessHeap(), 0, pm
);
789 LeaveCriticalSection(&monitor_handles_cs
);
792 /******************************************************************
793 * monitor_unloadall [internal]
795 * release all printmonitors and unload them from memory, when needed
798 static void monitor_unloadall(void)
803 EnterCriticalSection(&monitor_handles_cs
);
804 /* iterate through the list, with safety against removal */
805 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
809 LeaveCriticalSection(&monitor_handles_cs
);
812 /******************************************************************
813 * monitor_load [internal]
815 * load a printmonitor, get the dllname from the registry, when needed
816 * initialize the monitor and dump found function-pointers
818 * On failure, SetLastError() is called and NULL is returned
821 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
823 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
824 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
825 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
826 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
827 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
829 monitor_t
* pm
= NULL
;
831 LPWSTR regroot
= NULL
;
832 LPWSTR driver
= dllname
;
834 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
835 /* Is the Monitor already loaded? */
836 EnterCriticalSection(&monitor_handles_cs
);
839 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
841 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
849 pm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(monitor_t
));
850 if (pm
== NULL
) goto cleanup
;
851 list_add_tail(&monitor_handles
, &pm
->entry
);
855 if (pm
->name
== NULL
) {
856 /* Load the monitor */
857 LPMONITOREX pmonitorEx
;
861 len
= lstrlenW(MonitorsW
) + lstrlenW(name
) + 2;
862 regroot
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
866 lstrcpyW(regroot
, MonitorsW
);
867 lstrcatW(regroot
, name
);
868 /* Get the Driver from the Registry */
869 if (driver
== NULL
) {
872 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
873 if (RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, NULL
,
874 &namesize
) == ERROR_SUCCESS
) {
875 driver
= HeapAlloc(GetProcessHeap(), 0, namesize
);
876 RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
883 pm
->name
= strdupW(name
);
884 pm
->dllname
= strdupW(driver
);
886 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
888 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
893 pm
->hdll
= LoadLibraryW(driver
);
894 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
896 if (pm
->hdll
== NULL
) {
898 SetLastError(ERROR_MOD_NOT_FOUND
);
903 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
904 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
905 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
906 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
907 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
910 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
911 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
912 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
913 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
914 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
916 if (pInitializePrintMonitorUI
!= NULL
) {
917 pm
->monitorUI
= pInitializePrintMonitorUI();
918 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
920 TRACE( "0x%08x: dwMonitorSize (%d)\n",
921 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
926 if (pInitializePrintMonitor
&& regroot
) {
927 pmonitorEx
= pInitializePrintMonitor(regroot
);
928 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
929 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
932 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
933 pm
->monitor
= &(pmonitorEx
->Monitor
);
938 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
942 if (!pm
->monitor
&& regroot
) {
943 if (pInitializePrintMonitor2
!= NULL
) {
944 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
946 if (pInitializeMonitorEx
!= NULL
) {
947 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
949 if (pInitializeMonitor
!= NULL
) {
950 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
953 if (!pm
->monitor
&& !pm
->monitorUI
) {
955 SetLastError(ERROR_PROC_NOT_FOUND
);
960 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, LocalPortW
) == 0)) {
964 LeaveCriticalSection(&monitor_handles_cs
);
965 if (driver
!= dllname
) HeapFree(GetProcessHeap(), 0, driver
);
966 HeapFree(GetProcessHeap(), 0, regroot
);
967 TRACE("=> %p\n", pm
);
971 /******************************************************************
972 * monitor_loadall [internal]
974 * Load all registered monitors
977 static DWORD
monitor_loadall(void)
980 DWORD registered
= 0;
983 WCHAR buffer
[MAX_PATH
];
986 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
987 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
988 NULL
, NULL
, NULL
, NULL
, NULL
);
990 TRACE("%d monitors registered\n", registered
);
992 EnterCriticalSection(&monitor_handles_cs
);
993 while (id
< registered
) {
995 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
996 pm
= monitor_load(buffer
, NULL
);
1000 LeaveCriticalSection(&monitor_handles_cs
);
1001 RegCloseKey(hmonitors
);
1003 TRACE("%d monitors loaded\n", loaded
);
1007 /******************************************************************
1008 * monitor_loadui [internal]
1010 * load the userinterface-dll for a given portmonitor
1012 * On failure, NULL is returned
1015 static monitor_t
* monitor_loadui(monitor_t
* pm
)
1017 monitor_t
* pui
= NULL
;
1018 LPWSTR buffer
[MAX_PATH
];
1023 if (pm
== NULL
) return NULL
;
1024 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
1026 /* Try the Portmonitor first; works for many monitors */
1027 if (pm
->monitorUI
) {
1028 EnterCriticalSection(&monitor_handles_cs
);
1030 LeaveCriticalSection(&monitor_handles_cs
);
1034 /* query the userinterface-dllname from the Portmonitor */
1035 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
1036 /* building (",XcvMonitor %s",pm->name) not needed yet */
1037 res
= pm
->monitor
->pfnXcvOpenPort(emptyStringW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
1038 TRACE("got %u with %p\n", res
, hXcv
);
1040 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, MonitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
1041 TRACE("got %u with %s\n", res
, debugstr_w((LPWSTR
) buffer
));
1042 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, (LPWSTR
) buffer
);
1043 pm
->monitor
->pfnXcvClosePort(hXcv
);
1050 /******************************************************************
1051 * monitor_load_by_port [internal]
1053 * load a printmonitor for a given port
1055 * On failure, NULL is returned
1058 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
1063 monitor_t
* pm
= NULL
;
1064 DWORD registered
= 0;
1068 TRACE("(%s)\n", debugstr_w(portname
));
1070 /* Try the Local Monitor first */
1071 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
) == ERROR_SUCCESS
) {
1072 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
1073 /* found the portname */
1075 return monitor_load(LocalPortW
, NULL
);
1080 len
= MAX_PATH
+ lstrlenW(bs_Ports_bsW
) + lstrlenW(portname
) + 1;
1081 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1082 if (buffer
== NULL
) return NULL
;
1084 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
1085 EnterCriticalSection(&monitor_handles_cs
);
1086 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1088 while ((pm
== NULL
) && (id
< registered
)) {
1090 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
1091 TRACE("testing %s\n", debugstr_w(buffer
));
1092 len
= lstrlenW(buffer
);
1093 lstrcatW(buffer
, bs_Ports_bsW
);
1094 lstrcatW(buffer
, portname
);
1095 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
1097 buffer
[len
] = '\0'; /* use only the Monitor-Name */
1098 pm
= monitor_load(buffer
, NULL
);
1102 LeaveCriticalSection(&monitor_handles_cs
);
1105 HeapFree(GetProcessHeap(), 0, buffer
);
1109 /******************************************************************
1110 * enumerate the local Ports from all loaded monitors (internal)
1112 * returns the needed size (in bytes) for pPorts
1113 * and *lpreturned is set to number of entries returned in pPorts
1116 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
1120 LPPORT_INFO_2W cache
;
1122 LPBYTE pi_buffer
= NULL
;
1123 DWORD pi_allocated
= 0;
1134 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
1135 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
1137 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1138 needed
= entrysize
* numentries
;
1139 ptr
= (LPWSTR
) &pPorts
[needed
];
1144 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
1146 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
1149 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1150 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
1151 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1152 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1153 pi_buffer
= HeapAlloc(GetProcessHeap(), 0, pi_needed
);
1154 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
1155 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1157 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1158 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
1160 numentries
+= pi_returned
;
1161 needed
+= pi_needed
;
1163 /* fill the output-buffer (pPorts), if we have one */
1164 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
1166 while (pi_returned
> pi_index
) {
1167 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
1168 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
1169 out
->pPortName
= ptr
;
1170 lstrcpyW(ptr
, cache
->pPortName
);
1171 ptr
+= (lstrlenW(ptr
)+1);
1173 out
->pMonitorName
= ptr
;
1174 lstrcpyW(ptr
, cache
->pMonitorName
);
1175 ptr
+= (lstrlenW(ptr
)+1);
1177 out
->pDescription
= ptr
;
1178 lstrcpyW(ptr
, cache
->pDescription
);
1179 ptr
+= (lstrlenW(ptr
)+1);
1180 out
->fPortType
= cache
->fPortType
;
1181 out
->Reserved
= cache
->Reserved
;
1189 /* the temporary portinfo-buffer is no longer needed */
1190 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1192 *lpreturned
= numentries
;
1193 TRACE("need %d byte for %d entries\n", needed
, numentries
);
1197 /******************************************************************
1198 * get_servername_from_name (internal)
1200 * for an external server, a copy of the serverpart from the full name is returned
1203 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1207 WCHAR buffer
[MAX_PATH
];
1210 if (name
== NULL
) return NULL
;
1211 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1213 server
= strdupW(&name
[2]); /* skip over both backslash */
1214 if (server
== NULL
) return NULL
;
1216 /* strip '\' and the printername */
1217 ptr
= strchrW(server
, '\\');
1218 if (ptr
) ptr
[0] = '\0';
1220 TRACE("found %s\n", debugstr_w(server
));
1222 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1223 if (GetComputerNameW(buffer
, &len
)) {
1224 if (lstrcmpW(buffer
, server
) == 0) {
1225 /* The requested Servername is our computername */
1226 HeapFree(GetProcessHeap(), 0, server
);
1233 /******************************************************************
1234 * get_basename_from_name (internal)
1236 * skip over the serverpart from the full name
1239 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1241 if (name
== NULL
) return NULL
;
1242 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1243 /* skip over the servername and search for the following '\' */
1244 name
= strchrW(&name
[2], '\\');
1245 if ((name
) && (name
[1])) {
1246 /* found a separator ('\') followed by a name:
1247 skip over the separator and return the rest */
1252 /* no basename present (we found only a servername) */
1259 /******************************************************************
1260 * get_opened_printer_entry
1261 * Get the first place empty in the opened printer table
1264 * - pDefault is ignored
1266 static HANDLE
get_opened_printer_entry(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1268 UINT_PTR handle
= nb_printer_handles
, i
;
1269 jobqueue_t
*queue
= NULL
;
1270 opened_printer_t
*printer
= NULL
;
1272 LPCWSTR printername
;
1277 servername
= get_servername_from_name(name
);
1279 FIXME("server %s not supported\n", debugstr_w(servername
));
1280 HeapFree(GetProcessHeap(), 0, servername
);
1281 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1285 printername
= get_basename_from_name(name
);
1286 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1288 /* an empty printername is invalid */
1289 if (printername
&& (!printername
[0])) {
1290 SetLastError(ERROR_INVALID_PARAMETER
);
1294 EnterCriticalSection(&printer_handles_cs
);
1296 for (i
= 0; i
< nb_printer_handles
; i
++)
1298 if (!printer_handles
[i
])
1300 if(handle
== nb_printer_handles
)
1305 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1306 queue
= printer_handles
[i
]->queue
;
1310 if (handle
>= nb_printer_handles
)
1312 opened_printer_t
**new_array
;
1313 if (printer_handles
)
1314 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1315 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1317 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1318 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1325 printer_handles
= new_array
;
1326 nb_printer_handles
+= 16;
1329 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1336 /* clone the base name. This is NULL for the printserver */
1337 printer
->printername
= strdupW(printername
);
1339 /* clone the full name */
1340 printer
->name
= strdupW(name
);
1341 if (name
&& (!printer
->name
)) {
1347 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1348 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1349 /* OpenPrinter(",XcvMonitor " detected */
1350 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1351 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1352 if (printer
->pm
== NULL
) {
1353 SetLastError(ERROR_UNKNOWN_PORT
);
1360 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1361 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1362 /* OpenPrinter(",XcvPort " detected */
1363 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1364 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1365 if (printer
->pm
== NULL
) {
1366 SetLastError(ERROR_UNKNOWN_PORT
);
1374 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1375 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1376 pDefault
? pDefault
->DesiredAccess
: 0,
1379 if (printer
->hXcv
== NULL
) {
1380 SetLastError(ERROR_INVALID_PARAMETER
);
1387 /* Does the Printer exist? */
1388 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1389 ERR("Can't create Printers key\n");
1393 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1394 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1395 RegCloseKey(hkeyPrinters
);
1396 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1400 RegCloseKey(hkeyPrinter
);
1401 RegCloseKey(hkeyPrinters
);
1406 TRACE("using the local printserver\n");
1410 printer
->queue
= queue
;
1413 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1414 if (!printer
->queue
) {
1418 list_init(&printer
->queue
->jobs
);
1419 printer
->queue
->ref
= 0;
1421 InterlockedIncrement(&printer
->queue
->ref
);
1423 printer_handles
[handle
] = printer
;
1426 LeaveCriticalSection(&printer_handles_cs
);
1427 if (!handle
&& printer
) {
1428 /* Something failed: Free all resources */
1429 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1430 monitor_unload(printer
->pm
);
1431 HeapFree(GetProcessHeap(), 0, printer
->printername
);
1432 HeapFree(GetProcessHeap(), 0, printer
->name
);
1433 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1434 HeapFree(GetProcessHeap(), 0, printer
);
1437 return (HANDLE
)handle
;
1440 /******************************************************************
1441 * get_opened_printer
1442 * Get the pointer to the opened printer referred by the handle
1444 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
1446 UINT_PTR idx
= (UINT_PTR
)hprn
;
1447 opened_printer_t
*ret
= NULL
;
1449 EnterCriticalSection(&printer_handles_cs
);
1451 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
1452 ret
= printer_handles
[idx
- 1];
1454 LeaveCriticalSection(&printer_handles_cs
);
1458 /******************************************************************
1459 * get_opened_printer_name
1460 * Get the pointer to the opened printer name referred by the handle
1462 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
1464 opened_printer_t
*printer
= get_opened_printer(hprn
);
1465 if(!printer
) return NULL
;
1466 return printer
->name
;
1469 /******************************************************************
1470 * WINSPOOL_GetOpenedPrinterRegKey
1473 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
1475 LPCWSTR name
= get_opened_printer_name(hPrinter
);
1479 if(!name
) return ERROR_INVALID_HANDLE
;
1481 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
1485 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
1487 ERR("Can't find opened printer %s in registry\n",
1489 RegCloseKey(hkeyPrinters
);
1490 return ERROR_INVALID_PRINTER_NAME
; /* ? */
1492 RegCloseKey(hkeyPrinters
);
1493 return ERROR_SUCCESS
;
1496 void WINSPOOL_LoadSystemPrinters(void)
1498 HKEY hkey
, hkeyPrinters
;
1500 DWORD needed
, num
, i
;
1501 WCHAR PrinterName
[256];
1504 /* This ensures that all printer entries have a valid Name value. If causes
1505 problems later if they don't. If one is found to be missed we create one
1506 and set it equal to the name of the key */
1507 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1508 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1509 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1510 for(i
= 0; i
< num
; i
++) {
1511 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1512 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1513 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1514 set_reg_szW(hkey
, NameW
, PrinterName
);
1521 RegCloseKey(hkeyPrinters
);
1524 /* We want to avoid calling AddPrinter on printers as much as
1525 possible, because on cups printers this will (eventually) lead
1526 to a call to cupsGetPPD which takes forever, even with non-cups
1527 printers AddPrinter takes a while. So we'll tag all printers that
1528 were automatically added last time around, if they still exist
1529 we'll leave them be otherwise we'll delete them. */
1530 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1532 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1533 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1534 for(i
= 0; i
< num
; i
++) {
1535 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1536 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1537 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1539 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1547 HeapFree(GetProcessHeap(), 0, pi
);
1551 #ifdef SONAME_LIBCUPS
1552 done
= CUPS_LoadPrinters();
1555 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1556 PRINTCAP_LoadPrinters();
1558 /* Now enumerate the list again and delete any printers that are still tagged */
1559 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1561 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1562 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1563 for(i
= 0; i
< num
; i
++) {
1564 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1565 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1566 BOOL delete_driver
= FALSE
;
1567 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1568 DWORD dw
, type
, size
= sizeof(dw
);
1569 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1570 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1571 DeletePrinter(hprn
);
1572 delete_driver
= TRUE
;
1578 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1583 HeapFree(GetProcessHeap(), 0, pi
);
1590 /******************************************************************
1593 * Get the pointer to the specified job.
1594 * Should hold the printer_handles_cs before calling.
1596 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1598 opened_printer_t
*printer
= get_opened_printer(hprn
);
1601 if(!printer
) return NULL
;
1602 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1604 if(job
->job_id
== JobId
)
1610 /***********************************************************
1613 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1616 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1619 Formname
= (dmA
->dmSize
> off_formname
);
1620 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1621 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1622 dmW
->dmDeviceName
, CCHDEVICENAME
);
1624 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1625 dmA
->dmSize
- CCHDEVICENAME
);
1627 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1628 off_formname
- CCHDEVICENAME
);
1629 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1630 dmW
->dmFormName
, CCHFORMNAME
);
1631 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1632 (off_formname
+ CCHFORMNAME
));
1635 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1636 dmA
->dmDriverExtra
);
1640 /***********************************************************
1642 * Creates an ansi copy of supplied devmode
1644 static LPDEVMODEA
DEVMODEdupWtoA(const DEVMODEW
*dmW
)
1649 if (!dmW
) return NULL
;
1650 size
= dmW
->dmSize
- CCHDEVICENAME
-
1651 ((dmW
->dmSize
> FIELD_OFFSET(DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
1653 dmA
= HeapAlloc(GetProcessHeap(), 0, size
+ dmW
->dmDriverExtra
);
1654 if (!dmA
) return NULL
;
1656 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1657 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1659 if (FIELD_OFFSET(DEVMODEW
, dmFormName
) >= dmW
->dmSize
) {
1660 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1661 dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1665 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1666 FIELD_OFFSET(DEVMODEW
, dmFormName
) - FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1667 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1668 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1670 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmLogPixels
));
1674 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
1678 /******************************************************************
1679 * convert_printerinfo_W_to_A [internal]
1682 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1683 DWORD level
, DWORD outlen
, DWORD numentries
)
1689 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1691 len
= pi_sizeof
[level
] * numentries
;
1692 ptr
= (LPSTR
) out
+ len
;
1695 /* copy the numbers of all PRINTER_INFO_* first */
1696 memcpy(out
, pPrintersW
, len
);
1698 while (id
< numentries
) {
1702 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1703 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1705 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1706 if (piW
->pDescription
) {
1707 piA
->pDescription
= ptr
;
1708 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1709 ptr
, outlen
, NULL
, NULL
);
1715 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1716 ptr
, outlen
, NULL
, NULL
);
1720 if (piW
->pComment
) {
1721 piA
->pComment
= ptr
;
1722 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1723 ptr
, outlen
, NULL
, NULL
);
1732 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1733 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1736 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1737 if (piW
->pServerName
) {
1738 piA
->pServerName
= ptr
;
1739 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1740 ptr
, outlen
, NULL
, NULL
);
1744 if (piW
->pPrinterName
) {
1745 piA
->pPrinterName
= ptr
;
1746 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1747 ptr
, outlen
, NULL
, NULL
);
1751 if (piW
->pShareName
) {
1752 piA
->pShareName
= ptr
;
1753 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1754 ptr
, outlen
, NULL
, NULL
);
1758 if (piW
->pPortName
) {
1759 piA
->pPortName
= ptr
;
1760 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1761 ptr
, outlen
, NULL
, NULL
);
1765 if (piW
->pDriverName
) {
1766 piA
->pDriverName
= ptr
;
1767 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1768 ptr
, outlen
, NULL
, NULL
);
1772 if (piW
->pComment
) {
1773 piA
->pComment
= ptr
;
1774 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1775 ptr
, outlen
, NULL
, NULL
);
1779 if (piW
->pLocation
) {
1780 piA
->pLocation
= ptr
;
1781 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1782 ptr
, outlen
, NULL
, NULL
);
1787 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1789 /* align DEVMODEA to a DWORD boundary */
1790 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1794 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1795 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1796 memcpy(ptr
, dmA
, len
);
1797 HeapFree(GetProcessHeap(), 0, dmA
);
1803 if (piW
->pSepFile
) {
1804 piA
->pSepFile
= ptr
;
1805 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1806 ptr
, outlen
, NULL
, NULL
);
1810 if (piW
->pPrintProcessor
) {
1811 piA
->pPrintProcessor
= ptr
;
1812 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1813 ptr
, outlen
, NULL
, NULL
);
1817 if (piW
->pDatatype
) {
1818 piA
->pDatatype
= ptr
;
1819 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1820 ptr
, outlen
, NULL
, NULL
);
1824 if (piW
->pParameters
) {
1825 piA
->pParameters
= ptr
;
1826 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1827 ptr
, outlen
, NULL
, NULL
);
1831 if (piW
->pSecurityDescriptor
) {
1832 piA
->pSecurityDescriptor
= NULL
;
1833 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1840 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1841 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1843 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1845 if (piW
->pPrinterName
) {
1846 piA
->pPrinterName
= ptr
;
1847 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1848 ptr
, outlen
, NULL
, NULL
);
1852 if (piW
->pServerName
) {
1853 piA
->pServerName
= ptr
;
1854 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1855 ptr
, outlen
, NULL
, NULL
);
1864 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1865 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1867 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1869 if (piW
->pPrinterName
) {
1870 piA
->pPrinterName
= ptr
;
1871 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1872 ptr
, outlen
, NULL
, NULL
);
1876 if (piW
->pPortName
) {
1877 piA
->pPortName
= ptr
;
1878 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1879 ptr
, outlen
, NULL
, NULL
);
1887 FIXME("for level %u\n", level
);
1889 pPrintersW
+= pi_sizeof
[level
];
1890 out
+= pi_sizeof
[level
];
1895 /***********************************************************
1896 * PRINTER_INFO_2AtoW
1897 * Creates a unicode copy of PRINTER_INFO_2A on heap
1899 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1901 LPPRINTER_INFO_2W piW
;
1902 UNICODE_STRING usBuffer
;
1904 if(!piA
) return NULL
;
1905 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1906 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1908 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1909 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1910 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1911 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1912 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1913 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1914 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1915 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1916 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1917 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1918 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1919 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1923 /***********************************************************
1924 * FREE_PRINTER_INFO_2W
1925 * Free PRINTER_INFO_2W and all strings
1927 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1931 HeapFree(heap
,0,piW
->pServerName
);
1932 HeapFree(heap
,0,piW
->pPrinterName
);
1933 HeapFree(heap
,0,piW
->pShareName
);
1934 HeapFree(heap
,0,piW
->pPortName
);
1935 HeapFree(heap
,0,piW
->pDriverName
);
1936 HeapFree(heap
,0,piW
->pComment
);
1937 HeapFree(heap
,0,piW
->pLocation
);
1938 HeapFree(heap
,0,piW
->pDevMode
);
1939 HeapFree(heap
,0,piW
->pSepFile
);
1940 HeapFree(heap
,0,piW
->pPrintProcessor
);
1941 HeapFree(heap
,0,piW
->pDatatype
);
1942 HeapFree(heap
,0,piW
->pParameters
);
1943 HeapFree(heap
,0,piW
);
1947 /******************************************************************
1948 * DeviceCapabilities [WINSPOOL.@]
1949 * DeviceCapabilitiesA [WINSPOOL.@]
1952 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1953 LPSTR pOutput
, LPDEVMODEA lpdm
)
1957 if (!GDI_CallDeviceCapabilities16
)
1959 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1961 if (!GDI_CallDeviceCapabilities16
) return -1;
1963 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1965 /* If DC_PAPERSIZE map POINT16s to POINTs */
1966 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1967 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1968 POINT
*pt
= (POINT
*)pOutput
;
1970 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1971 for(i
= 0; i
< ret
; i
++, pt
++)
1976 HeapFree( GetProcessHeap(), 0, tmp
);
1982 /*****************************************************************************
1983 * DeviceCapabilitiesW [WINSPOOL.@]
1985 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1988 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1989 WORD fwCapability
, LPWSTR pOutput
,
1990 const DEVMODEW
*pDevMode
)
1992 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
1993 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1994 LPSTR pPortA
= strdupWtoA(pPort
);
1997 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1998 fwCapability
== DC_FILEDEPENDENCIES
||
1999 fwCapability
== DC_PAPERNAMES
)) {
2000 /* These need A -> W translation */
2003 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
2007 switch(fwCapability
) {
2012 case DC_FILEDEPENDENCIES
:
2016 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
2017 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
2019 for(i
= 0; i
< ret
; i
++)
2020 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
2021 pOutput
+ (i
* size
), size
);
2022 HeapFree(GetProcessHeap(), 0, pOutputA
);
2024 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
2025 (LPSTR
)pOutput
, dmA
);
2027 HeapFree(GetProcessHeap(),0,pPortA
);
2028 HeapFree(GetProcessHeap(),0,pDeviceA
);
2029 HeapFree(GetProcessHeap(),0,dmA
);
2033 /******************************************************************
2034 * DocumentPropertiesA [WINSPOOL.@]
2036 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2038 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
2039 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
2040 LPDEVMODEA pDevModeInput
,DWORD fMode
)
2042 LPSTR lpName
= pDeviceName
;
2043 static CHAR port
[] = "LPT1:";
2046 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2047 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
2051 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2053 ERR("no name from hPrinter?\n");
2054 SetLastError(ERROR_INVALID_HANDLE
);
2057 lpName
= strdupWtoA(lpNameW
);
2060 if (!GDI_CallExtDeviceMode16
)
2062 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2064 if (!GDI_CallExtDeviceMode16
) {
2065 ERR("No CallExtDeviceMode16?\n");
2069 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
2070 pDevModeInput
, NULL
, fMode
);
2073 HeapFree(GetProcessHeap(),0,lpName
);
2078 /*****************************************************************************
2079 * DocumentPropertiesW (WINSPOOL.@)
2081 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2083 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
2085 LPDEVMODEW pDevModeOutput
,
2086 LPDEVMODEW pDevModeInput
, DWORD fMode
)
2089 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
2090 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
2091 LPDEVMODEA pDevModeOutputA
= NULL
;
2094 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2095 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
2097 if(pDevModeOutput
) {
2098 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
2099 if(ret
< 0) return ret
;
2100 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
2102 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
2103 pDevModeInputA
, fMode
);
2104 if(pDevModeOutput
) {
2105 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
2106 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
2108 if(fMode
== 0 && ret
> 0)
2109 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2110 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
2111 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
2115 /******************************************************************
2116 * OpenPrinterA [WINSPOOL.@]
2121 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
2122 LPPRINTER_DEFAULTSA pDefault
)
2124 UNICODE_STRING lpPrinterNameW
;
2125 UNICODE_STRING usBuffer
;
2126 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
2127 PWSTR pwstrPrinterNameW
;
2130 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
2133 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
2134 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
2135 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
2136 pDefaultW
= &DefaultW
;
2138 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
2140 RtlFreeUnicodeString(&usBuffer
);
2141 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
2143 RtlFreeUnicodeString(&lpPrinterNameW
);
2147 /******************************************************************
2148 * OpenPrinterW [WINSPOOL.@]
2150 * Open a Printer / Printserver or a Printer-Object
2153 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2154 * phPrinter [O] The resulting Handle is stored here
2155 * pDefault [I] PTR to Default Printer Settings or NULL
2162 * lpPrinterName is one of:
2163 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2164 *| Printer: "PrinterName"
2165 *| Printer-Object: "PrinterName,Job xxx"
2166 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2167 *| XcvPort: "Servername,XcvPort PortName"
2170 *| Printer-Object not supported
2171 *| pDefaults is ignored
2174 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2177 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2179 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2180 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
2184 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2185 SetLastError(ERROR_INVALID_PARAMETER
);
2189 /* Get the unique handle of the printer or Printserver */
2190 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2191 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2192 return (*phPrinter
!= 0);
2195 /******************************************************************
2196 * AddMonitorA [WINSPOOL.@]
2201 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2203 LPWSTR nameW
= NULL
;
2206 LPMONITOR_INFO_2A mi2a
;
2207 MONITOR_INFO_2W mi2w
;
2209 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2210 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2211 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2212 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2213 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2216 SetLastError(ERROR_INVALID_LEVEL
);
2220 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2226 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2227 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2228 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2231 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2233 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2234 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2235 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2237 if (mi2a
->pEnvironment
) {
2238 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2239 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2240 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2242 if (mi2a
->pDLLName
) {
2243 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2244 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2245 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2248 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2250 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2251 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2252 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2254 HeapFree(GetProcessHeap(), 0, nameW
);
2258 /******************************************************************************
2259 * AddMonitorW [WINSPOOL.@]
2261 * Install a Printmonitor
2264 * pName [I] Servername or NULL (local Computer)
2265 * Level [I] Structure-Level (Must be 2)
2266 * pMonitors [I] PTR to MONITOR_INFO_2
2273 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2276 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2278 LPMONITOR_INFO_2W mi2w
;
2280 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2281 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2282 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2283 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2284 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2286 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2289 SetLastError(ERROR_INVALID_LEVEL
);
2293 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2298 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2301 /******************************************************************
2302 * DeletePrinterDriverA [WINSPOOL.@]
2305 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2307 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2310 /******************************************************************
2311 * DeletePrinterDriverW [WINSPOOL.@]
2314 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2316 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2319 /******************************************************************
2320 * DeleteMonitorA [WINSPOOL.@]
2322 * See DeleteMonitorW.
2325 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2327 LPWSTR nameW
= NULL
;
2328 LPWSTR EnvironmentW
= NULL
;
2329 LPWSTR MonitorNameW
= NULL
;
2334 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2335 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2336 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2340 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2341 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2342 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2345 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2346 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2347 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2350 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2352 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2353 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2354 HeapFree(GetProcessHeap(), 0, nameW
);
2358 /******************************************************************
2359 * DeleteMonitorW [WINSPOOL.@]
2361 * Delete a specific Printmonitor from a Printing-Environment
2364 * pName [I] Servername or NULL (local Computer)
2365 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2366 * pMonitorName [I] Name of the Monitor, that should be deleted
2373 * pEnvironment is ignored in Windows for the local Computer.
2376 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2379 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2380 debugstr_w(pMonitorName
));
2382 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2384 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2388 /******************************************************************
2389 * DeletePortA [WINSPOOL.@]
2394 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2396 LPWSTR nameW
= NULL
;
2397 LPWSTR portW
= NULL
;
2401 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2403 /* convert servername to unicode */
2405 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2406 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2407 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2410 /* convert portname to unicode */
2412 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2413 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2414 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2417 res
= DeletePortW(nameW
, hWnd
, portW
);
2418 HeapFree(GetProcessHeap(), 0, nameW
);
2419 HeapFree(GetProcessHeap(), 0, portW
);
2423 /******************************************************************
2424 * DeletePortW [WINSPOOL.@]
2426 * Delete a specific Port
2429 * pName [I] Servername or NULL (local Computer)
2430 * hWnd [I] Handle to parent Window for the Dialog-Box
2431 * pPortName [I] Name of the Port, that should be deleted
2438 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2444 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2446 if (pName
&& pName
[0]) {
2447 SetLastError(ERROR_INVALID_PARAMETER
);
2452 SetLastError(RPC_X_NULL_REF_POINTER
);
2456 /* an empty Portname is Invalid */
2457 if (!pPortName
[0]) {
2458 SetLastError(ERROR_NOT_SUPPORTED
);
2462 pm
= monitor_load_by_port(pPortName
);
2463 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
2464 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2465 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
2466 TRACE("got %d with %u\n", res
, GetLastError());
2470 pui
= monitor_loadui(pm
);
2471 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2472 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2473 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2474 TRACE("got %d with %u\n", res
, GetLastError());
2478 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
2479 pm
, debugstr_w(pm
? pm
->dllname
: NULL
), pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
2481 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2482 SetLastError(ERROR_NOT_SUPPORTED
);
2485 monitor_unload(pui
);
2489 TRACE("returning %d with %u\n", res
, GetLastError());
2493 /******************************************************************************
2494 * SetPrinterW [WINSPOOL.@]
2496 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2498 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2499 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2503 /******************************************************************************
2504 * WritePrinter [WINSPOOL.@]
2506 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2508 opened_printer_t
*printer
;
2511 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2513 EnterCriticalSection(&printer_handles_cs
);
2514 printer
= get_opened_printer(hPrinter
);
2517 SetLastError(ERROR_INVALID_HANDLE
);
2523 SetLastError(ERROR_SPL_NO_STARTDOC
);
2527 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2529 LeaveCriticalSection(&printer_handles_cs
);
2533 /*****************************************************************************
2534 * AddFormA [WINSPOOL.@]
2536 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2538 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2542 /*****************************************************************************
2543 * AddFormW [WINSPOOL.@]
2545 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2547 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2551 /*****************************************************************************
2552 * AddJobA [WINSPOOL.@]
2554 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2557 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2561 SetLastError(ERROR_INVALID_LEVEL
);
2565 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2568 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2569 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2570 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2571 if(*pcbNeeded
> cbBuf
) {
2572 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2575 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2576 addjobA
->JobId
= addjobW
->JobId
;
2577 addjobA
->Path
= (char *)(addjobA
+ 1);
2578 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2584 /*****************************************************************************
2585 * AddJobW [WINSPOOL.@]
2587 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2589 opened_printer_t
*printer
;
2592 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2593 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2594 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2596 ADDJOB_INFO_1W
*addjob
;
2598 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2600 EnterCriticalSection(&printer_handles_cs
);
2602 printer
= get_opened_printer(hPrinter
);
2605 SetLastError(ERROR_INVALID_HANDLE
);
2610 SetLastError(ERROR_INVALID_LEVEL
);
2614 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2618 job
->job_id
= InterlockedIncrement(&next_job_id
);
2620 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2621 if(path
[len
- 1] != '\\')
2623 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2624 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2626 len
= strlenW(filename
);
2627 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2628 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2629 job
->document_title
= strdupW(default_doc_title
);
2630 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2632 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2633 if(*pcbNeeded
<= cbBuf
) {
2634 addjob
= (ADDJOB_INFO_1W
*)pData
;
2635 addjob
->JobId
= job
->job_id
;
2636 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2637 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2640 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2643 LeaveCriticalSection(&printer_handles_cs
);
2647 /*****************************************************************************
2648 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2650 * Return the PATH for the Print-Processors
2652 * See GetPrintProcessorDirectoryW.
2656 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2657 DWORD level
, LPBYTE Info
,
2658 DWORD cbBuf
, LPDWORD pcbNeeded
)
2660 LPWSTR serverW
= NULL
;
2665 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2666 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2670 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2671 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2672 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2676 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2677 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2678 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2681 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2682 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2684 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2687 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2688 cbBuf
, NULL
, NULL
) > 0;
2691 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2692 HeapFree(GetProcessHeap(), 0, envW
);
2693 HeapFree(GetProcessHeap(), 0, serverW
);
2697 /*****************************************************************************
2698 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2700 * Return the PATH for the Print-Processors
2703 * server [I] Servername (NT only) or NULL (local Computer)
2704 * env [I] Printing-Environment (see below) or NULL (Default)
2705 * level [I] Structure-Level (must be 1)
2706 * Info [O] PTR to Buffer that receives the Result
2707 * cbBuf [I] Size of Buffer at "Info"
2708 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2709 * required for the Buffer at "Info"
2712 * Success: TRUE and in pcbNeeded the Bytes used in Info
2713 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2714 * if cbBuf is too small
2716 * Native Values returned in Info on Success:
2717 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2718 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2719 *| win9x(Windows 4.0): "%winsysdir%"
2721 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2724 * Only NULL or "" is supported for server
2727 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2728 DWORD level
, LPBYTE Info
,
2729 DWORD cbBuf
, LPDWORD pcbNeeded
)
2732 const printenv_t
* env_t
;
2734 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
),
2735 debugstr_w(env
), level
, Info
, cbBuf
, pcbNeeded
);
2737 if(server
!= NULL
&& server
[0]) {
2738 FIXME("server not supported: %s\n", debugstr_w(server
));
2739 SetLastError(ERROR_INVALID_PARAMETER
);
2743 env_t
= validate_envW(env
);
2744 if(!env_t
) return FALSE
; /* environment invalid or unsupported */
2747 WARN("(Level: %d) is ignored in win9x\n", level
);
2748 SetLastError(ERROR_INVALID_LEVEL
);
2752 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2753 needed
= GetSystemDirectoryW(NULL
, 0);
2754 /* add the Size for the Subdirectories */
2755 needed
+= lstrlenW(spoolprtprocsW
);
2756 needed
+= lstrlenW(env_t
->subdir
);
2757 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2759 if(pcbNeeded
) *pcbNeeded
= needed
;
2760 TRACE ("required: 0x%x/%d\n", needed
, needed
);
2761 if (needed
> cbBuf
) {
2762 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2765 if(pcbNeeded
== NULL
) {
2766 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2767 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2768 SetLastError(RPC_X_NULL_REF_POINTER
);
2772 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2773 SetLastError(RPC_X_NULL_REF_POINTER
);
2777 GetSystemDirectoryW((LPWSTR
) Info
, cbBuf
/sizeof(WCHAR
));
2778 /* add the Subdirectories */
2779 lstrcatW((LPWSTR
) Info
, spoolprtprocsW
);
2780 lstrcatW((LPWSTR
) Info
, env_t
->subdir
);
2781 TRACE(" => %s\n", debugstr_w((LPWSTR
) Info
));
2785 /*****************************************************************************
2786 * WINSPOOL_OpenDriverReg [internal]
2788 * opens the registry for the printer drivers depending on the given input
2789 * variable pEnvironment
2792 * the opened hkey on success
2795 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
, BOOL unicode
)
2799 const printenv_t
* env
;
2802 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
), unicode
);
2804 if (!pEnvironment
|| unicode
) {
2805 /* pEnvironment was NULL or a Unicode-String: use it direct */
2806 env
= validate_envW(pEnvironment
);
2810 /* pEnvironment was an ANSI-String: convert to unicode first */
2812 INT len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2813 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2814 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, buffer
, len
);
2815 env
= validate_envW(buffer
);
2816 HeapFree(GetProcessHeap(), 0, buffer
);
2818 if (!env
) return NULL
;
2820 buffer
= HeapAlloc( GetProcessHeap(), 0,
2821 (strlenW(DriversW
) + strlenW(env
->envname
) +
2822 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2824 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2825 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2826 HeapFree(GetProcessHeap(), 0, buffer
);
2831 /*****************************************************************************
2832 * AddPrinterW [WINSPOOL.@]
2834 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2836 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2840 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2842 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2843 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2844 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2845 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2846 statusW
[] = {'S','t','a','t','u','s',0},
2847 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2849 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2852 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2853 SetLastError(ERROR_INVALID_PARAMETER
);
2857 ERR("Level = %d, unsupported!\n", Level
);
2858 SetLastError(ERROR_INVALID_LEVEL
);
2862 SetLastError(ERROR_INVALID_PARAMETER
);
2865 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2867 ERR("Can't create Printers key\n");
2870 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2871 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2872 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2873 RegCloseKey(hkeyPrinter
);
2874 RegCloseKey(hkeyPrinters
);
2877 RegCloseKey(hkeyPrinter
);
2879 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
2881 ERR("Can't create Drivers key\n");
2882 RegCloseKey(hkeyPrinters
);
2885 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2887 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2888 RegCloseKey(hkeyPrinters
);
2889 RegCloseKey(hkeyDrivers
);
2890 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2893 RegCloseKey(hkeyDriver
);
2894 RegCloseKey(hkeyDrivers
);
2896 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2897 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2898 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2899 RegCloseKey(hkeyPrinters
);
2903 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2905 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2906 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2907 RegCloseKey(hkeyPrinters
);
2910 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2911 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2912 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2914 /* See if we can load the driver. We may need the devmode structure anyway
2917 * Note that DocumentPropertiesW will briefly try to open the printer we
2918 * just create to find a DEVMODEA struct (it will use the WINEPS default
2919 * one in case it is not there, so we are ok).
2921 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2924 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2925 size
= sizeof(DEVMODEW
);
2931 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2933 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2935 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2936 HeapFree(GetProcessHeap(),0,dmW
);
2941 /* set devmode to printer name */
2942 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2946 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2947 and we support these drivers. NT writes DEVMODEW so somehow
2948 we'll need to distinguish between these when we support NT
2952 dmA
= DEVMODEdupWtoA(dmW
);
2953 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2954 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2955 HeapFree(GetProcessHeap(), 0, dmA
);
2957 HeapFree(GetProcessHeap(), 0, dmW
);
2959 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2960 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2961 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2962 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2964 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2965 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2966 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2967 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2968 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2969 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2970 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2971 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2972 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2973 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2974 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2975 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2976 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2978 RegCloseKey(hkeyPrinter
);
2979 RegCloseKey(hkeyPrinters
);
2980 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2981 ERR("OpenPrinter failing\n");
2987 /*****************************************************************************
2988 * AddPrinterA [WINSPOOL.@]
2990 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2992 UNICODE_STRING pNameW
;
2994 PRINTER_INFO_2W
*piW
;
2995 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2998 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
3000 ERR("Level = %d, unsupported!\n", Level
);
3001 SetLastError(ERROR_INVALID_LEVEL
);
3004 pwstrNameW
= asciitounicode(&pNameW
,pName
);
3005 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
3007 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
3009 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
3010 RtlFreeUnicodeString(&pNameW
);
3015 /*****************************************************************************
3016 * ClosePrinter [WINSPOOL.@]
3018 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
3020 UINT_PTR i
= (UINT_PTR
)hPrinter
;
3021 opened_printer_t
*printer
= NULL
;
3024 TRACE("(%p)\n", hPrinter
);
3026 EnterCriticalSection(&printer_handles_cs
);
3028 if ((i
> 0) && (i
<= nb_printer_handles
))
3029 printer
= printer_handles
[i
- 1];
3034 struct list
*cursor
, *cursor2
;
3036 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer
->pm
,
3037 debugstr_w(printer
->pm
? printer
->pm
->dllname
: NULL
),
3038 printer
->hXcv
, debugstr_w(printer
->name
), printer
->doc
);
3041 EndDocPrinter(hPrinter
);
3043 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
3045 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
3047 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
3048 ScheduleJob(hPrinter
, job
->job_id
);
3050 HeapFree(GetProcessHeap(), 0, printer
->queue
);
3052 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
3053 monitor_unload(printer
->pm
);
3054 HeapFree(GetProcessHeap(), 0, printer
->printername
);
3055 HeapFree(GetProcessHeap(), 0, printer
->name
);
3056 HeapFree(GetProcessHeap(), 0, printer
);
3057 printer_handles
[i
- 1] = NULL
;
3060 LeaveCriticalSection(&printer_handles_cs
);
3064 /*****************************************************************************
3065 * DeleteFormA [WINSPOOL.@]
3067 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3069 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3073 /*****************************************************************************
3074 * DeleteFormW [WINSPOOL.@]
3076 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3078 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3082 /*****************************************************************************
3083 * DeletePrinter [WINSPOOL.@]
3085 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3087 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3088 HKEY hkeyPrinters
, hkey
;
3091 SetLastError(ERROR_INVALID_HANDLE
);
3094 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3095 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3096 RegCloseKey(hkeyPrinters
);
3098 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3099 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
3101 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3102 RegDeleteValueW(hkey
, lpNameW
);
3106 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
3107 RegDeleteValueW(hkey
, lpNameW
);
3113 /*****************************************************************************
3114 * SetPrinterA [WINSPOOL.@]
3116 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3119 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
3123 /*****************************************************************************
3124 * SetJobA [WINSPOOL.@]
3126 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3127 LPBYTE pJob
, DWORD Command
)
3131 UNICODE_STRING usBuffer
;
3133 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3135 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3136 are all ignored by SetJob, so we don't bother copying them */
3144 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3145 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3147 JobW
= (LPBYTE
)info1W
;
3148 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3149 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3150 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3151 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3152 info1W
->Status
= info1A
->Status
;
3153 info1W
->Priority
= info1A
->Priority
;
3154 info1W
->Position
= info1A
->Position
;
3155 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3160 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3161 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3163 JobW
= (LPBYTE
)info2W
;
3164 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3165 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3166 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3167 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3168 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3169 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3170 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3171 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3172 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3173 info2W
->Status
= info2A
->Status
;
3174 info2W
->Priority
= info2A
->Priority
;
3175 info2W
->Position
= info2A
->Position
;
3176 info2W
->StartTime
= info2A
->StartTime
;
3177 info2W
->UntilTime
= info2A
->UntilTime
;
3178 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3182 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3183 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3186 SetLastError(ERROR_INVALID_LEVEL
);
3190 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3196 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3197 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3198 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3199 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3200 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3205 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3206 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3207 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3208 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3209 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3210 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3211 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3212 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3213 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3217 HeapFree(GetProcessHeap(), 0, JobW
);
3222 /*****************************************************************************
3223 * SetJobW [WINSPOOL.@]
3225 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3226 LPBYTE pJob
, DWORD Command
)
3231 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3232 FIXME("Ignoring everything other than document title\n");
3234 EnterCriticalSection(&printer_handles_cs
);
3235 job
= get_job(hPrinter
, JobId
);
3245 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3246 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3247 job
->document_title
= strdupW(info1
->pDocument
);
3252 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3253 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3254 job
->document_title
= strdupW(info2
->pDocument
);
3260 SetLastError(ERROR_INVALID_LEVEL
);
3265 LeaveCriticalSection(&printer_handles_cs
);
3269 /*****************************************************************************
3270 * EndDocPrinter [WINSPOOL.@]
3272 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3274 opened_printer_t
*printer
;
3276 TRACE("(%p)\n", hPrinter
);
3278 EnterCriticalSection(&printer_handles_cs
);
3280 printer
= get_opened_printer(hPrinter
);
3283 SetLastError(ERROR_INVALID_HANDLE
);
3289 SetLastError(ERROR_SPL_NO_STARTDOC
);
3293 CloseHandle(printer
->doc
->hf
);
3294 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3295 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3296 printer
->doc
= NULL
;
3299 LeaveCriticalSection(&printer_handles_cs
);
3303 /*****************************************************************************
3304 * EndPagePrinter [WINSPOOL.@]
3306 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3308 FIXME("(%p): stub\n", hPrinter
);
3312 /*****************************************************************************
3313 * StartDocPrinterA [WINSPOOL.@]
3315 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3317 UNICODE_STRING usBuffer
;
3319 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3322 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3323 or one (DOC_INFO_3) extra DWORDs */
3327 doc2W
.JobId
= doc2
->JobId
;
3330 doc2W
.dwMode
= doc2
->dwMode
;
3333 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3334 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3335 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3339 SetLastError(ERROR_INVALID_LEVEL
);
3343 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3345 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3346 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3347 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3352 /*****************************************************************************
3353 * StartDocPrinterW [WINSPOOL.@]
3355 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3357 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3358 opened_printer_t
*printer
;
3359 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3360 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3361 JOB_INFO_1W job_info
;
3362 DWORD needed
, ret
= 0;
3366 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3367 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3368 debugstr_w(doc
->pDatatype
));
3370 if(Level
< 1 || Level
> 3)
3372 SetLastError(ERROR_INVALID_LEVEL
);
3376 EnterCriticalSection(&printer_handles_cs
);
3377 printer
= get_opened_printer(hPrinter
);
3380 SetLastError(ERROR_INVALID_HANDLE
);
3386 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3390 /* Even if we're printing to a file we still add a print job, we'll
3391 just ignore the spool file name */
3393 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3395 ERR("AddJob failed gle %u\n", GetLastError());
3399 if(doc
->pOutputFile
)
3400 filename
= doc
->pOutputFile
;
3402 filename
= addjob
->Path
;
3404 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3405 if(hf
== INVALID_HANDLE_VALUE
)
3408 memset(&job_info
, 0, sizeof(job_info
));
3409 job_info
.pDocument
= doc
->pDocName
;
3410 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3412 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3413 printer
->doc
->hf
= hf
;
3414 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3416 LeaveCriticalSection(&printer_handles_cs
);
3421 /*****************************************************************************
3422 * StartPagePrinter [WINSPOOL.@]
3424 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3426 FIXME("(%p): stub\n", hPrinter
);
3430 /*****************************************************************************
3431 * GetFormA [WINSPOOL.@]
3433 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3434 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3436 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3437 Level
,pForm
,cbBuf
,pcbNeeded
);
3441 /*****************************************************************************
3442 * GetFormW [WINSPOOL.@]
3444 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3445 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3447 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3448 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3452 /*****************************************************************************
3453 * SetFormA [WINSPOOL.@]
3455 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3458 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3462 /*****************************************************************************
3463 * SetFormW [WINSPOOL.@]
3465 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3468 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3472 /*****************************************************************************
3473 * ReadPrinter [WINSPOOL.@]
3475 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3476 LPDWORD pNoBytesRead
)
3478 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3482 /*****************************************************************************
3483 * ResetPrinterA [WINSPOOL.@]
3485 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3487 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3491 /*****************************************************************************
3492 * ResetPrinterW [WINSPOOL.@]
3494 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3496 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3500 /*****************************************************************************
3501 * WINSPOOL_GetDWORDFromReg
3503 * Return DWORD associated with ValueName from hkey.
3505 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3507 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3510 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3512 if(ret
!= ERROR_SUCCESS
) {
3513 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3516 if(type
!= REG_DWORD
) {
3517 ERR("Got type %d\n", type
);
3524 /*****************************************************************************
3525 * get_filename_from_reg [internal]
3527 * Get ValueName from hkey storing result in out
3528 * when the Value in the registry has only a filename, use driverdir as prefix
3529 * outlen is space left in out
3530 * String is stored either as unicode or ascii
3534 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3535 LPBYTE out
, DWORD outlen
, LPDWORD needed
, BOOL unicode
)
3537 WCHAR filename
[MAX_PATH
];
3541 LPWSTR buffer
= filename
;
3545 size
= sizeof(filename
);
3547 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3548 if (ret
== ERROR_MORE_DATA
) {
3549 TRACE("need dynamic buffer: %u\n", size
);
3550 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3552 /* No Memory is bad */
3556 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3559 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3560 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3566 /* do we have a full path ? */
3567 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3568 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3571 /* we must build the full Path */
3573 if ((out
) && (outlen
> dirlen
)) {
3575 lstrcpyW((LPWSTR
)out
, driverdir
);
3579 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3588 /* write the filename */
3590 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3591 if ((out
) && (outlen
>= size
)) {
3592 lstrcpyW((LPWSTR
)out
, ptr
);
3601 size
= WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, NULL
, 0, NULL
, NULL
);
3602 if ((out
) && (outlen
>= size
)) {
3603 WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3611 ptr
+= lstrlenW(ptr
)+1;
3612 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3615 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3617 /* write the multisz-termination */
3618 if (type
== REG_MULTI_SZ
) {
3619 size
= (unicode
) ? sizeof(WCHAR
) : 1;
3622 if (out
&& (outlen
>= size
)) {
3623 memset (out
, 0, size
);
3629 /*****************************************************************************
3630 * WINSPOOL_GetStringFromReg
3632 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3633 * String is stored either as unicode or ascii.
3634 * Bit of a hack here to get the ValueName if we want ascii.
3636 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3637 DWORD buflen
, DWORD
*needed
,
3640 DWORD sz
= buflen
, type
;
3644 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3646 LPSTR ValueNameA
= strdupWtoA(ValueName
);
3647 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
3648 HeapFree(GetProcessHeap(),0,ValueNameA
);
3650 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3651 WARN("Got ret = %d\n", ret
);
3655 /* add space for terminating '\0' */
3656 sz
+= unicode
? sizeof(WCHAR
) : 1;
3660 TRACE("%s: %s\n", debugstr_w(ValueName
), unicode
? debugstr_w((LPCWSTR
)ptr
) : debugstr_a((LPCSTR
)ptr
));
3665 /*****************************************************************************
3666 * WINSPOOL_GetDefaultDevMode
3668 * Get a default DevMode values for wineps.
3672 static void WINSPOOL_GetDefaultDevMode(
3674 DWORD buflen
, DWORD
*needed
,
3678 static const char szwps
[] = "wineps.drv";
3680 /* fill default DEVMODE - should be read from ppd... */
3681 ZeroMemory( &dm
, sizeof(dm
) );
3682 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
3683 dm
.dmSpecVersion
= DM_SPECVERSION
;
3684 dm
.dmDriverVersion
= 1;
3685 dm
.dmSize
= sizeof(DEVMODEA
);
3686 dm
.dmDriverExtra
= 0;
3688 DM_ORIENTATION
| DM_PAPERSIZE
|
3689 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3692 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3693 DM_YRESOLUTION
| DM_TTOPTION
;
3695 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3696 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3697 dm
.u1
.s1
.dmPaperLength
= 2970;
3698 dm
.u1
.s1
.dmPaperWidth
= 2100;
3700 dm
.u1
.s1
.dmScale
= 100;
3701 dm
.u1
.s1
.dmCopies
= 1;
3702 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3703 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3706 dm
.dmYResolution
= 300; /* 300dpi */
3707 dm
.dmTTOption
= DMTT_BITMAP
;
3710 /* dm.dmLogPixels */
3711 /* dm.dmBitsPerPel */
3712 /* dm.dmPelsWidth */
3713 /* dm.dmPelsHeight */
3714 /* dm.u2.dmDisplayFlags */
3715 /* dm.dmDisplayFrequency */
3716 /* dm.dmICMMethod */
3717 /* dm.dmICMIntent */
3718 /* dm.dmMediaType */
3719 /* dm.dmDitherType */
3720 /* dm.dmReserved1 */
3721 /* dm.dmReserved2 */
3722 /* dm.dmPanningWidth */
3723 /* dm.dmPanningHeight */
3726 if(buflen
>= sizeof(DEVMODEW
)) {
3727 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
3728 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
3729 HeapFree(GetProcessHeap(),0,pdmW
);
3731 *needed
= sizeof(DEVMODEW
);
3735 if(buflen
>= sizeof(DEVMODEA
)) {
3736 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
3738 *needed
= sizeof(DEVMODEA
);
3742 /*****************************************************************************
3743 * WINSPOOL_GetDevModeFromReg
3745 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3746 * DevMode is stored either as unicode or ascii.
3748 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3750 DWORD buflen
, DWORD
*needed
,
3753 DWORD sz
= buflen
, type
;
3756 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3757 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3758 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3759 if (sz
< sizeof(DEVMODEA
))
3761 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3764 /* ensures that dmSize is not erratically bogus if registry is invalid */
3765 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3766 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3768 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3770 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3771 memcpy(ptr
, dmW
, sz
);
3772 HeapFree(GetProcessHeap(),0,dmW
);
3779 /*********************************************************************
3780 * WINSPOOL_GetPrinter_1
3782 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3783 * The strings are either stored as unicode or ascii.
3785 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3786 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3789 DWORD size
, left
= cbBuf
;
3790 BOOL space
= (cbBuf
> 0);
3795 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3797 if(space
&& size
<= left
) {
3798 pi1
->pName
= (LPWSTR
)ptr
;
3806 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3807 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3809 if(space
&& size
<= left
) {
3810 pi1
->pDescription
= (LPWSTR
)ptr
;
3818 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3820 if(space
&& size
<= left
) {
3821 pi1
->pComment
= (LPWSTR
)ptr
;
3829 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3831 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3832 memset(pi1
, 0, sizeof(*pi1
));
3836 /*********************************************************************
3837 * WINSPOOL_GetPrinter_2
3839 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3840 * The strings are either stored as unicode or ascii.
3842 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3843 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3846 DWORD size
, left
= cbBuf
;
3847 BOOL space
= (cbBuf
> 0);
3852 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3854 if(space
&& size
<= left
) {
3855 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3862 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
3864 if(space
&& size
<= left
) {
3865 pi2
->pShareName
= (LPWSTR
)ptr
;
3872 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3874 if(space
&& size
<= left
) {
3875 pi2
->pPortName
= (LPWSTR
)ptr
;
3882 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
3884 if(space
&& size
<= left
) {
3885 pi2
->pDriverName
= (LPWSTR
)ptr
;
3892 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3894 if(space
&& size
<= left
) {
3895 pi2
->pComment
= (LPWSTR
)ptr
;
3902 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
3904 if(space
&& size
<= left
) {
3905 pi2
->pLocation
= (LPWSTR
)ptr
;
3912 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
3914 if(space
&& size
<= left
) {
3915 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3924 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
3925 if(space
&& size
<= left
) {
3926 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3933 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
3935 if(space
&& size
<= left
) {
3936 pi2
->pSepFile
= (LPWSTR
)ptr
;
3943 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
3945 if(space
&& size
<= left
) {
3946 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3953 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
3955 if(space
&& size
<= left
) {
3956 pi2
->pDatatype
= (LPWSTR
)ptr
;
3963 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
3965 if(space
&& size
<= left
) {
3966 pi2
->pParameters
= (LPWSTR
)ptr
;
3974 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3975 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3976 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3977 "Default Priority");
3978 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3979 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3982 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3983 memset(pi2
, 0, sizeof(*pi2
));
3988 /*********************************************************************
3989 * WINSPOOL_GetPrinter_4
3991 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3993 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3994 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3997 DWORD size
, left
= cbBuf
;
3998 BOOL space
= (cbBuf
> 0);
4003 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
4005 if(space
&& size
<= left
) {
4006 pi4
->pPrinterName
= (LPWSTR
)ptr
;
4014 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
4017 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
4018 memset(pi4
, 0, sizeof(*pi4
));
4023 /*********************************************************************
4024 * WINSPOOL_GetPrinter_5
4026 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4028 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
4029 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4032 DWORD size
, left
= cbBuf
;
4033 BOOL space
= (cbBuf
> 0);
4038 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
4040 if(space
&& size
<= left
) {
4041 pi5
->pPrinterName
= (LPWSTR
)ptr
;
4048 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
4050 if(space
&& size
<= left
) {
4051 pi5
->pPortName
= (LPWSTR
)ptr
;
4059 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
4060 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
4062 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
4066 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
4067 memset(pi5
, 0, sizeof(*pi5
));
4072 /*********************************************************************
4073 * WINSPOOL_GetPrinter_7
4075 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4077 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
4078 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
4080 DWORD size
, left
= cbBuf
;
4081 BOOL space
= (cbBuf
> 0);
4086 if (WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
, unicode
))
4088 if (space
&& size
<= left
) {
4089 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
4097 /* We do not have a Directory Service */
4098 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
4101 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
4102 memset(pi7
, 0, sizeof(*pi7
));
4107 /*********************************************************************
4108 * WINSPOOL_GetPrinter_9
4110 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
4111 * The strings are either stored as unicode or ascii.
4113 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
4114 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
4117 BOOL space
= (cbBuf
> 0);
4121 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
, unicode
)) {
4122 if(space
&& size
<= cbBuf
) {
4123 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4130 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
, unicode
);
4131 if(space
&& size
<= cbBuf
) {
4132 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4138 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
4139 memset(pi9
, 0, sizeof(*pi9
));
4144 /*****************************************************************************
4145 * WINSPOOL_GetPrinter
4147 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4148 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4149 * just a collection of pointers to strings.
4151 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4152 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
4155 DWORD size
, needed
= 0;
4157 HKEY hkeyPrinter
, hkeyPrinters
;
4160 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4162 if (!(name
= get_opened_printer_name(hPrinter
))) {
4163 SetLastError(ERROR_INVALID_HANDLE
);
4167 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4169 ERR("Can't create Printers key\n");
4172 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
4174 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4175 RegCloseKey(hkeyPrinters
);
4176 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4183 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4185 size
= sizeof(PRINTER_INFO_2W
);
4187 ptr
= pPrinter
+ size
;
4189 memset(pPrinter
, 0, size
);
4194 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
4202 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4204 size
= sizeof(PRINTER_INFO_4W
);
4206 ptr
= pPrinter
+ size
;
4208 memset(pPrinter
, 0, size
);
4213 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
4222 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4224 size
= sizeof(PRINTER_INFO_5W
);
4226 ptr
= pPrinter
+ size
;
4228 memset(pPrinter
, 0, size
);
4234 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
4243 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4245 size
= sizeof(PRINTER_INFO_6
);
4246 if (size
<= cbBuf
) {
4247 /* FIXME: We do not update the status yet */
4248 pi6
->dwStatus
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Status");
4260 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4262 size
= sizeof(PRINTER_INFO_7W
);
4263 if (size
<= cbBuf
) {
4264 ptr
= pPrinter
+ size
;
4266 memset(pPrinter
, 0, size
);
4272 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
, unicode
);
4280 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4282 size
= sizeof(PRINTER_INFO_9W
);
4284 ptr
= pPrinter
+ size
;
4286 memset(pPrinter
, 0, size
);
4292 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
, unicode
);
4299 FIXME("Unimplemented level %d\n", Level
);
4300 SetLastError(ERROR_INVALID_LEVEL
);
4301 RegCloseKey(hkeyPrinters
);
4302 RegCloseKey(hkeyPrinter
);
4306 RegCloseKey(hkeyPrinter
);
4307 RegCloseKey(hkeyPrinters
);
4309 TRACE("returning %d needed = %d\n", ret
, needed
);
4310 if(pcbNeeded
) *pcbNeeded
= needed
;
4312 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4316 /*****************************************************************************
4317 * GetPrinterW [WINSPOOL.@]
4319 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4320 DWORD cbBuf
, LPDWORD pcbNeeded
)
4322 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4326 /*****************************************************************************
4327 * GetPrinterA [WINSPOOL.@]
4329 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4330 DWORD cbBuf
, LPDWORD pcbNeeded
)
4332 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4336 /*****************************************************************************
4337 * WINSPOOL_EnumPrinters
4339 * Implementation of EnumPrintersA|W
4341 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
4342 DWORD dwLevel
, LPBYTE lpbPrinters
,
4343 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4344 LPDWORD lpdwReturned
, BOOL unicode
)
4347 HKEY hkeyPrinters
, hkeyPrinter
;
4348 WCHAR PrinterName
[255];
4349 DWORD needed
= 0, number
= 0;
4350 DWORD used
, i
, left
;
4354 memset(lpbPrinters
, 0, cbBuf
);
4360 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4361 if(dwType
== PRINTER_ENUM_DEFAULT
)
4364 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4365 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4366 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4368 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4376 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4377 FIXME("dwType = %08x\n", dwType
);
4378 SetLastError(ERROR_INVALID_FLAGS
);
4382 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4384 ERR("Can't create Printers key\n");
4388 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4389 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4390 RegCloseKey(hkeyPrinters
);
4391 ERR("Can't query Printers key\n");
4394 TRACE("Found %d printers\n", number
);
4398 used
= number
* sizeof(PRINTER_INFO_1W
);
4401 used
= number
* sizeof(PRINTER_INFO_2W
);
4404 used
= number
* sizeof(PRINTER_INFO_4W
);
4407 used
= number
* sizeof(PRINTER_INFO_5W
);
4411 SetLastError(ERROR_INVALID_LEVEL
);
4412 RegCloseKey(hkeyPrinters
);
4415 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4417 for(i
= 0; i
< number
; i
++) {
4418 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4420 ERR("Can't enum key number %d\n", i
);
4421 RegCloseKey(hkeyPrinters
);
4424 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4425 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4427 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4428 RegCloseKey(hkeyPrinters
);
4433 buf
= lpbPrinters
+ used
;
4434 left
= cbBuf
- used
;
4442 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4443 left
, &needed
, unicode
);
4445 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4448 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4449 left
, &needed
, unicode
);
4451 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4454 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4455 left
, &needed
, unicode
);
4457 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4460 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4461 left
, &needed
, unicode
);
4463 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4466 ERR("Shouldn't be here!\n");
4467 RegCloseKey(hkeyPrinter
);
4468 RegCloseKey(hkeyPrinters
);
4471 RegCloseKey(hkeyPrinter
);
4473 RegCloseKey(hkeyPrinters
);
4480 memset(lpbPrinters
, 0, cbBuf
);
4481 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4485 *lpdwReturned
= number
;
4486 SetLastError(ERROR_SUCCESS
);
4491 /******************************************************************
4492 * EnumPrintersW [WINSPOOL.@]
4494 * Enumerates the available printers, print servers and print
4495 * providers, depending on the specified flags, name and level.
4499 * If level is set to 1:
4500 * Returns an array of PRINTER_INFO_1 data structures in the
4501 * lpbPrinters buffer.
4503 * If level is set to 2:
4504 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4505 * Returns an array of PRINTER_INFO_2 data structures in the
4506 * lpbPrinters buffer. Note that according to MSDN also an
4507 * OpenPrinter should be performed on every remote printer.
4509 * If level is set to 4 (officially WinNT only):
4510 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4511 * Fast: Only the registry is queried to retrieve printer names,
4512 * no connection to the driver is made.
4513 * Returns an array of PRINTER_INFO_4 data structures in the
4514 * lpbPrinters buffer.
4516 * If level is set to 5 (officially WinNT4/Win9x only):
4517 * Fast: Only the registry is queried to retrieve printer names,
4518 * no connection to the driver is made.
4519 * Returns an array of PRINTER_INFO_5 data structures in the
4520 * lpbPrinters buffer.
4522 * If level set to 3 or 6+:
4523 * returns zero (failure!)
4525 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4529 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4530 * - Only levels 2, 4 and 5 are implemented at the moment.
4531 * - 16-bit printer drivers are not enumerated.
4532 * - Returned amount of bytes used/needed does not match the real Windoze
4533 * implementation (as in this implementation, all strings are part
4534 * of the buffer, whereas Win32 keeps them somewhere else)
4535 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4538 * - In a regular Wine installation, no registry settings for printers
4539 * exist, which makes this function return an empty list.
4541 BOOL WINAPI
EnumPrintersW(
4542 DWORD dwType
, /* [in] Types of print objects to enumerate */
4543 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4544 DWORD dwLevel
, /* [in] type of printer info structure */
4545 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4546 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4547 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4548 LPDWORD lpdwReturned
/* [out] number of entries returned */
4551 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4552 lpdwNeeded
, lpdwReturned
, TRUE
);
4555 /******************************************************************
4556 * EnumPrintersA [WINSPOOL.@]
4561 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4562 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4565 UNICODE_STRING pNameU
;
4569 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4570 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4572 pNameW
= asciitounicode(&pNameU
, pName
);
4574 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4575 MS Office need this */
4576 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4578 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4580 RtlFreeUnicodeString(&pNameU
);
4582 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4584 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4588 /*****************************************************************************
4589 * WINSPOOL_GetDriverInfoFromReg [internal]
4591 * Enters the information from the registry into the DRIVER_INFO struct
4594 * zero if the printer driver does not exist in the registry
4595 * (only if Level > 1) otherwise nonzero
4597 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4600 const printenv_t
* env
,
4602 LPBYTE ptr
, /* DRIVER_INFO */
4603 LPBYTE pDriverStrings
, /* strings buffer */
4604 DWORD cbBuf
, /* size of string buffer */
4605 LPDWORD pcbNeeded
, /* space needed for str. */
4606 BOOL unicode
) /* type of strings */
4610 WCHAR driverdir
[MAX_PATH
];
4612 LPBYTE strPtr
= pDriverStrings
;
4613 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4615 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers
,
4616 debugstr_w(DriverName
), env
,
4617 Level
, di
, pDriverStrings
, cbBuf
, unicode
);
4619 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4622 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4623 if (*pcbNeeded
<= cbBuf
)
4624 strcpyW((LPWSTR
)strPtr
, DriverName
);
4628 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0, NULL
, NULL
);
4629 if (*pcbNeeded
<= cbBuf
)
4630 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
4633 /* pName for level 1 has a different offset! */
4635 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4639 /* .cVersion and .pName for level > 1 */
4641 di
->cVersion
= env
->driverversion
;
4642 di
->pName
= (LPWSTR
) strPtr
;
4643 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4646 /* Reserve Space for the largest subdir and a Backslash*/
4647 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4648 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4649 /* Should never Fail */
4652 lstrcatW(driverdir
, env
->versionsubdir
);
4653 lstrcatW(driverdir
, backslashW
);
4655 /* dirlen must not include the terminating zero */
4656 dirlen
= (unicode
) ? lstrlenW(driverdir
) * sizeof(WCHAR
) :
4657 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, NULL
, 0, NULL
, NULL
) -1;
4659 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4660 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4661 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4667 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4669 size
= WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, NULL
, 0, NULL
, NULL
);
4672 if (*pcbNeeded
<= cbBuf
) {
4674 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4678 WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, (LPSTR
)strPtr
, size
, NULL
, NULL
);
4680 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4681 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4684 /* .pDriverPath is the Graphics rendering engine.
4685 The full Path is required to avoid a crash in some apps */
4686 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
, unicode
)) {
4688 if (*pcbNeeded
<= cbBuf
)
4689 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
, unicode
);
4691 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4692 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4695 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4696 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
, unicode
)) {
4698 if (*pcbNeeded
<= cbBuf
)
4699 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
, unicode
);
4701 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4702 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4705 /* .pConfigFile is the Driver user Interface */
4706 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
, unicode
)) {
4708 if (*pcbNeeded
<= cbBuf
)
4709 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
, unicode
);
4711 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4712 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4716 RegCloseKey(hkeyDriver
);
4717 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4722 RegCloseKey(hkeyDriver
);
4723 FIXME("level 5: incomplete\n");
4728 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
, unicode
)) {
4730 if (*pcbNeeded
<= cbBuf
)
4731 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
, unicode
);
4733 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4734 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4737 /* .pDependentFiles */
4738 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
, unicode
)) {
4740 if (*pcbNeeded
<= cbBuf
)
4741 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
, unicode
);
4743 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4744 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4746 else if (GetVersion() & 0x80000000) {
4747 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4748 size
= 2 * ((unicode
) ? sizeof(WCHAR
) : 1);
4750 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4752 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4753 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4756 /* .pMonitorName is the optional Language Monitor */
4757 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
, unicode
)) {
4759 if (*pcbNeeded
<= cbBuf
)
4760 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
, unicode
);
4762 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4763 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4766 /* .pDefaultDataType */
4767 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
, unicode
)) {
4769 if(*pcbNeeded
<= cbBuf
)
4770 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
, unicode
);
4772 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4773 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4777 RegCloseKey(hkeyDriver
);
4778 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4782 /* .pszzPreviousNames */
4783 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
, unicode
)) {
4785 if(*pcbNeeded
<= cbBuf
)
4786 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
, unicode
);
4788 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4789 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4793 RegCloseKey(hkeyDriver
);
4794 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4798 /* support is missing, but not important enough for a FIXME */
4799 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4802 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
, unicode
)) {
4804 if(*pcbNeeded
<= cbBuf
)
4805 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
, unicode
);
4807 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4808 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4812 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
, unicode
)) {
4814 if(*pcbNeeded
<= cbBuf
)
4815 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
, unicode
);
4817 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4818 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4821 /* .pszHardwareID */
4822 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
, unicode
)) {
4824 if(*pcbNeeded
<= cbBuf
)
4825 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
, unicode
);
4827 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4828 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4832 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
, unicode
)) {
4834 if(*pcbNeeded
<= cbBuf
)
4835 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
, unicode
);
4837 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4838 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4842 RegCloseKey(hkeyDriver
);
4846 /* support is missing, but not important enough for a FIXME */
4847 TRACE("level 8: incomplete\n");
4849 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4850 RegCloseKey(hkeyDriver
);
4854 /*****************************************************************************
4855 * WINSPOOL_GetPrinterDriver
4857 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPCWSTR pEnvironment
,
4858 DWORD Level
, LPBYTE pDriverInfo
,
4859 DWORD cbBuf
, LPDWORD pcbNeeded
,
4863 WCHAR DriverName
[100];
4864 DWORD ret
, type
, size
, needed
= 0;
4866 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4867 const printenv_t
* env
;
4869 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4870 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4873 if (!(name
= get_opened_printer_name(hPrinter
))) {
4874 SetLastError(ERROR_INVALID_HANDLE
);
4878 if (Level
< 1 || Level
== 7 || Level
> 8) {
4879 SetLastError(ERROR_INVALID_LEVEL
);
4883 env
= validate_envW(pEnvironment
);
4884 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4886 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4888 ERR("Can't create Printers key\n");
4891 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4893 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4894 RegCloseKey(hkeyPrinters
);
4895 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4898 size
= sizeof(DriverName
);
4900 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4901 (LPBYTE
)DriverName
, &size
);
4902 RegCloseKey(hkeyPrinter
);
4903 RegCloseKey(hkeyPrinters
);
4904 if(ret
!= ERROR_SUCCESS
) {
4905 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4909 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
4911 ERR("Can't create Drivers key\n");
4915 size
= di_sizeof
[Level
];
4916 if ((size
<= cbBuf
) && pDriverInfo
)
4917 ptr
= pDriverInfo
+ size
;
4919 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4920 env
, Level
, pDriverInfo
, ptr
,
4921 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4922 &needed
, unicode
)) {
4923 RegCloseKey(hkeyDrivers
);
4927 RegCloseKey(hkeyDrivers
);
4929 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4930 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4931 if(cbBuf
>= needed
) return TRUE
;
4932 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4936 /*****************************************************************************
4937 * GetPrinterDriverA [WINSPOOL.@]
4939 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4940 DWORD Level
, LPBYTE pDriverInfo
,
4941 DWORD cbBuf
, LPDWORD pcbNeeded
)
4944 UNICODE_STRING pEnvW
;
4947 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4948 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
4949 cbBuf
, pcbNeeded
, FALSE
);
4950 RtlFreeUnicodeString(&pEnvW
);
4953 /*****************************************************************************
4954 * GetPrinterDriverW [WINSPOOL.@]
4956 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4957 DWORD Level
, LPBYTE pDriverInfo
,
4958 DWORD cbBuf
, LPDWORD pcbNeeded
)
4960 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
4961 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
4964 /*****************************************************************************
4965 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4967 * Return the PATH for the Printer-Drivers (UNICODE)
4970 * pName [I] Servername (NT only) or NULL (local Computer)
4971 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4972 * Level [I] Structure-Level (must be 1)
4973 * pDriverDirectory [O] PTR to Buffer that receives the Result
4974 * cbBuf [I] Size of Buffer at pDriverDirectory
4975 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4976 * required for pDriverDirectory
4979 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4980 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4981 * if cbBuf is too small
4983 * Native Values returned in pDriverDirectory on Success:
4984 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4985 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4986 *| win9x(Windows 4.0): "%winsysdir%"
4988 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4991 *- Only NULL or "" is supported for pName
4994 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4995 DWORD Level
, LPBYTE pDriverDirectory
,
4996 DWORD cbBuf
, LPDWORD pcbNeeded
)
4998 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4999 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5001 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5004 /* (Level != 1) is ignored in win9x */
5005 SetLastError(ERROR_INVALID_LEVEL
);
5008 if (pcbNeeded
== NULL
) {
5009 /* (pcbNeeded == NULL) is ignored in win9x */
5010 SetLastError(RPC_X_NULL_REF_POINTER
);
5014 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
5015 pDriverDirectory
, cbBuf
, pcbNeeded
);
5020 /*****************************************************************************
5021 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5023 * Return the PATH for the Printer-Drivers (ANSI)
5025 * See GetPrinterDriverDirectoryW.
5028 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5031 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
5032 DWORD Level
, LPBYTE pDriverDirectory
,
5033 DWORD cbBuf
, LPDWORD pcbNeeded
)
5035 UNICODE_STRING nameW
, environmentW
;
5038 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
5039 WCHAR
*driverDirectoryW
= NULL
;
5041 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
5042 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
5044 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
5046 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
5047 else nameW
.Buffer
= NULL
;
5048 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
5049 else environmentW
.Buffer
= NULL
;
5051 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
5052 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
5055 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
5056 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
5058 *pcbNeeded
= needed
;
5059 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
5061 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
5063 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
5065 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
5066 RtlFreeUnicodeString(&environmentW
);
5067 RtlFreeUnicodeString(&nameW
);
5072 /*****************************************************************************
5073 * AddPrinterDriverA [WINSPOOL.@]
5075 * See AddPrinterDriverW.
5078 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5080 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
5081 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5084 /******************************************************************************
5085 * AddPrinterDriverW (WINSPOOL.@)
5087 * Install a Printer Driver
5090 * pName [I] Servername or NULL (local Computer)
5091 * level [I] Level for the supplied DRIVER_INFO_*W struct
5092 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5099 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
5101 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
5102 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
5105 /*****************************************************************************
5106 * AddPrintProcessorA [WINSPOOL.@]
5108 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
5109 LPSTR pPrintProcessorName
)
5111 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
5112 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
5116 /*****************************************************************************
5117 * AddPrintProcessorW [WINSPOOL.@]
5119 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5120 LPWSTR pPrintProcessorName
)
5122 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5123 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5127 /*****************************************************************************
5128 * AddPrintProvidorA [WINSPOOL.@]
5130 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5132 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5136 /*****************************************************************************
5137 * AddPrintProvidorW [WINSPOOL.@]
5139 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5141 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5145 /*****************************************************************************
5146 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5148 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5149 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5151 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5152 pDevModeOutput
, pDevModeInput
);
5156 /*****************************************************************************
5157 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5159 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5160 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5162 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5163 pDevModeOutput
, pDevModeInput
);
5167 /*****************************************************************************
5168 * PrinterProperties [WINSPOOL.@]
5170 * Displays a dialog to set the properties of the printer.
5173 * nonzero on success or zero on failure
5176 * implemented as stub only
5178 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5179 HANDLE hPrinter
/* [in] handle to printer object */
5181 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5182 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5186 /*****************************************************************************
5187 * EnumJobsA [WINSPOOL.@]
5190 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5191 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5194 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5195 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5197 if(pcbNeeded
) *pcbNeeded
= 0;
5198 if(pcReturned
) *pcReturned
= 0;
5203 /*****************************************************************************
5204 * EnumJobsW [WINSPOOL.@]
5207 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5208 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5211 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5212 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5214 if(pcbNeeded
) *pcbNeeded
= 0;
5215 if(pcReturned
) *pcReturned
= 0;
5219 /*****************************************************************************
5220 * WINSPOOL_EnumPrinterDrivers [internal]
5222 * Delivers information about all printer drivers installed on the
5223 * localhost or a given server
5226 * nonzero on success or zero on failure. If the buffer for the returned
5227 * information is too small the function will return an error
5230 * - only implemented for localhost, foreign hosts will return an error
5232 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5233 DWORD Level
, LPBYTE pDriverInfo
,
5234 DWORD cbBuf
, LPDWORD pcbNeeded
,
5235 LPDWORD pcReturned
, BOOL unicode
)
5238 DWORD i
, needed
, number
= 0, size
= 0;
5239 WCHAR DriverNameW
[255];
5241 const printenv_t
* env
;
5243 TRACE("%s,%s,%d,%p,%d,%d\n",
5244 debugstr_w(pName
), debugstr_w(pEnvironment
),
5245 Level
, pDriverInfo
, cbBuf
, unicode
);
5247 /* check for local drivers */
5248 if((pName
) && (pName
[0])) {
5249 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5250 SetLastError(ERROR_ACCESS_DENIED
);
5254 env
= validate_envW(pEnvironment
);
5255 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5257 /* check input parameter */
5258 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5259 SetLastError(ERROR_INVALID_LEVEL
);
5263 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
)) {
5264 SetLastError(RPC_X_NULL_REF_POINTER
);
5268 /* initialize return values */
5270 memset( pDriverInfo
, 0, cbBuf
);
5274 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
5276 ERR("Can't open Drivers key\n");
5280 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
5281 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5282 RegCloseKey(hkeyDrivers
);
5283 ERR("Can't query Drivers key\n");
5286 TRACE("Found %d Drivers\n", number
);
5288 /* get size of single struct
5289 * unicode and ascii structure have the same size
5291 size
= di_sizeof
[Level
];
5293 /* calculate required buffer size */
5294 *pcbNeeded
= size
* number
;
5296 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
5298 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
5299 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
5301 ERR("Can't enum key number %d\n", i
);
5302 RegCloseKey(hkeyDrivers
);
5305 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5307 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
5308 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5309 &needed
, unicode
)) {
5310 RegCloseKey(hkeyDrivers
);
5313 (*pcbNeeded
) += needed
;
5316 RegCloseKey(hkeyDrivers
);
5318 if(cbBuf
< *pcbNeeded
){
5319 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5323 *pcReturned
= number
;
5327 /*****************************************************************************
5328 * EnumPrinterDriversW [WINSPOOL.@]
5330 * see function EnumPrinterDrivers for RETURNS, BUGS
5332 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5333 LPBYTE pDriverInfo
, DWORD cbBuf
,
5334 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5336 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5337 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
5340 /*****************************************************************************
5341 * EnumPrinterDriversA [WINSPOOL.@]
5343 * see function EnumPrinterDrivers for RETURNS, BUGS
5345 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5346 LPBYTE pDriverInfo
, DWORD cbBuf
,
5347 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5349 UNICODE_STRING pNameW
, pEnvironmentW
;
5350 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5352 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5353 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5355 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
5356 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
5358 RtlFreeUnicodeString(&pNameW
);
5359 RtlFreeUnicodeString(&pEnvironmentW
);
5364 /******************************************************************************
5365 * EnumPortsA (WINSPOOL.@)
5370 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5371 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5374 LPBYTE bufferW
= NULL
;
5375 LPWSTR nameW
= NULL
;
5377 DWORD numentries
= 0;
5380 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5381 cbBuf
, pcbNeeded
, pcReturned
);
5383 /* convert servername to unicode */
5385 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5386 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5387 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5389 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5390 needed
= cbBuf
* sizeof(WCHAR
);
5391 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5392 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5394 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5395 if (pcbNeeded
) needed
= *pcbNeeded
;
5396 /* HeapReAlloc return NULL, when bufferW was NULL */
5397 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5398 HeapAlloc(GetProcessHeap(), 0, needed
);
5400 /* Try again with the large Buffer */
5401 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5403 needed
= pcbNeeded
? *pcbNeeded
: 0;
5404 numentries
= pcReturned
? *pcReturned
: 0;
5407 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5408 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5411 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5412 DWORD entrysize
= 0;
5415 LPPORT_INFO_2W pi2w
;
5416 LPPORT_INFO_2A pi2a
;
5419 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5421 /* First pass: calculate the size for all Entries */
5422 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5423 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5425 while (index
< numentries
) {
5427 needed
+= entrysize
; /* PORT_INFO_?A */
5428 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5430 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5431 NULL
, 0, NULL
, NULL
);
5433 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5434 NULL
, 0, NULL
, NULL
);
5435 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5436 NULL
, 0, NULL
, NULL
);
5438 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5439 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5440 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5443 /* check for errors and quit on failure */
5444 if (cbBuf
< needed
) {
5445 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5449 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5450 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5451 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5452 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5453 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5455 /* Second Pass: Fill the User Buffer (if we have one) */
5456 while ((index
< numentries
) && pPorts
) {
5458 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5459 pi2a
->pPortName
= ptr
;
5460 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5461 ptr
, cbBuf
, NULL
, NULL
);
5465 pi2a
->pMonitorName
= ptr
;
5466 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5467 ptr
, cbBuf
, NULL
, NULL
);
5471 pi2a
->pDescription
= ptr
;
5472 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5473 ptr
, cbBuf
, NULL
, NULL
);
5477 pi2a
->fPortType
= pi2w
->fPortType
;
5478 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5481 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5482 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5483 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5488 if (pcbNeeded
) *pcbNeeded
= needed
;
5489 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5491 HeapFree(GetProcessHeap(), 0, nameW
);
5492 HeapFree(GetProcessHeap(), 0, bufferW
);
5494 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5495 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5501 /******************************************************************************
5502 * EnumPortsW (WINSPOOL.@)
5504 * Enumerate available Ports
5507 * name [I] Servername or NULL (local Computer)
5508 * level [I] Structure-Level (1 or 2)
5509 * buffer [O] PTR to Buffer that receives the Result
5510 * bufsize [I] Size of Buffer at buffer
5511 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5512 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5516 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5520 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5523 DWORD numentries
= 0;
5526 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5527 cbBuf
, pcbNeeded
, pcReturned
);
5529 if (pName
&& (pName
[0])) {
5530 FIXME("not implemented for Server %s\n", debugstr_w(pName
));
5531 SetLastError(ERROR_ACCESS_DENIED
);
5535 /* Level is not checked in win9x */
5536 if (!Level
|| (Level
> 2)) {
5537 WARN("level (%d) is ignored in win9x\n", Level
);
5538 SetLastError(ERROR_INVALID_LEVEL
);
5542 SetLastError(RPC_X_NULL_REF_POINTER
);
5546 EnterCriticalSection(&monitor_handles_cs
);
5549 /* Scan all local Ports */
5551 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
5553 /* we calculated the needed buffersize. now do the error-checks */
5554 if (cbBuf
< needed
) {
5555 monitor_unloadall();
5556 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5557 goto emP_cleanup_cs
;
5559 else if (!pPorts
|| !pcReturned
) {
5560 monitor_unloadall();
5561 SetLastError(RPC_X_NULL_REF_POINTER
);
5562 goto emP_cleanup_cs
;
5565 /* Fill the Buffer */
5566 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
5568 monitor_unloadall();
5571 LeaveCriticalSection(&monitor_handles_cs
);
5574 if (pcbNeeded
) *pcbNeeded
= needed
;
5575 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5577 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5578 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5583 /******************************************************************************
5584 * GetDefaultPrinterW (WINSPOOL.@)
5587 * This function must read the value from data 'device' of key
5588 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5590 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5594 WCHAR
*buffer
, *ptr
;
5598 SetLastError(ERROR_INVALID_PARAMETER
);
5602 /* make the buffer big enough for the stuff from the profile/registry,
5603 * the content must fit into the local buffer to compute the correct
5604 * size even if the extern buffer is too small or not given.
5605 * (20 for ,driver,port) */
5607 len
= max(100, (insize
+ 20));
5608 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5610 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5612 SetLastError (ERROR_FILE_NOT_FOUND
);
5616 TRACE("%s\n", debugstr_w(buffer
));
5618 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5620 SetLastError(ERROR_INVALID_NAME
);
5626 *namesize
= strlenW(buffer
) + 1;
5627 if(!name
|| (*namesize
> insize
))
5629 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5633 strcpyW(name
, buffer
);
5636 HeapFree( GetProcessHeap(), 0, buffer
);
5641 /******************************************************************************
5642 * GetDefaultPrinterA (WINSPOOL.@)
5644 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5648 WCHAR
*bufferW
= NULL
;
5652 SetLastError(ERROR_INVALID_PARAMETER
);
5656 if(name
&& *namesize
) {
5658 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5661 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5666 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5670 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5673 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5676 HeapFree( GetProcessHeap(), 0, bufferW
);
5681 /******************************************************************************
5682 * SetDefaultPrinterW (WINSPOOL.204)
5684 * Set the Name of the Default Printer
5687 * pszPrinter [I] Name of the Printer or NULL
5694 * When the Parameter is NULL or points to an Empty String and
5695 * a Default Printer was already present, then this Function changes nothing.
5696 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5697 * the First enumerated local Printer is used.
5700 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5703 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5705 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5709 /******************************************************************************
5710 * SetDefaultPrinterA (WINSPOOL.202)
5712 * See SetDefaultPrinterW.
5715 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5718 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5720 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5725 /******************************************************************************
5726 * SetPrinterDataExA (WINSPOOL.@)
5728 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5729 LPCSTR pValueName
, DWORD Type
,
5730 LPBYTE pData
, DWORD cbData
)
5732 HKEY hkeyPrinter
, hkeySubkey
;
5735 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5736 debugstr_a(pValueName
), Type
, pData
, cbData
);
5738 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5742 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5744 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5745 RegCloseKey(hkeyPrinter
);
5748 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5749 RegCloseKey(hkeySubkey
);
5750 RegCloseKey(hkeyPrinter
);
5754 /******************************************************************************
5755 * SetPrinterDataExW (WINSPOOL.@)
5757 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5758 LPCWSTR pValueName
, DWORD Type
,
5759 LPBYTE pData
, DWORD cbData
)
5761 HKEY hkeyPrinter
, hkeySubkey
;
5764 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5765 debugstr_w(pValueName
), Type
, pData
, cbData
);
5767 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5771 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5773 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5774 RegCloseKey(hkeyPrinter
);
5777 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5778 RegCloseKey(hkeySubkey
);
5779 RegCloseKey(hkeyPrinter
);
5783 /******************************************************************************
5784 * SetPrinterDataA (WINSPOOL.@)
5786 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5787 LPBYTE pData
, DWORD cbData
)
5789 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5793 /******************************************************************************
5794 * SetPrinterDataW (WINSPOOL.@)
5796 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5797 LPBYTE pData
, DWORD cbData
)
5799 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5803 /******************************************************************************
5804 * GetPrinterDataExA (WINSPOOL.@)
5806 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5807 LPCSTR pValueName
, LPDWORD pType
,
5808 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5810 HKEY hkeyPrinter
, hkeySubkey
;
5813 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5814 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
5817 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5821 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5823 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
5824 RegCloseKey(hkeyPrinter
);
5828 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5829 RegCloseKey(hkeySubkey
);
5830 RegCloseKey(hkeyPrinter
);
5834 /******************************************************************************
5835 * GetPrinterDataExW (WINSPOOL.@)
5837 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5838 LPCWSTR pValueName
, LPDWORD pType
,
5839 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5841 HKEY hkeyPrinter
, hkeySubkey
;
5844 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5845 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
5848 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5852 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5854 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
5855 RegCloseKey(hkeyPrinter
);
5859 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5860 RegCloseKey(hkeySubkey
);
5861 RegCloseKey(hkeyPrinter
);
5865 /******************************************************************************
5866 * GetPrinterDataA (WINSPOOL.@)
5868 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5869 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5871 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5872 pData
, nSize
, pcbNeeded
);
5875 /******************************************************************************
5876 * GetPrinterDataW (WINSPOOL.@)
5878 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5879 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5881 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5882 pData
, nSize
, pcbNeeded
);
5885 /*******************************************************************************
5886 * EnumPrinterDataExW [WINSPOOL.@]
5888 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5889 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5890 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5892 HKEY hkPrinter
, hkSubKey
;
5893 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5894 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5899 PPRINTER_ENUM_VALUESW ppev
;
5901 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5903 if (pKeyName
== NULL
|| *pKeyName
== 0)
5904 return ERROR_INVALID_PARAMETER
;
5906 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5907 if (ret
!= ERROR_SUCCESS
)
5909 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5914 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5915 if (ret
!= ERROR_SUCCESS
)
5917 r
= RegCloseKey (hkPrinter
);
5918 if (r
!= ERROR_SUCCESS
)
5919 WARN ("RegCloseKey returned %i\n", r
);
5920 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5921 debugstr_w (pKeyName
), ret
);
5925 ret
= RegCloseKey (hkPrinter
);
5926 if (ret
!= ERROR_SUCCESS
)
5928 ERR ("RegCloseKey returned %i\n", ret
);
5929 r
= RegCloseKey (hkSubKey
);
5930 if (r
!= ERROR_SUCCESS
)
5931 WARN ("RegCloseKey returned %i\n", r
);
5935 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5936 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5937 if (ret
!= ERROR_SUCCESS
)
5939 r
= RegCloseKey (hkSubKey
);
5940 if (r
!= ERROR_SUCCESS
)
5941 WARN ("RegCloseKey returned %i\n", r
);
5942 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5946 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5947 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5949 if (cValues
== 0) /* empty key */
5951 r
= RegCloseKey (hkSubKey
);
5952 if (r
!= ERROR_SUCCESS
)
5953 WARN ("RegCloseKey returned %i\n", r
);
5954 *pcbEnumValues
= *pnEnumValues
= 0;
5955 return ERROR_SUCCESS
;
5958 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5960 hHeap
= GetProcessHeap ();
5963 ERR ("GetProcessHeap failed\n");
5964 r
= RegCloseKey (hkSubKey
);
5965 if (r
!= ERROR_SUCCESS
)
5966 WARN ("RegCloseKey returned %i\n", r
);
5967 return ERROR_OUTOFMEMORY
;
5970 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5971 if (lpValueName
== NULL
)
5973 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5974 r
= RegCloseKey (hkSubKey
);
5975 if (r
!= ERROR_SUCCESS
)
5976 WARN ("RegCloseKey returned %i\n", r
);
5977 return ERROR_OUTOFMEMORY
;
5980 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5981 if (lpValue
== NULL
)
5983 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5984 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5985 WARN ("HeapFree failed with code %i\n", GetLastError ());
5986 r
= RegCloseKey (hkSubKey
);
5987 if (r
!= ERROR_SUCCESS
)
5988 WARN ("RegCloseKey returned %i\n", r
);
5989 return ERROR_OUTOFMEMORY
;
5992 TRACE ("pass 1: calculating buffer required for all names and values\n");
5994 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5996 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5998 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6000 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6001 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6002 NULL
, NULL
, lpValue
, &cbValueLen
);
6003 if (ret
!= ERROR_SUCCESS
)
6005 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6006 WARN ("HeapFree failed with code %i\n", GetLastError ());
6007 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6008 WARN ("HeapFree failed with code %i\n", GetLastError ());
6009 r
= RegCloseKey (hkSubKey
);
6010 if (r
!= ERROR_SUCCESS
)
6011 WARN ("RegCloseKey returned %i\n", r
);
6012 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6016 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6017 debugstr_w (lpValueName
), dwIndex
,
6018 cbValueNameLen
+ 1, cbValueLen
);
6020 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6021 cbBufSize
+= cbValueLen
;
6024 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
6026 *pcbEnumValues
= cbBufSize
;
6027 *pnEnumValues
= cValues
;
6029 if (cbEnumValues
< cbBufSize
) /* buffer too small */
6031 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6032 WARN ("HeapFree failed with code %i\n", GetLastError ());
6033 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6034 WARN ("HeapFree failed with code %i\n", GetLastError ());
6035 r
= RegCloseKey (hkSubKey
);
6036 if (r
!= ERROR_SUCCESS
)
6037 WARN ("RegCloseKey returned %i\n", r
);
6038 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
6039 return ERROR_MORE_DATA
;
6042 TRACE ("pass 2: copying all names and values to buffer\n");
6044 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
6045 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
6047 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
6049 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
6050 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
6051 NULL
, &dwType
, lpValue
, &cbValueLen
);
6052 if (ret
!= ERROR_SUCCESS
)
6054 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6055 WARN ("HeapFree failed with code %i\n", GetLastError ());
6056 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6057 WARN ("HeapFree failed with code %i\n", GetLastError ());
6058 r
= RegCloseKey (hkSubKey
);
6059 if (r
!= ERROR_SUCCESS
)
6060 WARN ("RegCloseKey returned %i\n", r
);
6061 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
6065 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
6066 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
6067 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
6068 pEnumValues
+= cbValueNameLen
;
6070 /* return # of *bytes* (including trailing \0), not # of chars */
6071 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
6073 ppev
[dwIndex
].dwType
= dwType
;
6075 memcpy (pEnumValues
, lpValue
, cbValueLen
);
6076 ppev
[dwIndex
].pData
= pEnumValues
;
6077 pEnumValues
+= cbValueLen
;
6079 ppev
[dwIndex
].cbData
= cbValueLen
;
6081 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6082 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
6085 if (HeapFree (hHeap
, 0, lpValue
) == 0)
6087 ret
= GetLastError ();
6088 ERR ("HeapFree failed with code %i\n", ret
);
6089 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6090 WARN ("HeapFree failed with code %i\n", GetLastError ());
6091 r
= RegCloseKey (hkSubKey
);
6092 if (r
!= ERROR_SUCCESS
)
6093 WARN ("RegCloseKey returned %i\n", r
);
6097 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
6099 ret
= GetLastError ();
6100 ERR ("HeapFree failed with code %i\n", ret
);
6101 r
= RegCloseKey (hkSubKey
);
6102 if (r
!= ERROR_SUCCESS
)
6103 WARN ("RegCloseKey returned %i\n", r
);
6107 ret
= RegCloseKey (hkSubKey
);
6108 if (ret
!= ERROR_SUCCESS
)
6110 ERR ("RegCloseKey returned %i\n", ret
);
6114 return ERROR_SUCCESS
;
6117 /*******************************************************************************
6118 * EnumPrinterDataExA [WINSPOOL.@]
6120 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6121 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6122 * what Windows 2000 SP1 does.
6125 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6126 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6127 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6131 DWORD ret
, dwIndex
, dwBufSize
;
6135 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6137 if (pKeyName
== NULL
|| *pKeyName
== 0)
6138 return ERROR_INVALID_PARAMETER
;
6140 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6143 ret
= GetLastError ();
6144 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6148 hHeap
= GetProcessHeap ();
6151 ERR ("GetProcessHeap failed\n");
6152 return ERROR_OUTOFMEMORY
;
6155 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6156 if (pKeyNameW
== NULL
)
6158 ERR ("Failed to allocate %i bytes from process heap\n",
6159 (LONG
)(len
* sizeof (WCHAR
)));
6160 return ERROR_OUTOFMEMORY
;
6163 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6165 ret
= GetLastError ();
6166 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6167 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6168 WARN ("HeapFree failed with code %i\n", GetLastError ());
6172 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6173 pcbEnumValues
, pnEnumValues
);
6174 if (ret
!= ERROR_SUCCESS
)
6176 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6177 WARN ("HeapFree failed with code %i\n", GetLastError ());
6178 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6182 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6184 ret
= GetLastError ();
6185 ERR ("HeapFree failed with code %i\n", ret
);
6189 if (*pnEnumValues
== 0) /* empty key */
6190 return ERROR_SUCCESS
;
6193 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6195 PPRINTER_ENUM_VALUESW ppev
=
6196 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6198 if (dwBufSize
< ppev
->cbValueName
)
6199 dwBufSize
= ppev
->cbValueName
;
6201 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6202 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6203 dwBufSize
= ppev
->cbData
;
6206 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6208 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6209 if (pBuffer
== NULL
)
6211 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6212 return ERROR_OUTOFMEMORY
;
6215 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6217 PPRINTER_ENUM_VALUESW ppev
=
6218 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6220 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6221 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6225 ret
= GetLastError ();
6226 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6227 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6228 WARN ("HeapFree failed with code %i\n", GetLastError ());
6232 memcpy (ppev
->pValueName
, pBuffer
, len
);
6234 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6236 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6237 ppev
->dwType
!= REG_MULTI_SZ
)
6240 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6241 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6244 ret
= GetLastError ();
6245 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6246 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6247 WARN ("HeapFree failed with code %i\n", GetLastError ());
6251 memcpy (ppev
->pData
, pBuffer
, len
);
6253 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6254 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6257 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6259 ret
= GetLastError ();
6260 ERR ("HeapFree failed with code %i\n", ret
);
6264 return ERROR_SUCCESS
;
6267 /******************************************************************************
6268 * AbortPrinter (WINSPOOL.@)
6270 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6272 FIXME("(%p), stub!\n", hPrinter
);
6276 /******************************************************************************
6277 * AddPortA (WINSPOOL.@)
6282 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6284 LPWSTR nameW
= NULL
;
6285 LPWSTR monitorW
= NULL
;
6289 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6292 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6293 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6294 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6298 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6299 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6300 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6302 res
= AddPortW(nameW
, hWnd
, monitorW
);
6303 HeapFree(GetProcessHeap(), 0, nameW
);
6304 HeapFree(GetProcessHeap(), 0, monitorW
);
6308 /******************************************************************************
6309 * AddPortW (WINSPOOL.@)
6311 * Add a Port for a specific Monitor
6314 * pName [I] Servername or NULL (local Computer)
6315 * hWnd [I] Handle to parent Window for the Dialog-Box
6316 * pMonitorName [I] Name of the Monitor that manage the Port
6323 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6329 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6331 if (pName
&& pName
[0]) {
6332 SetLastError(ERROR_INVALID_PARAMETER
);
6336 if (!pMonitorName
) {
6337 SetLastError(RPC_X_NULL_REF_POINTER
);
6341 /* an empty Monitorname is Invalid */
6342 if (!pMonitorName
[0]) {
6343 SetLastError(ERROR_NOT_SUPPORTED
);
6347 pm
= monitor_load(pMonitorName
, NULL
);
6348 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
6349 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
6350 TRACE("got %d with %u\n", res
, GetLastError());
6355 pui
= monitor_loadui(pm
);
6356 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
6357 TRACE("use %p: %s\n", pui
, debugstr_w(pui
->dllname
));
6358 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
6359 TRACE("got %d with %u\n", res
, GetLastError());
6364 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName
),
6365 pm
, debugstr_w(pm
? pm
->dllname
: NULL
), pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
6367 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6368 SetLastError(ERROR_NOT_SUPPORTED
);
6371 monitor_unload(pui
);
6374 TRACE("returning %d with %u\n", res
, GetLastError());
6378 /******************************************************************************
6379 * AddPortExA (WINSPOOL.@)
6384 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6387 PORT_INFO_2A
* pi2A
;
6388 LPWSTR nameW
= NULL
;
6389 LPWSTR monitorW
= NULL
;
6393 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6395 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6396 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6398 if ((level
< 1) || (level
> 2)) {
6399 SetLastError(ERROR_INVALID_LEVEL
);
6404 SetLastError(ERROR_INVALID_PARAMETER
);
6409 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6410 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6411 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6415 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6416 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6417 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6420 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6422 if (pi2A
->pPortName
) {
6423 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6424 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6425 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6429 if (pi2A
->pMonitorName
) {
6430 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6431 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6432 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6435 if (pi2A
->pDescription
) {
6436 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6437 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6438 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6440 pi2W
.fPortType
= pi2A
->fPortType
;
6441 pi2W
.Reserved
= pi2A
->Reserved
;
6444 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6446 HeapFree(GetProcessHeap(), 0, nameW
);
6447 HeapFree(GetProcessHeap(), 0, monitorW
);
6448 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6449 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6450 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6455 /******************************************************************************
6456 * AddPortExW (WINSPOOL.@)
6458 * Add a Port for a specific Monitor, without presenting a user interface
6461 * pName [I] Servername or NULL (local Computer)
6462 * level [I] Structure-Level (1 or 2) for pBuffer
6463 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6464 * pMonitorName [I] Name of the Monitor that manage the Port
6471 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6477 pi2
= (PORT_INFO_2W
*) pBuffer
;
6479 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6480 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6481 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6482 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6485 if ((level
< 1) || (level
> 2)) {
6486 SetLastError(ERROR_INVALID_LEVEL
);
6490 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6491 SetLastError(ERROR_INVALID_PARAMETER
);
6495 /* load the Monitor */
6496 pm
= monitor_load(pMonitorName
, NULL
);
6498 SetLastError(ERROR_INVALID_PARAMETER
);
6502 if (pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
6503 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6504 TRACE("got %u with %u\n", res
, GetLastError());
6508 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName
), pm
->monitor
);
6514 /******************************************************************************
6515 * AddPrinterConnectionA (WINSPOOL.@)
6517 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6519 FIXME("%s\n", debugstr_a(pName
));
6523 /******************************************************************************
6524 * AddPrinterConnectionW (WINSPOOL.@)
6526 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6528 FIXME("%s\n", debugstr_w(pName
));
6532 /******************************************************************************
6533 * AddPrinterDriverExW (WINSPOOL.@)
6535 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6538 * pName [I] Servername or NULL (local Computer)
6539 * level [I] Level for the supplied DRIVER_INFO_*W struct
6540 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6541 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6548 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6550 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6552 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6554 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6555 SetLastError(ERROR_INVALID_LEVEL
);
6560 SetLastError(ERROR_INVALID_PARAMETER
);
6564 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6567 /******************************************************************************
6568 * AddPrinterDriverExA (WINSPOOL.@)
6570 * See AddPrinterDriverExW.
6573 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6575 DRIVER_INFO_8A
*diA
;
6577 LPWSTR nameW
= NULL
;
6582 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6584 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6585 ZeroMemory(&diW
, sizeof(diW
));
6587 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6588 SetLastError(ERROR_INVALID_LEVEL
);
6593 SetLastError(ERROR_INVALID_PARAMETER
);
6597 /* convert servername to unicode */
6599 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6600 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6601 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6605 diW
.cVersion
= diA
->cVersion
;
6608 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6609 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6610 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6613 if (diA
->pEnvironment
) {
6614 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6615 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6616 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6619 if (diA
->pDriverPath
) {
6620 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6621 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6622 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6625 if (diA
->pDataFile
) {
6626 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6627 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6628 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6631 if (diA
->pConfigFile
) {
6632 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6633 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6634 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6637 if ((Level
> 2) && diA
->pDependentFiles
) {
6638 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6639 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6640 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6641 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6644 if ((Level
> 2) && diA
->pMonitorName
) {
6645 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6646 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6647 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6650 if ((Level
> 3) && diA
->pDefaultDataType
) {
6651 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6652 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6653 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6656 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6657 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6658 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6659 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6660 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6663 if ((Level
> 5) && diA
->pszMfgName
) {
6664 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6665 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6666 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6669 if ((Level
> 5) && diA
->pszOEMUrl
) {
6670 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6671 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6672 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6675 if ((Level
> 5) && diA
->pszHardwareID
) {
6676 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6677 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6678 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6681 if ((Level
> 5) && diA
->pszProvider
) {
6682 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6683 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6684 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6688 FIXME("level %u is incomplete\n", Level
);
6691 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6692 TRACE("got %u with %u\n", res
, GetLastError());
6693 HeapFree(GetProcessHeap(), 0, nameW
);
6694 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6695 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6696 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6697 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6698 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6699 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6700 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6701 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6702 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6703 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6704 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6705 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6706 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6708 TRACE("=> %u with %u\n", res
, GetLastError());
6712 /******************************************************************************
6713 * ConfigurePortA (WINSPOOL.@)
6715 * See ConfigurePortW.
6718 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6720 LPWSTR nameW
= NULL
;
6721 LPWSTR portW
= NULL
;
6725 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6727 /* convert servername to unicode */
6729 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6730 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6731 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6734 /* convert portname to unicode */
6736 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6737 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6738 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6741 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6742 HeapFree(GetProcessHeap(), 0, nameW
);
6743 HeapFree(GetProcessHeap(), 0, portW
);
6747 /******************************************************************************
6748 * ConfigurePortW (WINSPOOL.@)
6750 * Display the Configuration-Dialog for a specific Port
6753 * pName [I] Servername or NULL (local Computer)
6754 * hWnd [I] Handle to parent Window for the Dialog-Box
6755 * pPortName [I] Name of the Port, that should be configured
6762 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6768 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6770 if (pName
&& pName
[0]) {
6771 SetLastError(ERROR_INVALID_PARAMETER
);
6776 SetLastError(RPC_X_NULL_REF_POINTER
);
6780 /* an empty Portname is Invalid, but can popup a Dialog */
6781 if (!pPortName
[0]) {
6782 SetLastError(ERROR_NOT_SUPPORTED
);
6786 pm
= monitor_load_by_port(pPortName
);
6787 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
6788 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
6789 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
6790 TRACE("got %d with %u\n", res
, GetLastError());
6794 pui
= monitor_loadui(pm
);
6795 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
6796 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
6797 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
6798 TRACE("got %d with %u\n", res
, GetLastError());
6802 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
6803 pm
, debugstr_w(pm
? pm
->dllname
: NULL
), pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
6805 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6806 SetLastError(ERROR_NOT_SUPPORTED
);
6809 monitor_unload(pui
);
6813 TRACE("returning %d with %u\n", res
, GetLastError());
6817 /******************************************************************************
6818 * ConnectToPrinterDlg (WINSPOOL.@)
6820 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6822 FIXME("%p %x\n", hWnd
, Flags
);
6826 /******************************************************************************
6827 * DeletePrinterConnectionA (WINSPOOL.@)
6829 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6831 FIXME("%s\n", debugstr_a(pName
));
6835 /******************************************************************************
6836 * DeletePrinterConnectionW (WINSPOOL.@)
6838 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6840 FIXME("%s\n", debugstr_w(pName
));
6844 /******************************************************************************
6845 * DeletePrinterDriverExW (WINSPOOL.@)
6847 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6848 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6853 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6854 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6856 if(pName
&& pName
[0])
6858 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6859 SetLastError(ERROR_INVALID_PARAMETER
);
6865 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6866 SetLastError(ERROR_INVALID_PARAMETER
);
6870 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
6874 ERR("Can't open drivers key\n");
6878 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6881 RegCloseKey(hkey_drivers
);
6886 /******************************************************************************
6887 * DeletePrinterDriverExA (WINSPOOL.@)
6889 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6890 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6892 UNICODE_STRING NameW
, EnvW
, DriverW
;
6895 asciitounicode(&NameW
, pName
);
6896 asciitounicode(&EnvW
, pEnvironment
);
6897 asciitounicode(&DriverW
, pDriverName
);
6899 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6901 RtlFreeUnicodeString(&DriverW
);
6902 RtlFreeUnicodeString(&EnvW
);
6903 RtlFreeUnicodeString(&NameW
);
6908 /******************************************************************************
6909 * DeletePrinterDataExW (WINSPOOL.@)
6911 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6914 FIXME("%p %s %s\n", hPrinter
,
6915 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6916 return ERROR_INVALID_PARAMETER
;
6919 /******************************************************************************
6920 * DeletePrinterDataExA (WINSPOOL.@)
6922 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6925 FIXME("%p %s %s\n", hPrinter
,
6926 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6927 return ERROR_INVALID_PARAMETER
;
6930 /******************************************************************************
6931 * DeletePrintProcessorA (WINSPOOL.@)
6933 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6935 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6936 debugstr_a(pPrintProcessorName
));
6940 /******************************************************************************
6941 * DeletePrintProcessorW (WINSPOOL.@)
6943 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6945 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6946 debugstr_w(pPrintProcessorName
));
6950 /******************************************************************************
6951 * DeletePrintProvidorA (WINSPOOL.@)
6953 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6955 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6956 debugstr_a(pPrintProviderName
));
6960 /******************************************************************************
6961 * DeletePrintProvidorW (WINSPOOL.@)
6963 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6965 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6966 debugstr_w(pPrintProviderName
));
6970 /******************************************************************************
6971 * EnumFormsA (WINSPOOL.@)
6973 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6974 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6976 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6977 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6981 /******************************************************************************
6982 * EnumFormsW (WINSPOOL.@)
6984 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6985 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6987 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6988 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6992 /*****************************************************************************
6993 * EnumMonitorsA [WINSPOOL.@]
6995 * See EnumMonitorsW.
6998 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6999 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7002 LPBYTE bufferW
= NULL
;
7003 LPWSTR nameW
= NULL
;
7005 DWORD numentries
= 0;
7008 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
7009 cbBuf
, pcbNeeded
, pcReturned
);
7011 /* convert servername to unicode */
7013 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7014 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7015 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7017 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7018 needed
= cbBuf
* sizeof(WCHAR
);
7019 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7020 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7022 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7023 if (pcbNeeded
) needed
= *pcbNeeded
;
7024 /* HeapReAlloc return NULL, when bufferW was NULL */
7025 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7026 HeapAlloc(GetProcessHeap(), 0, needed
);
7028 /* Try again with the large Buffer */
7029 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7031 numentries
= pcReturned
? *pcReturned
: 0;
7034 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7035 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7038 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7039 DWORD entrysize
= 0;
7042 LPMONITOR_INFO_2W mi2w
;
7043 LPMONITOR_INFO_2A mi2a
;
7045 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7046 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
7048 /* First pass: calculate the size for all Entries */
7049 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7050 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7052 while (index
< numentries
) {
7054 needed
+= entrysize
; /* MONITOR_INFO_?A */
7055 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
7057 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7058 NULL
, 0, NULL
, NULL
);
7060 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7061 NULL
, 0, NULL
, NULL
);
7062 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7063 NULL
, 0, NULL
, NULL
);
7065 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7066 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7067 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7070 /* check for errors and quit on failure */
7071 if (cbBuf
< needed
) {
7072 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7076 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
7077 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
7078 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7079 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7080 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7082 /* Second Pass: Fill the User Buffer (if we have one) */
7083 while ((index
< numentries
) && pMonitors
) {
7085 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7087 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7088 ptr
, cbBuf
, NULL
, NULL
);
7092 mi2a
->pEnvironment
= ptr
;
7093 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7094 ptr
, cbBuf
, NULL
, NULL
);
7098 mi2a
->pDLLName
= ptr
;
7099 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7100 ptr
, cbBuf
, NULL
, NULL
);
7104 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7105 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7106 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7110 if (pcbNeeded
) *pcbNeeded
= needed
;
7111 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7113 HeapFree(GetProcessHeap(), 0, nameW
);
7114 HeapFree(GetProcessHeap(), 0, bufferW
);
7116 TRACE("returning %d with %d (%d byte for %d entries)\n",
7117 (res
), GetLastError(), needed
, numentries
);
7123 /*****************************************************************************
7124 * EnumMonitorsW [WINSPOOL.@]
7126 * Enumerate available Port-Monitors
7129 * pName [I] Servername or NULL (local Computer)
7130 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7131 * pMonitors [O] PTR to Buffer that receives the Result
7132 * cbBuf [I] Size of Buffer at pMonitors
7133 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7134 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7138 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7141 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7142 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7145 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7146 cbBuf
, pcbNeeded
, pcReturned
);
7148 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7150 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
7151 SetLastError(RPC_X_NULL_REF_POINTER
);
7155 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
7158 /******************************************************************************
7159 * SpoolerInit (WINSPOOL.@)
7161 * Initialize the Spooler
7168 * The function fails on windows, when the spooler service is not running
7171 BOOL WINAPI
SpoolerInit(void)
7174 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7178 /******************************************************************************
7179 * XcvDataW (WINSPOOL.@)
7181 * Execute commands in the Printmonitor DLL
7184 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7185 * pszDataName [i] Name of the command to execute
7186 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7187 * cbInputData [i] Size in Bytes of Buffer at pInputData
7188 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7189 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7190 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7191 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7198 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7199 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7201 * Minimal List of commands, that a Printmonitor DLL should support:
7203 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7204 *| "AddPort" : Add a Port
7205 *| "DeletePort": Delete a Port
7207 * Many Printmonitors support additional commands. Examples for localspl.dll:
7208 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7209 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7212 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7213 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7214 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7216 opened_printer_t
*printer
;
7218 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7219 pInputData
, cbInputData
, pOutputData
,
7220 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7222 printer
= get_opened_printer(hXcv
);
7223 if (!printer
|| (!printer
->hXcv
)) {
7224 SetLastError(ERROR_INVALID_HANDLE
);
7228 if (!pcbOutputNeeded
) {
7229 SetLastError(ERROR_INVALID_PARAMETER
);
7233 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7234 SetLastError(RPC_X_NULL_REF_POINTER
);
7238 *pcbOutputNeeded
= 0;
7240 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
7241 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
7246 /*****************************************************************************
7247 * EnumPrinterDataA [WINSPOOL.@]
7250 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7251 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7252 DWORD cbData
, LPDWORD pcbData
)
7254 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7255 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7256 return ERROR_NO_MORE_ITEMS
;
7259 /*****************************************************************************
7260 * EnumPrinterDataW [WINSPOOL.@]
7263 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7264 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7265 DWORD cbData
, LPDWORD pcbData
)
7267 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7268 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7269 return ERROR_NO_MORE_ITEMS
;
7272 /*****************************************************************************
7273 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7276 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7277 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7278 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7280 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7281 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7282 pcbNeeded
, pcReturned
);
7286 /*****************************************************************************
7287 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7290 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7291 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7292 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7294 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7295 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7296 pcbNeeded
, pcReturned
);
7300 /*****************************************************************************
7301 * EnumPrintProcessorsA [WINSPOOL.@]
7304 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7305 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7307 FIXME("Stub: %s %s %d %p %d %p %p\n", pName
, pEnvironment
, Level
,
7308 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
7312 /*****************************************************************************
7313 * EnumPrintProcessorsW [WINSPOOL.@]
7316 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7317 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7319 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7320 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
7321 cbBuf
, pcbNeeded
, pcbReturned
);
7325 /*****************************************************************************
7326 * ExtDeviceMode [WINSPOOL.@]
7329 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7330 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7333 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7334 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7335 debugstr_a(pProfile
), fMode
);
7339 /*****************************************************************************
7340 * FindClosePrinterChangeNotification [WINSPOOL.@]
7343 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7345 FIXME("Stub: %p\n", hChange
);
7349 /*****************************************************************************
7350 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7353 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7354 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7356 FIXME("Stub: %p %x %x %p\n",
7357 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7358 return INVALID_HANDLE_VALUE
;
7361 /*****************************************************************************
7362 * FindNextPrinterChangeNotification [WINSPOOL.@]
7365 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7366 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7368 FIXME("Stub: %p %p %p %p\n",
7369 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7373 /*****************************************************************************
7374 * FreePrinterNotifyInfo [WINSPOOL.@]
7377 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7379 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7383 /*****************************************************************************
7386 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7387 * ansi depending on the unicode parameter.
7389 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7399 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7402 memcpy(ptr
, str
, *size
);
7409 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7412 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7419 /*****************************************************************************
7422 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7423 LPDWORD pcbNeeded
, BOOL unicode
)
7425 DWORD size
, left
= cbBuf
;
7426 BOOL space
= (cbBuf
> 0);
7433 ji1
->JobId
= job
->job_id
;
7436 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7437 if(space
&& size
<= left
)
7439 ji1
->pDocument
= (LPWSTR
)ptr
;
7450 /*****************************************************************************
7453 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7454 LPDWORD pcbNeeded
, BOOL unicode
)
7456 DWORD size
, left
= cbBuf
;
7457 BOOL space
= (cbBuf
> 0);
7464 ji2
->JobId
= job
->job_id
;
7467 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7468 if(space
&& size
<= left
)
7470 ji2
->pDocument
= (LPWSTR
)ptr
;
7481 /*****************************************************************************
7484 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7485 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7488 DWORD needed
= 0, size
;
7492 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7494 EnterCriticalSection(&printer_handles_cs
);
7495 job
= get_job(hPrinter
, JobId
);
7502 size
= sizeof(JOB_INFO_1W
);
7507 memset(pJob
, 0, size
);
7511 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7516 size
= sizeof(JOB_INFO_2W
);
7521 memset(pJob
, 0, size
);
7525 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7530 size
= sizeof(JOB_INFO_3
);
7534 memset(pJob
, 0, size
);
7543 SetLastError(ERROR_INVALID_LEVEL
);
7547 *pcbNeeded
= needed
;
7549 LeaveCriticalSection(&printer_handles_cs
);
7553 /*****************************************************************************
7554 * GetJobA [WINSPOOL.@]
7557 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7558 DWORD cbBuf
, LPDWORD pcbNeeded
)
7560 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7563 /*****************************************************************************
7564 * GetJobW [WINSPOOL.@]
7567 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7568 DWORD cbBuf
, LPDWORD pcbNeeded
)
7570 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7573 /*****************************************************************************
7576 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7578 char *unixname
, *queue
, *cmd
;
7579 char fmt
[] = "lpr -P%s %s";
7583 if(!(unixname
= wine_get_unix_file_name(filename
)))
7586 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7587 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7588 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7590 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7591 sprintf(cmd
, fmt
, queue
, unixname
);
7593 TRACE("printing with: %s\n", cmd
);
7596 HeapFree(GetProcessHeap(), 0, cmd
);
7597 HeapFree(GetProcessHeap(), 0, queue
);
7598 HeapFree(GetProcessHeap(), 0, unixname
);
7602 /*****************************************************************************
7605 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7607 #ifdef SONAME_LIBCUPS
7610 char *unixname
, *queue
, *unix_doc_title
;
7614 if(!(unixname
= wine_get_unix_file_name(filename
)))
7617 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7618 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7619 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7621 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7622 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
7623 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
7625 TRACE("printing via cups\n");
7626 ret
= pcupsPrintFile(queue
, unixname
, unix_doc_title
, 0, NULL
);
7627 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
7628 HeapFree(GetProcessHeap(), 0, queue
);
7629 HeapFree(GetProcessHeap(), 0, unixname
);
7635 return schedule_lpr(printer_name
, filename
);
7639 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7646 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7650 if(HIWORD(wparam
) == BN_CLICKED
)
7652 if(LOWORD(wparam
) == IDOK
)
7655 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7658 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7659 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7661 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7663 WCHAR caption
[200], message
[200];
7666 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7667 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7668 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7669 if(mb_ret
== IDCANCEL
)
7671 HeapFree(GetProcessHeap(), 0, filename
);
7675 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7676 if(hf
== INVALID_HANDLE_VALUE
)
7678 WCHAR caption
[200], message
[200];
7680 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7681 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7682 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7683 HeapFree(GetProcessHeap(), 0, filename
);
7687 DeleteFileW(filename
);
7688 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7690 EndDialog(hwnd
, IDOK
);
7693 if(LOWORD(wparam
) == IDCANCEL
)
7695 EndDialog(hwnd
, IDCANCEL
);
7704 /*****************************************************************************
7707 static BOOL
get_filename(LPWSTR
*filename
)
7709 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7710 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7713 /*****************************************************************************
7716 static BOOL
schedule_file(LPCWSTR filename
)
7718 LPWSTR output
= NULL
;
7720 if(get_filename(&output
))
7723 TRACE("copy to %s\n", debugstr_w(output
));
7724 r
= CopyFileW(filename
, output
, FALSE
);
7725 HeapFree(GetProcessHeap(), 0, output
);
7731 /*****************************************************************************
7734 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7737 char *unixname
, *cmdA
;
7739 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7743 if(!(unixname
= wine_get_unix_file_name(filename
)))
7746 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7747 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7748 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7750 TRACE("printing with: %s\n", cmdA
);
7752 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7757 ERR("pipe() failed!\n");
7767 /* reset signals that we previously set to SIG_IGN */
7768 signal(SIGPIPE
, SIG_DFL
);
7769 signal(SIGCHLD
, SIG_DFL
);
7771 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
7775 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7776 write(fds
[1], buf
, no_read
);
7781 if(file_fd
!= -1) close(file_fd
);
7782 if(fds
[0] != -1) close(fds
[0]);
7783 if(fds
[1] != -1) close(fds
[1]);
7785 HeapFree(GetProcessHeap(), 0, cmdA
);
7786 HeapFree(GetProcessHeap(), 0, unixname
);
7793 /*****************************************************************************
7796 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7798 int in_fd
, out_fd
, no_read
;
7801 char *unixname
, *outputA
;
7804 if(!(unixname
= wine_get_unix_file_name(filename
)))
7807 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7808 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7809 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7811 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7812 in_fd
= open(unixname
, O_RDONLY
);
7813 if(out_fd
== -1 || in_fd
== -1)
7816 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7817 write(out_fd
, buf
, no_read
);
7821 if(in_fd
!= -1) close(in_fd
);
7822 if(out_fd
!= -1) close(out_fd
);
7823 HeapFree(GetProcessHeap(), 0, outputA
);
7824 HeapFree(GetProcessHeap(), 0, unixname
);
7828 /*****************************************************************************
7829 * ScheduleJob [WINSPOOL.@]
7832 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7834 opened_printer_t
*printer
;
7836 struct list
*cursor
, *cursor2
;
7838 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7839 EnterCriticalSection(&printer_handles_cs
);
7840 printer
= get_opened_printer(hPrinter
);
7844 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7846 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7849 if(job
->job_id
!= dwJobID
) continue;
7851 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7852 if(hf
!= INVALID_HANDLE_VALUE
)
7854 PRINTER_INFO_5W
*pi5
;
7858 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7859 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7861 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7862 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7863 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7864 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7865 debugstr_w(pi5
->pPortName
));
7869 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7870 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7872 DWORD type
, count
= sizeof(output
);
7873 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
7876 if(output
[0] == '|')
7878 ret
= schedule_pipe(output
+ 1, job
->filename
);
7882 ret
= schedule_unixfile(output
, job
->filename
);
7884 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
7886 ret
= schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
7888 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
7890 ret
= schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7892 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
7894 ret
= schedule_file(job
->filename
);
7898 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
7900 HeapFree(GetProcessHeap(), 0, pi5
);
7902 DeleteFileW(job
->filename
);
7904 list_remove(cursor
);
7905 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7906 HeapFree(GetProcessHeap(), 0, job
->filename
);
7907 HeapFree(GetProcessHeap(), 0, job
);
7911 LeaveCriticalSection(&printer_handles_cs
);
7915 /*****************************************************************************
7916 * StartDocDlgA [WINSPOOL.@]
7918 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7920 UNICODE_STRING usBuffer
;
7923 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7926 docW
.cbSize
= sizeof(docW
);
7927 if (doc
->lpszDocName
)
7929 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7930 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7932 if (doc
->lpszOutput
)
7934 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7935 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7937 if (doc
->lpszDatatype
)
7939 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7940 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7942 docW
.fwType
= doc
->fwType
;
7944 retW
= StartDocDlgW(hPrinter
, &docW
);
7948 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7949 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7950 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7951 HeapFree(GetProcessHeap(), 0, retW
);
7954 HeapFree(GetProcessHeap(), 0, datatypeW
);
7955 HeapFree(GetProcessHeap(), 0, outputW
);
7956 HeapFree(GetProcessHeap(), 0, docnameW
);
7961 /*****************************************************************************
7962 * StartDocDlgW [WINSPOOL.@]
7964 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7965 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7966 * port is "FILE:". Also returns the full path if passed a relative path.
7968 * The caller should free the returned string from the process heap.
7970 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7975 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7977 PRINTER_INFO_5W
*pi5
;
7978 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7979 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7981 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7982 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7983 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7985 HeapFree(GetProcessHeap(), 0, pi5
);
7988 HeapFree(GetProcessHeap(), 0, pi5
);
7991 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7995 if (get_filename(&name
))
7997 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7999 HeapFree(GetProcessHeap(), 0, name
);
8002 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8003 GetFullPathNameW(name
, len
, ret
, NULL
);
8004 HeapFree(GetProcessHeap(), 0, name
);
8009 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8012 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8013 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8015 attr
= GetFileAttributesW(ret
);
8016 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8018 HeapFree(GetProcessHeap(), 0, ret
);