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-2009 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 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
271 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
272 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
274 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
276 /******************************************************************
277 * validate the user-supplied printing-environment [internal]
280 * env [I] PTR to Environment-String or NULL
284 * Success: PTR to printenv_t
287 * An empty string is handled the same way as NULL.
288 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
292 static const printenv_t
* validate_envW(LPCWSTR env
)
294 const printenv_t
*result
= NULL
;
297 TRACE("testing %s\n", debugstr_w(env
));
300 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
302 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
304 result
= all_printenv
[i
];
309 if (result
== NULL
) {
310 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
311 SetLastError(ERROR_INVALID_ENVIRONMENT
);
313 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
317 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
319 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
325 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
326 if passed a NULL string. This returns NULLs to the result.
328 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
332 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
333 return usBufferPtr
->Buffer
;
335 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
339 static LPWSTR
strdupW(LPCWSTR p
)
345 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
346 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
351 static LPSTR
strdupWtoA( LPCWSTR str
)
356 if (!str
) return NULL
;
357 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
358 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
359 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
363 /******************************************************************
364 * Return the number of bytes for an multi_sz string.
365 * The result includes all \0s
366 * (specifically the extra \0, that is needed as multi_sz terminator).
369 static int multi_sz_lenW(const WCHAR
*str
)
371 const WCHAR
*ptr
= str
;
375 ptr
+= lstrlenW(ptr
) + 1;
378 return (ptr
- str
+ 1) * sizeof(WCHAR
);
381 /* ################################ */
383 static int multi_sz_lenA(const char *str
)
385 const char *ptr
= str
;
389 ptr
+= lstrlenA(ptr
) + 1;
392 return ptr
- str
+ 1;
396 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
399 /* If forcing, or no profile string entry for device yet, set the entry
401 * The always change entry if not WINEPS yet is discussable.
404 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
406 !strstr(qbuf
,"WINEPS.DRV")
408 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
411 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
412 WriteProfileStringA("windows","device",buf
);
413 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
414 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
417 HeapFree(GetProcessHeap(),0,buf
);
421 static BOOL
add_printer_driver(const char *name
)
425 static char driver_9x
[] = "wineps16.drv",
426 driver_nt
[] = "wineps.drv",
427 env_9x
[] = "Windows 4.0",
428 env_nt
[] = "Windows NT x86",
429 data_file
[] = "generic.ppd",
430 default_data_type
[] = "RAW";
432 ZeroMemory(&di3a
, sizeof(DRIVER_INFO_3A
));
434 di3a
.pName
= (char *)name
;
435 di3a
.pEnvironment
= env_nt
;
436 di3a
.pDriverPath
= driver_nt
;
437 di3a
.pDataFile
= data_file
;
438 di3a
.pConfigFile
= driver_nt
;
439 di3a
.pDefaultDataType
= default_data_type
;
441 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
442 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
445 di3a
.pEnvironment
= env_9x
;
446 di3a
.pDriverPath
= driver_9x
;
447 di3a
.pConfigFile
= driver_9x
;
448 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
449 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
454 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a
.pDriverPath
),
455 debugstr_a(di3a
.pEnvironment
), GetLastError());
459 #ifdef SONAME_LIBCUPS
460 static typeof(cupsFreeDests
) *pcupsFreeDests
;
461 static typeof(cupsGetDests
) *pcupsGetDests
;
462 static typeof(cupsGetPPD
) *pcupsGetPPD
;
463 static typeof(cupsPrintFile
) *pcupsPrintFile
;
464 static void *cupshandle
;
466 static BOOL
CUPS_LoadPrinters(void)
469 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
471 PRINTER_INFO_2A pinfo2a
;
473 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
476 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
478 TRACE("%s\n", loaderror
);
481 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
484 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
485 if (!p##x) return FALSE;
487 DYNCUPS(cupsFreeDests
);
489 DYNCUPS(cupsGetDests
);
490 DYNCUPS(cupsPrintFile
);
493 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
495 ERR("Can't create Printers key\n");
499 nrofdests
= pcupsGetDests(&dests
);
500 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
501 for (i
=0;i
<nrofdests
;i
++) {
502 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
503 port
= HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests
[i
].name
)+1);
504 sprintf(port
,"LPR:%s", dests
[i
].name
);
505 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
506 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port
));
507 sprintf(devline
, "WINEPS.DRV,%s", port
);
508 WriteProfileStringA("devices", dests
[i
].name
, devline
);
509 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
510 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
514 lstrcatA(devline
, ",15,45");
515 WriteProfileStringA("PrinterPorts", dests
[i
].name
, devline
);
516 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
517 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
521 HeapFree(GetProcessHeap(), 0, devline
);
523 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
524 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
525 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
527 TRACE("Printer already exists\n");
528 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
529 RegCloseKey(hkeyPrinter
);
531 static CHAR data_type
[] = "RAW",
532 print_proc
[] = "WinPrint",
533 comment
[] = "WINEPS Printer using CUPS",
534 location
[] = "<physical location of printer>",
535 params
[] = "<parameters?>",
536 share_name
[] = "<share name?>",
537 sep_file
[] = "<sep file?>";
539 add_printer_driver(dests
[i
].name
);
541 memset(&pinfo2a
,0,sizeof(pinfo2a
));
542 pinfo2a
.pPrinterName
= dests
[i
].name
;
543 pinfo2a
.pDatatype
= data_type
;
544 pinfo2a
.pPrintProcessor
= print_proc
;
545 pinfo2a
.pDriverName
= dests
[i
].name
;
546 pinfo2a
.pComment
= comment
;
547 pinfo2a
.pLocation
= location
;
548 pinfo2a
.pPortName
= port
;
549 pinfo2a
.pParameters
= params
;
550 pinfo2a
.pShareName
= share_name
;
551 pinfo2a
.pSepFile
= sep_file
;
553 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
554 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
555 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
558 HeapFree(GetProcessHeap(),0,port
);
561 if (dests
[i
].is_default
) {
562 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
566 if (hadprinter
& !haddefault
)
567 WINSPOOL_SetDefaultPrinter(dests
[0].name
, dests
[0].name
, TRUE
);
568 pcupsFreeDests(nrofdests
, dests
);
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_load [internal]
795 * load a printmonitor, get the dllname from the registry, when needed
796 * initialize the monitor and dump found function-pointers
798 * On failure, SetLastError() is called and NULL is returned
801 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
803 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
804 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
805 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
806 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
807 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
809 monitor_t
* pm
= NULL
;
811 LPWSTR regroot
= NULL
;
812 LPWSTR driver
= dllname
;
814 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
815 /* Is the Monitor already loaded? */
816 EnterCriticalSection(&monitor_handles_cs
);
819 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
821 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
829 pm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(monitor_t
));
830 if (pm
== NULL
) goto cleanup
;
831 list_add_tail(&monitor_handles
, &pm
->entry
);
835 if (pm
->name
== NULL
) {
836 /* Load the monitor */
837 LPMONITOREX pmonitorEx
;
841 len
= lstrlenW(MonitorsW
) + lstrlenW(name
) + 2;
842 regroot
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
846 lstrcpyW(regroot
, MonitorsW
);
847 lstrcatW(regroot
, name
);
848 /* Get the Driver from the Registry */
849 if (driver
== NULL
) {
852 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
853 if (RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, NULL
,
854 &namesize
) == ERROR_SUCCESS
) {
855 driver
= HeapAlloc(GetProcessHeap(), 0, namesize
);
856 RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
863 pm
->name
= strdupW(name
);
864 pm
->dllname
= strdupW(driver
);
866 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
868 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
873 pm
->hdll
= LoadLibraryW(driver
);
874 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
876 if (pm
->hdll
== NULL
) {
878 SetLastError(ERROR_MOD_NOT_FOUND
);
883 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
884 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
885 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
886 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
887 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
890 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
891 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
892 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
893 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
894 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
896 if (pInitializePrintMonitorUI
!= NULL
) {
897 pm
->monitorUI
= pInitializePrintMonitorUI();
898 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
900 TRACE( "0x%08x: dwMonitorSize (%d)\n",
901 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
906 if (pInitializePrintMonitor
&& regroot
) {
907 pmonitorEx
= pInitializePrintMonitor(regroot
);
908 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
909 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
912 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
913 pm
->monitor
= &(pmonitorEx
->Monitor
);
918 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
922 if (!pm
->monitor
&& regroot
) {
923 if (pInitializePrintMonitor2
!= NULL
) {
924 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
926 if (pInitializeMonitorEx
!= NULL
) {
927 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
929 if (pInitializeMonitor
!= NULL
) {
930 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
933 if (!pm
->monitor
&& !pm
->monitorUI
) {
935 SetLastError(ERROR_PROC_NOT_FOUND
);
940 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, LocalPortW
) == 0)) {
944 LeaveCriticalSection(&monitor_handles_cs
);
945 if (driver
!= dllname
) HeapFree(GetProcessHeap(), 0, driver
);
946 HeapFree(GetProcessHeap(), 0, regroot
);
947 TRACE("=> %p\n", pm
);
951 /******************************************************************
952 * monitor_loadui [internal]
954 * load the userinterface-dll for a given portmonitor
956 * On failure, NULL is returned
959 static monitor_t
* monitor_loadui(monitor_t
* pm
)
961 monitor_t
* pui
= NULL
;
962 LPWSTR buffer
[MAX_PATH
];
967 if (pm
== NULL
) return NULL
;
968 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
970 /* Try the Portmonitor first; works for many monitors */
972 EnterCriticalSection(&monitor_handles_cs
);
974 LeaveCriticalSection(&monitor_handles_cs
);
978 /* query the userinterface-dllname from the Portmonitor */
979 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
980 /* building (",XcvMonitor %s",pm->name) not needed yet */
981 res
= pm
->monitor
->pfnXcvOpenPort(emptyStringW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
982 TRACE("got %u with %p\n", res
, hXcv
);
984 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, MonitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
985 TRACE("got %u with %s\n", res
, debugstr_w((LPWSTR
) buffer
));
986 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, (LPWSTR
) buffer
);
987 pm
->monitor
->pfnXcvClosePort(hXcv
);
994 /******************************************************************
995 * monitor_load_by_port [internal]
997 * load a printmonitor for a given port
999 * On failure, NULL is returned
1002 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
1007 monitor_t
* pm
= NULL
;
1008 DWORD registered
= 0;
1012 TRACE("(%s)\n", debugstr_w(portname
));
1014 /* Try the Local Monitor first */
1015 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
) == ERROR_SUCCESS
) {
1016 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
1017 /* found the portname */
1019 return monitor_load(LocalPortW
, NULL
);
1024 len
= MAX_PATH
+ lstrlenW(bs_Ports_bsW
) + lstrlenW(portname
) + 1;
1025 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1026 if (buffer
== NULL
) return NULL
;
1028 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
1029 EnterCriticalSection(&monitor_handles_cs
);
1030 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1032 while ((pm
== NULL
) && (id
< registered
)) {
1034 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
1035 TRACE("testing %s\n", debugstr_w(buffer
));
1036 len
= lstrlenW(buffer
);
1037 lstrcatW(buffer
, bs_Ports_bsW
);
1038 lstrcatW(buffer
, portname
);
1039 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
1041 buffer
[len
] = '\0'; /* use only the Monitor-Name */
1042 pm
= monitor_load(buffer
, NULL
);
1046 LeaveCriticalSection(&monitor_handles_cs
);
1049 HeapFree(GetProcessHeap(), 0, buffer
);
1053 /******************************************************************
1054 * get_servername_from_name (internal)
1056 * for an external server, a copy of the serverpart from the full name is returned
1059 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1063 WCHAR buffer
[MAX_PATH
];
1066 if (name
== NULL
) return NULL
;
1067 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1069 server
= strdupW(&name
[2]); /* skip over both backslash */
1070 if (server
== NULL
) return NULL
;
1072 /* strip '\' and the printername */
1073 ptr
= strchrW(server
, '\\');
1074 if (ptr
) ptr
[0] = '\0';
1076 TRACE("found %s\n", debugstr_w(server
));
1078 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1079 if (GetComputerNameW(buffer
, &len
)) {
1080 if (lstrcmpW(buffer
, server
) == 0) {
1081 /* The requested Servername is our computername */
1082 HeapFree(GetProcessHeap(), 0, server
);
1089 /******************************************************************
1090 * get_basename_from_name (internal)
1092 * skip over the serverpart from the full name
1095 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1097 if (name
== NULL
) return NULL
;
1098 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1099 /* skip over the servername and search for the following '\' */
1100 name
= strchrW(&name
[2], '\\');
1101 if ((name
) && (name
[1])) {
1102 /* found a separator ('\') followed by a name:
1103 skip over the separator and return the rest */
1108 /* no basename present (we found only a servername) */
1115 /******************************************************************
1116 * get_opened_printer_entry
1117 * Get the first place empty in the opened printer table
1120 * - pDefault is ignored
1122 static HANDLE
get_opened_printer_entry(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1124 UINT_PTR handle
= nb_printer_handles
, i
;
1125 jobqueue_t
*queue
= NULL
;
1126 opened_printer_t
*printer
= NULL
;
1128 LPCWSTR printername
;
1133 servername
= get_servername_from_name(name
);
1135 FIXME("server %s not supported\n", debugstr_w(servername
));
1136 HeapFree(GetProcessHeap(), 0, servername
);
1137 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1141 printername
= get_basename_from_name(name
);
1142 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1144 /* an empty printername is invalid */
1145 if (printername
&& (!printername
[0])) {
1146 SetLastError(ERROR_INVALID_PARAMETER
);
1150 EnterCriticalSection(&printer_handles_cs
);
1152 for (i
= 0; i
< nb_printer_handles
; i
++)
1154 if (!printer_handles
[i
])
1156 if(handle
== nb_printer_handles
)
1161 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1162 queue
= printer_handles
[i
]->queue
;
1166 if (handle
>= nb_printer_handles
)
1168 opened_printer_t
**new_array
;
1169 if (printer_handles
)
1170 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1171 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1173 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1174 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1181 printer_handles
= new_array
;
1182 nb_printer_handles
+= 16;
1185 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1192 /* clone the base name. This is NULL for the printserver */
1193 printer
->printername
= strdupW(printername
);
1195 /* clone the full name */
1196 printer
->name
= strdupW(name
);
1197 if (name
&& (!printer
->name
)) {
1203 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1204 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1205 /* OpenPrinter(",XcvMonitor " detected */
1206 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1207 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1208 if (printer
->pm
== NULL
) {
1209 SetLastError(ERROR_UNKNOWN_PORT
);
1216 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1217 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1218 /* OpenPrinter(",XcvPort " detected */
1219 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1220 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1221 if (printer
->pm
== NULL
) {
1222 SetLastError(ERROR_UNKNOWN_PORT
);
1230 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1231 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1232 pDefault
? pDefault
->DesiredAccess
: 0,
1235 if (printer
->hXcv
== NULL
) {
1236 SetLastError(ERROR_INVALID_PARAMETER
);
1243 /* Does the Printer exist? */
1244 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1245 ERR("Can't create Printers key\n");
1249 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1250 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1251 RegCloseKey(hkeyPrinters
);
1252 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1256 RegCloseKey(hkeyPrinter
);
1257 RegCloseKey(hkeyPrinters
);
1262 TRACE("using the local printserver\n");
1266 printer
->queue
= queue
;
1269 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1270 if (!printer
->queue
) {
1274 list_init(&printer
->queue
->jobs
);
1275 printer
->queue
->ref
= 0;
1277 InterlockedIncrement(&printer
->queue
->ref
);
1279 printer_handles
[handle
] = printer
;
1282 LeaveCriticalSection(&printer_handles_cs
);
1283 if (!handle
&& printer
) {
1284 /* Something failed: Free all resources */
1285 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1286 monitor_unload(printer
->pm
);
1287 HeapFree(GetProcessHeap(), 0, printer
->printername
);
1288 HeapFree(GetProcessHeap(), 0, printer
->name
);
1289 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1290 HeapFree(GetProcessHeap(), 0, printer
);
1293 return (HANDLE
)handle
;
1296 /******************************************************************
1297 * get_opened_printer
1298 * Get the pointer to the opened printer referred by the handle
1300 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
1302 UINT_PTR idx
= (UINT_PTR
)hprn
;
1303 opened_printer_t
*ret
= NULL
;
1305 EnterCriticalSection(&printer_handles_cs
);
1307 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
1308 ret
= printer_handles
[idx
- 1];
1310 LeaveCriticalSection(&printer_handles_cs
);
1314 /******************************************************************
1315 * get_opened_printer_name
1316 * Get the pointer to the opened printer name referred by the handle
1318 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
1320 opened_printer_t
*printer
= get_opened_printer(hprn
);
1321 if(!printer
) return NULL
;
1322 return printer
->name
;
1325 /******************************************************************
1326 * WINSPOOL_GetOpenedPrinterRegKey
1329 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
1331 LPCWSTR name
= get_opened_printer_name(hPrinter
);
1335 if(!name
) return ERROR_INVALID_HANDLE
;
1337 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
1341 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
1343 ERR("Can't find opened printer %s in registry\n",
1345 RegCloseKey(hkeyPrinters
);
1346 return ERROR_INVALID_PRINTER_NAME
; /* ? */
1348 RegCloseKey(hkeyPrinters
);
1349 return ERROR_SUCCESS
;
1352 void WINSPOOL_LoadSystemPrinters(void)
1354 HKEY hkey
, hkeyPrinters
;
1356 DWORD needed
, num
, i
;
1357 WCHAR PrinterName
[256];
1360 /* This ensures that all printer entries have a valid Name value. If causes
1361 problems later if they don't. If one is found to be missed we create one
1362 and set it equal to the name of the key */
1363 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1364 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1365 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1366 for(i
= 0; i
< num
; i
++) {
1367 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1368 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1369 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1370 set_reg_szW(hkey
, NameW
, PrinterName
);
1377 RegCloseKey(hkeyPrinters
);
1380 /* We want to avoid calling AddPrinter on printers as much as
1381 possible, because on cups printers this will (eventually) lead
1382 to a call to cupsGetPPD which takes forever, even with non-cups
1383 printers AddPrinter takes a while. So we'll tag all printers that
1384 were automatically added last time around, if they still exist
1385 we'll leave them be otherwise we'll delete them. */
1386 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1388 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1389 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1390 for(i
= 0; i
< num
; i
++) {
1391 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1392 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1393 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1395 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1403 HeapFree(GetProcessHeap(), 0, pi
);
1407 #ifdef SONAME_LIBCUPS
1408 done
= CUPS_LoadPrinters();
1411 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1412 PRINTCAP_LoadPrinters();
1414 /* Now enumerate the list again and delete any printers that are still tagged */
1415 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1417 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1418 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1419 for(i
= 0; i
< num
; i
++) {
1420 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1421 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1422 BOOL delete_driver
= FALSE
;
1423 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1424 DWORD dw
, type
, size
= sizeof(dw
);
1425 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1426 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1427 DeletePrinter(hprn
);
1428 delete_driver
= TRUE
;
1434 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1439 HeapFree(GetProcessHeap(), 0, pi
);
1446 /******************************************************************
1449 * Get the pointer to the specified job.
1450 * Should hold the printer_handles_cs before calling.
1452 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1454 opened_printer_t
*printer
= get_opened_printer(hprn
);
1457 if(!printer
) return NULL
;
1458 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1460 if(job
->job_id
== JobId
)
1466 /***********************************************************
1469 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1472 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1475 Formname
= (dmA
->dmSize
> off_formname
);
1476 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1477 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1478 dmW
->dmDeviceName
, CCHDEVICENAME
);
1480 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1481 dmA
->dmSize
- CCHDEVICENAME
);
1483 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1484 off_formname
- CCHDEVICENAME
);
1485 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1486 dmW
->dmFormName
, CCHFORMNAME
);
1487 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1488 (off_formname
+ CCHFORMNAME
));
1491 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1492 dmA
->dmDriverExtra
);
1496 /***********************************************************
1498 * Creates an ansi copy of supplied devmode
1500 static LPDEVMODEA
DEVMODEdupWtoA(const DEVMODEW
*dmW
)
1505 if (!dmW
) return NULL
;
1506 size
= dmW
->dmSize
- CCHDEVICENAME
-
1507 ((dmW
->dmSize
> FIELD_OFFSET(DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
1509 dmA
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1510 if (!dmA
) return NULL
;
1512 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1513 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1515 if (FIELD_OFFSET(DEVMODEW
, dmFormName
) >= dmW
->dmSize
) {
1516 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1517 dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1521 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1522 FIELD_OFFSET(DEVMODEW
, dmFormName
) - FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1523 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1524 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1526 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmLogPixels
));
1530 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
1534 /******************************************************************
1535 * convert_printerinfo_W_to_A [internal]
1538 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1539 DWORD level
, DWORD outlen
, DWORD numentries
)
1545 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1547 len
= pi_sizeof
[level
] * numentries
;
1548 ptr
= (LPSTR
) out
+ len
;
1551 /* copy the numbers of all PRINTER_INFO_* first */
1552 memcpy(out
, pPrintersW
, len
);
1554 while (id
< numentries
) {
1558 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1559 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1561 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1562 if (piW
->pDescription
) {
1563 piA
->pDescription
= ptr
;
1564 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1565 ptr
, outlen
, NULL
, NULL
);
1571 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1572 ptr
, outlen
, NULL
, NULL
);
1576 if (piW
->pComment
) {
1577 piA
->pComment
= ptr
;
1578 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1579 ptr
, outlen
, NULL
, NULL
);
1588 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1589 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1592 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1593 if (piW
->pServerName
) {
1594 piA
->pServerName
= ptr
;
1595 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1596 ptr
, outlen
, NULL
, NULL
);
1600 if (piW
->pPrinterName
) {
1601 piA
->pPrinterName
= ptr
;
1602 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1603 ptr
, outlen
, NULL
, NULL
);
1607 if (piW
->pShareName
) {
1608 piA
->pShareName
= ptr
;
1609 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1610 ptr
, outlen
, NULL
, NULL
);
1614 if (piW
->pPortName
) {
1615 piA
->pPortName
= ptr
;
1616 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1617 ptr
, outlen
, NULL
, NULL
);
1621 if (piW
->pDriverName
) {
1622 piA
->pDriverName
= ptr
;
1623 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1624 ptr
, outlen
, NULL
, NULL
);
1628 if (piW
->pComment
) {
1629 piA
->pComment
= ptr
;
1630 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1631 ptr
, outlen
, NULL
, NULL
);
1635 if (piW
->pLocation
) {
1636 piA
->pLocation
= ptr
;
1637 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1638 ptr
, outlen
, NULL
, NULL
);
1643 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1645 /* align DEVMODEA to a DWORD boundary */
1646 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1650 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1651 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1652 memcpy(ptr
, dmA
, len
);
1653 HeapFree(GetProcessHeap(), 0, dmA
);
1659 if (piW
->pSepFile
) {
1660 piA
->pSepFile
= ptr
;
1661 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1662 ptr
, outlen
, NULL
, NULL
);
1666 if (piW
->pPrintProcessor
) {
1667 piA
->pPrintProcessor
= ptr
;
1668 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1669 ptr
, outlen
, NULL
, NULL
);
1673 if (piW
->pDatatype
) {
1674 piA
->pDatatype
= ptr
;
1675 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1676 ptr
, outlen
, NULL
, NULL
);
1680 if (piW
->pParameters
) {
1681 piA
->pParameters
= ptr
;
1682 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1683 ptr
, outlen
, NULL
, NULL
);
1687 if (piW
->pSecurityDescriptor
) {
1688 piA
->pSecurityDescriptor
= NULL
;
1689 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1696 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1697 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1699 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1701 if (piW
->pPrinterName
) {
1702 piA
->pPrinterName
= ptr
;
1703 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1704 ptr
, outlen
, NULL
, NULL
);
1708 if (piW
->pServerName
) {
1709 piA
->pServerName
= ptr
;
1710 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1711 ptr
, outlen
, NULL
, NULL
);
1720 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1721 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1723 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1725 if (piW
->pPrinterName
) {
1726 piA
->pPrinterName
= ptr
;
1727 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1728 ptr
, outlen
, NULL
, NULL
);
1732 if (piW
->pPortName
) {
1733 piA
->pPortName
= ptr
;
1734 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1735 ptr
, outlen
, NULL
, NULL
);
1743 FIXME("for level %u\n", level
);
1745 pPrintersW
+= pi_sizeof
[level
];
1746 out
+= pi_sizeof
[level
];
1751 /***********************************************************
1752 * PRINTER_INFO_2AtoW
1753 * Creates a unicode copy of PRINTER_INFO_2A on heap
1755 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1757 LPPRINTER_INFO_2W piW
;
1758 UNICODE_STRING usBuffer
;
1760 if(!piA
) return NULL
;
1761 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1762 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1764 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1765 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1766 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1767 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1768 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1769 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1770 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1771 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1772 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1773 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1774 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1775 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1779 /***********************************************************
1780 * FREE_PRINTER_INFO_2W
1781 * Free PRINTER_INFO_2W and all strings
1783 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1787 HeapFree(heap
,0,piW
->pServerName
);
1788 HeapFree(heap
,0,piW
->pPrinterName
);
1789 HeapFree(heap
,0,piW
->pShareName
);
1790 HeapFree(heap
,0,piW
->pPortName
);
1791 HeapFree(heap
,0,piW
->pDriverName
);
1792 HeapFree(heap
,0,piW
->pComment
);
1793 HeapFree(heap
,0,piW
->pLocation
);
1794 HeapFree(heap
,0,piW
->pDevMode
);
1795 HeapFree(heap
,0,piW
->pSepFile
);
1796 HeapFree(heap
,0,piW
->pPrintProcessor
);
1797 HeapFree(heap
,0,piW
->pDatatype
);
1798 HeapFree(heap
,0,piW
->pParameters
);
1799 HeapFree(heap
,0,piW
);
1803 /******************************************************************
1804 * DeviceCapabilities [WINSPOOL.@]
1805 * DeviceCapabilitiesA [WINSPOOL.@]
1808 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1809 LPSTR pOutput
, LPDEVMODEA lpdm
)
1813 if (!GDI_CallDeviceCapabilities16
)
1815 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1817 if (!GDI_CallDeviceCapabilities16
) return -1;
1819 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1821 /* If DC_PAPERSIZE map POINT16s to POINTs */
1822 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1823 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1824 POINT
*pt
= (POINT
*)pOutput
;
1826 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1827 for(i
= 0; i
< ret
; i
++, pt
++)
1832 HeapFree( GetProcessHeap(), 0, tmp
);
1838 /*****************************************************************************
1839 * DeviceCapabilitiesW [WINSPOOL.@]
1841 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1844 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1845 WORD fwCapability
, LPWSTR pOutput
,
1846 const DEVMODEW
*pDevMode
)
1848 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
1849 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1850 LPSTR pPortA
= strdupWtoA(pPort
);
1853 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1854 fwCapability
== DC_FILEDEPENDENCIES
||
1855 fwCapability
== DC_PAPERNAMES
)) {
1856 /* These need A -> W translation */
1859 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1863 switch(fwCapability
) {
1868 case DC_FILEDEPENDENCIES
:
1872 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1873 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1875 for(i
= 0; i
< ret
; i
++)
1876 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1877 pOutput
+ (i
* size
), size
);
1878 HeapFree(GetProcessHeap(), 0, pOutputA
);
1880 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1881 (LPSTR
)pOutput
, dmA
);
1883 HeapFree(GetProcessHeap(),0,pPortA
);
1884 HeapFree(GetProcessHeap(),0,pDeviceA
);
1885 HeapFree(GetProcessHeap(),0,dmA
);
1889 /******************************************************************
1890 * DocumentPropertiesA [WINSPOOL.@]
1892 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1894 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1895 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1896 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1898 LPSTR lpName
= pDeviceName
;
1899 static CHAR port
[] = "LPT1:";
1902 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1903 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1907 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1909 ERR("no name from hPrinter?\n");
1910 SetLastError(ERROR_INVALID_HANDLE
);
1913 lpName
= strdupWtoA(lpNameW
);
1916 if (!GDI_CallExtDeviceMode16
)
1918 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1920 if (!GDI_CallExtDeviceMode16
) {
1921 ERR("No CallExtDeviceMode16?\n");
1925 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1926 pDevModeInput
, NULL
, fMode
);
1929 HeapFree(GetProcessHeap(),0,lpName
);
1934 /*****************************************************************************
1935 * DocumentPropertiesW (WINSPOOL.@)
1937 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1939 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1941 LPDEVMODEW pDevModeOutput
,
1942 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1945 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1946 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
1947 LPDEVMODEA pDevModeOutputA
= NULL
;
1950 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1951 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1953 if(pDevModeOutput
) {
1954 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1955 if(ret
< 0) return ret
;
1956 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1958 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1959 pDevModeInputA
, fMode
);
1960 if(pDevModeOutput
) {
1961 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1962 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1964 if(fMode
== 0 && ret
> 0)
1965 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1966 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1967 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1971 /******************************************************************
1972 * OpenPrinterA [WINSPOOL.@]
1977 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1978 LPPRINTER_DEFAULTSA pDefault
)
1980 UNICODE_STRING lpPrinterNameW
;
1981 UNICODE_STRING usBuffer
;
1982 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1983 PWSTR pwstrPrinterNameW
;
1986 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1989 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1990 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1991 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1992 pDefaultW
= &DefaultW
;
1994 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1996 RtlFreeUnicodeString(&usBuffer
);
1997 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1999 RtlFreeUnicodeString(&lpPrinterNameW
);
2003 /******************************************************************
2004 * OpenPrinterW [WINSPOOL.@]
2006 * Open a Printer / Printserver or a Printer-Object
2009 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2010 * phPrinter [O] The resulting Handle is stored here
2011 * pDefault [I] PTR to Default Printer Settings or NULL
2018 * lpPrinterName is one of:
2019 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2020 *| Printer: "PrinterName"
2021 *| Printer-Object: "PrinterName,Job xxx"
2022 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2023 *| XcvPort: "Servername,XcvPort PortName"
2026 *| Printer-Object not supported
2027 *| pDefaults is ignored
2030 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2033 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2035 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2036 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
2040 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2041 SetLastError(ERROR_INVALID_PARAMETER
);
2045 /* Get the unique handle of the printer or Printserver */
2046 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2047 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2048 return (*phPrinter
!= 0);
2051 /******************************************************************
2052 * AddMonitorA [WINSPOOL.@]
2057 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2059 LPWSTR nameW
= NULL
;
2062 LPMONITOR_INFO_2A mi2a
;
2063 MONITOR_INFO_2W mi2w
;
2065 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2066 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2067 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2068 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2069 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2072 SetLastError(ERROR_INVALID_LEVEL
);
2076 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2082 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2083 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2084 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2087 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2089 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2090 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2091 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2093 if (mi2a
->pEnvironment
) {
2094 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2095 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2096 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2098 if (mi2a
->pDLLName
) {
2099 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2100 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2101 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2104 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2106 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2107 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2108 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2110 HeapFree(GetProcessHeap(), 0, nameW
);
2114 /******************************************************************************
2115 * AddMonitorW [WINSPOOL.@]
2117 * Install a Printmonitor
2120 * pName [I] Servername or NULL (local Computer)
2121 * Level [I] Structure-Level (Must be 2)
2122 * pMonitors [I] PTR to MONITOR_INFO_2
2129 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2132 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2134 LPMONITOR_INFO_2W mi2w
;
2136 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2137 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2138 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2139 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2140 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2142 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2145 SetLastError(ERROR_INVALID_LEVEL
);
2149 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2154 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2157 /******************************************************************
2158 * DeletePrinterDriverA [WINSPOOL.@]
2161 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2163 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2166 /******************************************************************
2167 * DeletePrinterDriverW [WINSPOOL.@]
2170 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2172 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2175 /******************************************************************
2176 * DeleteMonitorA [WINSPOOL.@]
2178 * See DeleteMonitorW.
2181 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2183 LPWSTR nameW
= NULL
;
2184 LPWSTR EnvironmentW
= NULL
;
2185 LPWSTR MonitorNameW
= NULL
;
2190 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2191 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2192 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2196 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2197 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2198 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2201 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2202 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2203 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2206 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2208 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2209 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2210 HeapFree(GetProcessHeap(), 0, nameW
);
2214 /******************************************************************
2215 * DeleteMonitorW [WINSPOOL.@]
2217 * Delete a specific Printmonitor from a Printing-Environment
2220 * pName [I] Servername or NULL (local Computer)
2221 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2222 * pMonitorName [I] Name of the Monitor, that should be deleted
2229 * pEnvironment is ignored in Windows for the local Computer.
2232 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2235 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2236 debugstr_w(pMonitorName
));
2238 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2240 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2244 /******************************************************************
2245 * DeletePortA [WINSPOOL.@]
2250 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2252 LPWSTR nameW
= NULL
;
2253 LPWSTR portW
= NULL
;
2257 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2259 /* convert servername to unicode */
2261 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2262 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2263 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2266 /* convert portname to unicode */
2268 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2269 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2270 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2273 res
= DeletePortW(nameW
, hWnd
, portW
);
2274 HeapFree(GetProcessHeap(), 0, nameW
);
2275 HeapFree(GetProcessHeap(), 0, portW
);
2279 /******************************************************************
2280 * DeletePortW [WINSPOOL.@]
2282 * Delete a specific Port
2285 * pName [I] Servername or NULL (local Computer)
2286 * hWnd [I] Handle to parent Window for the Dialog-Box
2287 * pPortName [I] Name of the Port, that should be deleted
2294 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2300 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2302 if (pName
&& pName
[0]) {
2303 SetLastError(ERROR_INVALID_PARAMETER
);
2308 SetLastError(RPC_X_NULL_REF_POINTER
);
2312 /* an empty Portname is Invalid */
2313 if (!pPortName
[0]) {
2314 SetLastError(ERROR_NOT_SUPPORTED
);
2318 pm
= monitor_load_by_port(pPortName
);
2319 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
2320 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2321 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
2322 TRACE("got %d with %u\n", res
, GetLastError());
2326 pui
= monitor_loadui(pm
);
2327 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2328 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2329 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2330 TRACE("got %d with %u\n", res
, GetLastError());
2334 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
2335 pm
, debugstr_w(pm
? pm
->dllname
: NULL
), pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
2337 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2338 SetLastError(ERROR_NOT_SUPPORTED
);
2341 monitor_unload(pui
);
2345 TRACE("returning %d with %u\n", res
, GetLastError());
2349 /******************************************************************************
2350 * SetPrinterW [WINSPOOL.@]
2352 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2354 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2355 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2359 /******************************************************************************
2360 * WritePrinter [WINSPOOL.@]
2362 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2364 opened_printer_t
*printer
;
2367 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2369 EnterCriticalSection(&printer_handles_cs
);
2370 printer
= get_opened_printer(hPrinter
);
2373 SetLastError(ERROR_INVALID_HANDLE
);
2379 SetLastError(ERROR_SPL_NO_STARTDOC
);
2383 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2385 LeaveCriticalSection(&printer_handles_cs
);
2389 /*****************************************************************************
2390 * AddFormA [WINSPOOL.@]
2392 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2394 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2398 /*****************************************************************************
2399 * AddFormW [WINSPOOL.@]
2401 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2403 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2407 /*****************************************************************************
2408 * AddJobA [WINSPOOL.@]
2410 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2413 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2417 SetLastError(ERROR_INVALID_LEVEL
);
2421 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2424 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2425 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2426 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2427 if(*pcbNeeded
> cbBuf
) {
2428 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2431 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2432 addjobA
->JobId
= addjobW
->JobId
;
2433 addjobA
->Path
= (char *)(addjobA
+ 1);
2434 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2440 /*****************************************************************************
2441 * AddJobW [WINSPOOL.@]
2443 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2445 opened_printer_t
*printer
;
2448 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2449 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2450 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2452 ADDJOB_INFO_1W
*addjob
;
2454 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2456 EnterCriticalSection(&printer_handles_cs
);
2458 printer
= get_opened_printer(hPrinter
);
2461 SetLastError(ERROR_INVALID_HANDLE
);
2466 SetLastError(ERROR_INVALID_LEVEL
);
2470 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2474 job
->job_id
= InterlockedIncrement(&next_job_id
);
2476 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2477 if(path
[len
- 1] != '\\')
2479 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2480 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2482 len
= strlenW(filename
);
2483 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2484 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2485 job
->document_title
= strdupW(default_doc_title
);
2486 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2488 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2489 if(*pcbNeeded
<= cbBuf
) {
2490 addjob
= (ADDJOB_INFO_1W
*)pData
;
2491 addjob
->JobId
= job
->job_id
;
2492 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2493 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2496 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2499 LeaveCriticalSection(&printer_handles_cs
);
2503 /*****************************************************************************
2504 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2506 * Return the PATH for the Print-Processors
2508 * See GetPrintProcessorDirectoryW.
2512 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2513 DWORD level
, LPBYTE Info
,
2514 DWORD cbBuf
, LPDWORD pcbNeeded
)
2516 LPWSTR serverW
= NULL
;
2521 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2522 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2526 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2527 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2528 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2532 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2533 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2534 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2537 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2538 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2540 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2543 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2544 cbBuf
, NULL
, NULL
) > 0;
2547 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2548 HeapFree(GetProcessHeap(), 0, envW
);
2549 HeapFree(GetProcessHeap(), 0, serverW
);
2553 /*****************************************************************************
2554 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2556 * Return the PATH for the Print-Processors
2559 * server [I] Servername (NT only) or NULL (local Computer)
2560 * env [I] Printing-Environment (see below) or NULL (Default)
2561 * level [I] Structure-Level (must be 1)
2562 * Info [O] PTR to Buffer that receives the Result
2563 * cbBuf [I] Size of Buffer at "Info"
2564 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2565 * required for the Buffer at "Info"
2568 * Success: TRUE and in pcbNeeded the Bytes used in Info
2569 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2570 * if cbBuf is too small
2572 * Native Values returned in Info on Success:
2573 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2574 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2575 *| win9x(Windows 4.0): "%winsysdir%"
2577 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2580 * Only NULL or "" is supported for server
2583 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2584 DWORD level
, LPBYTE Info
,
2585 DWORD cbBuf
, LPDWORD pcbNeeded
)
2588 const printenv_t
* env_t
;
2590 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
),
2591 debugstr_w(env
), level
, Info
, cbBuf
, pcbNeeded
);
2593 if(server
!= NULL
&& server
[0]) {
2594 FIXME("server not supported: %s\n", debugstr_w(server
));
2595 SetLastError(ERROR_INVALID_PARAMETER
);
2599 env_t
= validate_envW(env
);
2600 if(!env_t
) return FALSE
; /* environment invalid or unsupported */
2603 WARN("(Level: %d) is ignored in win9x\n", level
);
2604 SetLastError(ERROR_INVALID_LEVEL
);
2608 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2609 needed
= GetSystemDirectoryW(NULL
, 0);
2610 /* add the Size for the Subdirectories */
2611 needed
+= lstrlenW(spoolprtprocsW
);
2612 needed
+= lstrlenW(env_t
->subdir
);
2613 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2615 if(pcbNeeded
) *pcbNeeded
= needed
;
2616 TRACE ("required: 0x%x/%d\n", needed
, needed
);
2617 if (needed
> cbBuf
) {
2618 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2621 if(pcbNeeded
== NULL
) {
2622 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2623 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2624 SetLastError(RPC_X_NULL_REF_POINTER
);
2628 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2629 SetLastError(RPC_X_NULL_REF_POINTER
);
2633 GetSystemDirectoryW((LPWSTR
) Info
, cbBuf
/sizeof(WCHAR
));
2634 /* add the Subdirectories */
2635 lstrcatW((LPWSTR
) Info
, spoolprtprocsW
);
2636 lstrcatW((LPWSTR
) Info
, env_t
->subdir
);
2637 TRACE(" => %s\n", debugstr_w((LPWSTR
) Info
));
2641 /*****************************************************************************
2642 * WINSPOOL_OpenDriverReg [internal]
2644 * opens the registry for the printer drivers depending on the given input
2645 * variable pEnvironment
2648 * the opened hkey on success
2651 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
, BOOL unicode
)
2655 const printenv_t
* env
;
2658 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
), unicode
);
2660 if (!pEnvironment
|| unicode
) {
2661 /* pEnvironment was NULL or a Unicode-String: use it direct */
2662 env
= validate_envW(pEnvironment
);
2666 /* pEnvironment was an ANSI-String: convert to unicode first */
2668 INT len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2669 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2670 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, buffer
, len
);
2671 env
= validate_envW(buffer
);
2672 HeapFree(GetProcessHeap(), 0, buffer
);
2674 if (!env
) return NULL
;
2676 buffer
= HeapAlloc( GetProcessHeap(), 0,
2677 (strlenW(DriversW
) + strlenW(env
->envname
) +
2678 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2680 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2681 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2682 HeapFree(GetProcessHeap(), 0, buffer
);
2687 /*****************************************************************************
2688 * AddPrinterW [WINSPOOL.@]
2690 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2692 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2696 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2698 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2699 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2700 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2701 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2702 statusW
[] = {'S','t','a','t','u','s',0},
2703 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2705 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2708 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2709 SetLastError(ERROR_INVALID_PARAMETER
);
2713 ERR("Level = %d, unsupported!\n", Level
);
2714 SetLastError(ERROR_INVALID_LEVEL
);
2718 SetLastError(ERROR_INVALID_PARAMETER
);
2721 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2723 ERR("Can't create Printers key\n");
2726 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2727 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2728 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2729 RegCloseKey(hkeyPrinter
);
2730 RegCloseKey(hkeyPrinters
);
2733 RegCloseKey(hkeyPrinter
);
2735 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
2737 ERR("Can't create Drivers key\n");
2738 RegCloseKey(hkeyPrinters
);
2741 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2743 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2744 RegCloseKey(hkeyPrinters
);
2745 RegCloseKey(hkeyDrivers
);
2746 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2749 RegCloseKey(hkeyDriver
);
2750 RegCloseKey(hkeyDrivers
);
2752 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2753 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2754 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2755 RegCloseKey(hkeyPrinters
);
2759 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2761 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2762 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2763 RegCloseKey(hkeyPrinters
);
2766 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2767 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2768 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2770 /* See if we can load the driver. We may need the devmode structure anyway
2773 * Note that DocumentPropertiesW will briefly try to open the printer we
2774 * just create to find a DEVMODEA struct (it will use the WINEPS default
2775 * one in case it is not there, so we are ok).
2777 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2780 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2781 size
= sizeof(DEVMODEW
);
2787 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2789 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2791 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2792 HeapFree(GetProcessHeap(),0,dmW
);
2797 /* set devmode to printer name */
2798 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2802 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2803 and we support these drivers. NT writes DEVMODEW so somehow
2804 we'll need to distinguish between these when we support NT
2808 dmA
= DEVMODEdupWtoA(dmW
);
2809 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2810 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2811 HeapFree(GetProcessHeap(), 0, dmA
);
2813 HeapFree(GetProcessHeap(), 0, dmW
);
2815 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2816 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2817 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2818 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2820 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2821 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2822 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2823 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2824 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2825 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2826 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2827 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2828 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2829 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2830 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2831 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2832 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2834 RegCloseKey(hkeyPrinter
);
2835 RegCloseKey(hkeyPrinters
);
2836 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2837 ERR("OpenPrinter failing\n");
2843 /*****************************************************************************
2844 * AddPrinterA [WINSPOOL.@]
2846 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2848 UNICODE_STRING pNameW
;
2850 PRINTER_INFO_2W
*piW
;
2851 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2854 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
2856 ERR("Level = %d, unsupported!\n", Level
);
2857 SetLastError(ERROR_INVALID_LEVEL
);
2860 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2861 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2863 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2865 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2866 RtlFreeUnicodeString(&pNameW
);
2871 /*****************************************************************************
2872 * ClosePrinter [WINSPOOL.@]
2874 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2876 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2877 opened_printer_t
*printer
= NULL
;
2880 TRACE("(%p)\n", hPrinter
);
2882 EnterCriticalSection(&printer_handles_cs
);
2884 if ((i
> 0) && (i
<= nb_printer_handles
))
2885 printer
= printer_handles
[i
- 1];
2890 struct list
*cursor
, *cursor2
;
2892 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer
->pm
,
2893 debugstr_w(printer
->pm
? printer
->pm
->dllname
: NULL
),
2894 printer
->hXcv
, debugstr_w(printer
->name
), printer
->doc
);
2897 EndDocPrinter(hPrinter
);
2899 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2901 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2903 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2904 ScheduleJob(hPrinter
, job
->job_id
);
2906 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2908 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
2909 monitor_unload(printer
->pm
);
2910 HeapFree(GetProcessHeap(), 0, printer
->printername
);
2911 HeapFree(GetProcessHeap(), 0, printer
->name
);
2912 HeapFree(GetProcessHeap(), 0, printer
);
2913 printer_handles
[i
- 1] = NULL
;
2916 LeaveCriticalSection(&printer_handles_cs
);
2920 /*****************************************************************************
2921 * DeleteFormA [WINSPOOL.@]
2923 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2925 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2929 /*****************************************************************************
2930 * DeleteFormW [WINSPOOL.@]
2932 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2934 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2938 /*****************************************************************************
2939 * DeletePrinter [WINSPOOL.@]
2941 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2943 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2944 HKEY hkeyPrinters
, hkey
;
2947 SetLastError(ERROR_INVALID_HANDLE
);
2950 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
2951 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
2952 RegCloseKey(hkeyPrinters
);
2954 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
2955 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
2957 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2958 RegDeleteValueW(hkey
, lpNameW
);
2962 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
2963 RegDeleteValueW(hkey
, lpNameW
);
2969 /*****************************************************************************
2970 * SetPrinterA [WINSPOOL.@]
2972 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2975 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
2979 /*****************************************************************************
2980 * SetJobA [WINSPOOL.@]
2982 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2983 LPBYTE pJob
, DWORD Command
)
2987 UNICODE_STRING usBuffer
;
2989 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
2991 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2992 are all ignored by SetJob, so we don't bother copying them */
3000 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3001 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3003 JobW
= (LPBYTE
)info1W
;
3004 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3005 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3006 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3007 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3008 info1W
->Status
= info1A
->Status
;
3009 info1W
->Priority
= info1A
->Priority
;
3010 info1W
->Position
= info1A
->Position
;
3011 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3016 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3017 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3019 JobW
= (LPBYTE
)info2W
;
3020 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3021 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3022 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3023 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3024 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3025 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3026 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3027 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3028 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3029 info2W
->Status
= info2A
->Status
;
3030 info2W
->Priority
= info2A
->Priority
;
3031 info2W
->Position
= info2A
->Position
;
3032 info2W
->StartTime
= info2A
->StartTime
;
3033 info2W
->UntilTime
= info2A
->UntilTime
;
3034 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3038 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3039 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3042 SetLastError(ERROR_INVALID_LEVEL
);
3046 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3052 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3053 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3054 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3055 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3056 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3061 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3062 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3063 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3064 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3065 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3066 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3067 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3068 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3069 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3073 HeapFree(GetProcessHeap(), 0, JobW
);
3078 /*****************************************************************************
3079 * SetJobW [WINSPOOL.@]
3081 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3082 LPBYTE pJob
, DWORD Command
)
3087 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3088 FIXME("Ignoring everything other than document title\n");
3090 EnterCriticalSection(&printer_handles_cs
);
3091 job
= get_job(hPrinter
, JobId
);
3101 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3102 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3103 job
->document_title
= strdupW(info1
->pDocument
);
3108 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3109 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3110 job
->document_title
= strdupW(info2
->pDocument
);
3116 SetLastError(ERROR_INVALID_LEVEL
);
3121 LeaveCriticalSection(&printer_handles_cs
);
3125 /*****************************************************************************
3126 * EndDocPrinter [WINSPOOL.@]
3128 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3130 opened_printer_t
*printer
;
3132 TRACE("(%p)\n", hPrinter
);
3134 EnterCriticalSection(&printer_handles_cs
);
3136 printer
= get_opened_printer(hPrinter
);
3139 SetLastError(ERROR_INVALID_HANDLE
);
3145 SetLastError(ERROR_SPL_NO_STARTDOC
);
3149 CloseHandle(printer
->doc
->hf
);
3150 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3151 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3152 printer
->doc
= NULL
;
3155 LeaveCriticalSection(&printer_handles_cs
);
3159 /*****************************************************************************
3160 * EndPagePrinter [WINSPOOL.@]
3162 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3164 FIXME("(%p): stub\n", hPrinter
);
3168 /*****************************************************************************
3169 * StartDocPrinterA [WINSPOOL.@]
3171 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3173 UNICODE_STRING usBuffer
;
3175 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3178 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3179 or one (DOC_INFO_3) extra DWORDs */
3183 doc2W
.JobId
= doc2
->JobId
;
3186 doc2W
.dwMode
= doc2
->dwMode
;
3189 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3190 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3191 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3195 SetLastError(ERROR_INVALID_LEVEL
);
3199 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3201 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3202 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3203 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3208 /*****************************************************************************
3209 * StartDocPrinterW [WINSPOOL.@]
3211 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3213 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3214 opened_printer_t
*printer
;
3215 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3216 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3217 JOB_INFO_1W job_info
;
3218 DWORD needed
, ret
= 0;
3222 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3223 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3224 debugstr_w(doc
->pDatatype
));
3226 if(Level
< 1 || Level
> 3)
3228 SetLastError(ERROR_INVALID_LEVEL
);
3232 EnterCriticalSection(&printer_handles_cs
);
3233 printer
= get_opened_printer(hPrinter
);
3236 SetLastError(ERROR_INVALID_HANDLE
);
3242 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3246 /* Even if we're printing to a file we still add a print job, we'll
3247 just ignore the spool file name */
3249 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3251 ERR("AddJob failed gle %u\n", GetLastError());
3255 if(doc
->pOutputFile
)
3256 filename
= doc
->pOutputFile
;
3258 filename
= addjob
->Path
;
3260 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3261 if(hf
== INVALID_HANDLE_VALUE
)
3264 memset(&job_info
, 0, sizeof(job_info
));
3265 job_info
.pDocument
= doc
->pDocName
;
3266 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3268 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3269 printer
->doc
->hf
= hf
;
3270 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3272 LeaveCriticalSection(&printer_handles_cs
);
3277 /*****************************************************************************
3278 * StartPagePrinter [WINSPOOL.@]
3280 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3282 FIXME("(%p): stub\n", hPrinter
);
3286 /*****************************************************************************
3287 * GetFormA [WINSPOOL.@]
3289 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3290 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3292 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3293 Level
,pForm
,cbBuf
,pcbNeeded
);
3297 /*****************************************************************************
3298 * GetFormW [WINSPOOL.@]
3300 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3301 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3303 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3304 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3308 /*****************************************************************************
3309 * SetFormA [WINSPOOL.@]
3311 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3314 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3318 /*****************************************************************************
3319 * SetFormW [WINSPOOL.@]
3321 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3324 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3328 /*****************************************************************************
3329 * ReadPrinter [WINSPOOL.@]
3331 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3332 LPDWORD pNoBytesRead
)
3334 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3338 /*****************************************************************************
3339 * ResetPrinterA [WINSPOOL.@]
3341 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3343 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3347 /*****************************************************************************
3348 * ResetPrinterW [WINSPOOL.@]
3350 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3352 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3356 /*****************************************************************************
3357 * WINSPOOL_GetDWORDFromReg
3359 * Return DWORD associated with ValueName from hkey.
3361 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3363 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3366 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3368 if(ret
!= ERROR_SUCCESS
) {
3369 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3372 if(type
!= REG_DWORD
) {
3373 ERR("Got type %d\n", type
);
3380 /*****************************************************************************
3381 * get_filename_from_reg [internal]
3383 * Get ValueName from hkey storing result in out
3384 * when the Value in the registry has only a filename, use driverdir as prefix
3385 * outlen is space left in out
3386 * String is stored either as unicode or ascii
3390 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3391 LPBYTE out
, DWORD outlen
, LPDWORD needed
, BOOL unicode
)
3393 WCHAR filename
[MAX_PATH
];
3397 LPWSTR buffer
= filename
;
3401 size
= sizeof(filename
);
3403 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3404 if (ret
== ERROR_MORE_DATA
) {
3405 TRACE("need dynamic buffer: %u\n", size
);
3406 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3408 /* No Memory is bad */
3412 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3415 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3416 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3422 /* do we have a full path ? */
3423 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3424 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3427 /* we must build the full Path */
3429 if ((out
) && (outlen
> dirlen
)) {
3431 lstrcpyW((LPWSTR
)out
, driverdir
);
3435 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3444 /* write the filename */
3446 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3447 if ((out
) && (outlen
>= size
)) {
3448 lstrcpyW((LPWSTR
)out
, ptr
);
3457 size
= WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, NULL
, 0, NULL
, NULL
);
3458 if ((out
) && (outlen
>= size
)) {
3459 WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3467 ptr
+= lstrlenW(ptr
)+1;
3468 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3471 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3473 /* write the multisz-termination */
3474 if (type
== REG_MULTI_SZ
) {
3475 size
= (unicode
) ? sizeof(WCHAR
) : 1;
3478 if (out
&& (outlen
>= size
)) {
3479 memset (out
, 0, size
);
3485 /*****************************************************************************
3486 * WINSPOOL_GetStringFromReg
3488 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3489 * String is stored either as unicode or ascii.
3490 * Bit of a hack here to get the ValueName if we want ascii.
3492 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3493 DWORD buflen
, DWORD
*needed
,
3496 DWORD sz
= buflen
, type
;
3500 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3502 LPSTR ValueNameA
= strdupWtoA(ValueName
);
3503 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
3504 HeapFree(GetProcessHeap(),0,ValueNameA
);
3506 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3507 WARN("Got ret = %d\n", ret
);
3511 /* add space for terminating '\0' */
3512 sz
+= unicode
? sizeof(WCHAR
) : 1;
3516 TRACE("%s: %s\n", debugstr_w(ValueName
), unicode
? debugstr_w((LPCWSTR
)ptr
) : debugstr_a((LPCSTR
)ptr
));
3521 /*****************************************************************************
3522 * WINSPOOL_GetDefaultDevMode
3524 * Get a default DevMode values for wineps.
3528 static void WINSPOOL_GetDefaultDevMode(
3530 DWORD buflen
, DWORD
*needed
,
3534 static const char szwps
[] = "wineps.drv";
3536 /* fill default DEVMODE - should be read from ppd... */
3537 ZeroMemory( &dm
, sizeof(dm
) );
3538 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
3539 dm
.dmSpecVersion
= DM_SPECVERSION
;
3540 dm
.dmDriverVersion
= 1;
3541 dm
.dmSize
= sizeof(DEVMODEA
);
3542 dm
.dmDriverExtra
= 0;
3544 DM_ORIENTATION
| DM_PAPERSIZE
|
3545 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3548 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3549 DM_YRESOLUTION
| DM_TTOPTION
;
3551 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3552 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3553 dm
.u1
.s1
.dmPaperLength
= 2970;
3554 dm
.u1
.s1
.dmPaperWidth
= 2100;
3556 dm
.u1
.s1
.dmScale
= 100;
3557 dm
.u1
.s1
.dmCopies
= 1;
3558 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3559 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3562 dm
.dmYResolution
= 300; /* 300dpi */
3563 dm
.dmTTOption
= DMTT_BITMAP
;
3566 /* dm.dmLogPixels */
3567 /* dm.dmBitsPerPel */
3568 /* dm.dmPelsWidth */
3569 /* dm.dmPelsHeight */
3570 /* dm.u2.dmDisplayFlags */
3571 /* dm.dmDisplayFrequency */
3572 /* dm.dmICMMethod */
3573 /* dm.dmICMIntent */
3574 /* dm.dmMediaType */
3575 /* dm.dmDitherType */
3576 /* dm.dmReserved1 */
3577 /* dm.dmReserved2 */
3578 /* dm.dmPanningWidth */
3579 /* dm.dmPanningHeight */
3582 if(buflen
>= sizeof(DEVMODEW
)) {
3583 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
3584 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
3585 HeapFree(GetProcessHeap(),0,pdmW
);
3587 *needed
= sizeof(DEVMODEW
);
3591 if(buflen
>= sizeof(DEVMODEA
)) {
3592 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
3594 *needed
= sizeof(DEVMODEA
);
3598 /*****************************************************************************
3599 * WINSPOOL_GetDevModeFromReg
3601 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3602 * DevMode is stored either as unicode or ascii.
3604 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3606 DWORD buflen
, DWORD
*needed
,
3609 DWORD sz
= buflen
, type
;
3612 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3613 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3614 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3615 if (sz
< sizeof(DEVMODEA
))
3617 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3620 /* ensures that dmSize is not erratically bogus if registry is invalid */
3621 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3622 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3624 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3626 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3627 memcpy(ptr
, dmW
, sz
);
3628 HeapFree(GetProcessHeap(),0,dmW
);
3635 /*********************************************************************
3636 * WINSPOOL_GetPrinter_1
3638 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3639 * The strings are either stored as unicode or ascii.
3641 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3642 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3645 DWORD size
, left
= cbBuf
;
3646 BOOL space
= (cbBuf
> 0);
3651 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3653 if(space
&& size
<= left
) {
3654 pi1
->pName
= (LPWSTR
)ptr
;
3662 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3663 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3665 if(space
&& size
<= left
) {
3666 pi1
->pDescription
= (LPWSTR
)ptr
;
3674 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3676 if(space
&& size
<= left
) {
3677 pi1
->pComment
= (LPWSTR
)ptr
;
3685 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3687 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3688 memset(pi1
, 0, sizeof(*pi1
));
3692 /*********************************************************************
3693 * WINSPOOL_GetPrinter_2
3695 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3696 * The strings are either stored as unicode or ascii.
3698 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3699 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3702 DWORD size
, left
= cbBuf
;
3703 BOOL space
= (cbBuf
> 0);
3708 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3710 if(space
&& size
<= left
) {
3711 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3718 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
3720 if(space
&& size
<= left
) {
3721 pi2
->pShareName
= (LPWSTR
)ptr
;
3728 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3730 if(space
&& size
<= left
) {
3731 pi2
->pPortName
= (LPWSTR
)ptr
;
3738 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
3740 if(space
&& size
<= left
) {
3741 pi2
->pDriverName
= (LPWSTR
)ptr
;
3748 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3750 if(space
&& size
<= left
) {
3751 pi2
->pComment
= (LPWSTR
)ptr
;
3758 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
3760 if(space
&& size
<= left
) {
3761 pi2
->pLocation
= (LPWSTR
)ptr
;
3768 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
3770 if(space
&& size
<= left
) {
3771 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3780 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
3781 if(space
&& size
<= left
) {
3782 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3789 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
3791 if(space
&& size
<= left
) {
3792 pi2
->pSepFile
= (LPWSTR
)ptr
;
3799 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
3801 if(space
&& size
<= left
) {
3802 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3809 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
3811 if(space
&& size
<= left
) {
3812 pi2
->pDatatype
= (LPWSTR
)ptr
;
3819 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
3821 if(space
&& size
<= left
) {
3822 pi2
->pParameters
= (LPWSTR
)ptr
;
3830 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3831 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3832 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3833 "Default Priority");
3834 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3835 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3838 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3839 memset(pi2
, 0, sizeof(*pi2
));
3844 /*********************************************************************
3845 * WINSPOOL_GetPrinter_4
3847 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3849 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3850 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3853 DWORD size
, left
= cbBuf
;
3854 BOOL space
= (cbBuf
> 0);
3859 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3861 if(space
&& size
<= left
) {
3862 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3870 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3873 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3874 memset(pi4
, 0, sizeof(*pi4
));
3879 /*********************************************************************
3880 * WINSPOOL_GetPrinter_5
3882 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3884 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3885 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3888 DWORD size
, left
= cbBuf
;
3889 BOOL space
= (cbBuf
> 0);
3894 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3896 if(space
&& size
<= left
) {
3897 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3904 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3906 if(space
&& size
<= left
) {
3907 pi5
->pPortName
= (LPWSTR
)ptr
;
3915 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3916 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3918 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3922 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3923 memset(pi5
, 0, sizeof(*pi5
));
3928 /*********************************************************************
3929 * WINSPOOL_GetPrinter_7
3931 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3933 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
3934 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
3936 DWORD size
, left
= cbBuf
;
3937 BOOL space
= (cbBuf
> 0);
3942 if (WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
, unicode
))
3944 if (space
&& size
<= left
) {
3945 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
3953 /* We do not have a Directory Service */
3954 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
3957 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
3958 memset(pi7
, 0, sizeof(*pi7
));
3963 /*********************************************************************
3964 * WINSPOOL_GetPrinter_9
3966 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
3967 * The strings are either stored as unicode or ascii.
3969 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
3970 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
3973 BOOL space
= (cbBuf
> 0);
3977 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
, unicode
)) {
3978 if(space
&& size
<= cbBuf
) {
3979 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3986 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
, unicode
);
3987 if(space
&& size
<= cbBuf
) {
3988 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3994 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
3995 memset(pi9
, 0, sizeof(*pi9
));
4000 /*****************************************************************************
4001 * WINSPOOL_GetPrinter
4003 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4004 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4005 * just a collection of pointers to strings.
4007 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4008 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
4011 DWORD size
, needed
= 0;
4013 HKEY hkeyPrinter
, hkeyPrinters
;
4016 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4018 if (!(name
= get_opened_printer_name(hPrinter
))) {
4019 SetLastError(ERROR_INVALID_HANDLE
);
4023 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4025 ERR("Can't create Printers key\n");
4028 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
4030 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4031 RegCloseKey(hkeyPrinters
);
4032 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4039 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4041 size
= sizeof(PRINTER_INFO_2W
);
4043 ptr
= pPrinter
+ size
;
4045 memset(pPrinter
, 0, size
);
4050 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
4058 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4060 size
= sizeof(PRINTER_INFO_4W
);
4062 ptr
= pPrinter
+ size
;
4064 memset(pPrinter
, 0, size
);
4069 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
4078 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4080 size
= sizeof(PRINTER_INFO_5W
);
4082 ptr
= pPrinter
+ size
;
4084 memset(pPrinter
, 0, size
);
4090 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
4099 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4101 size
= sizeof(PRINTER_INFO_6
);
4102 if (size
<= cbBuf
) {
4103 /* FIXME: We do not update the status yet */
4104 pi6
->dwStatus
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Status");
4116 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4118 size
= sizeof(PRINTER_INFO_7W
);
4119 if (size
<= cbBuf
) {
4120 ptr
= pPrinter
+ size
;
4122 memset(pPrinter
, 0, size
);
4128 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
, unicode
);
4136 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4138 size
= sizeof(PRINTER_INFO_9W
);
4140 ptr
= pPrinter
+ size
;
4142 memset(pPrinter
, 0, size
);
4148 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
, unicode
);
4155 FIXME("Unimplemented level %d\n", Level
);
4156 SetLastError(ERROR_INVALID_LEVEL
);
4157 RegCloseKey(hkeyPrinters
);
4158 RegCloseKey(hkeyPrinter
);
4162 RegCloseKey(hkeyPrinter
);
4163 RegCloseKey(hkeyPrinters
);
4165 TRACE("returning %d needed = %d\n", ret
, needed
);
4166 if(pcbNeeded
) *pcbNeeded
= needed
;
4168 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4172 /*****************************************************************************
4173 * GetPrinterW [WINSPOOL.@]
4175 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4176 DWORD cbBuf
, LPDWORD pcbNeeded
)
4178 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4182 /*****************************************************************************
4183 * GetPrinterA [WINSPOOL.@]
4185 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4186 DWORD cbBuf
, LPDWORD pcbNeeded
)
4188 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4192 /*****************************************************************************
4193 * WINSPOOL_EnumPrinters
4195 * Implementation of EnumPrintersA|W
4197 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
4198 DWORD dwLevel
, LPBYTE lpbPrinters
,
4199 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4200 LPDWORD lpdwReturned
, BOOL unicode
)
4203 HKEY hkeyPrinters
, hkeyPrinter
;
4204 WCHAR PrinterName
[255];
4205 DWORD needed
= 0, number
= 0;
4206 DWORD used
, i
, left
;
4210 memset(lpbPrinters
, 0, cbBuf
);
4216 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4217 if(dwType
== PRINTER_ENUM_DEFAULT
)
4220 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4221 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4222 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4224 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4232 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4233 FIXME("dwType = %08x\n", dwType
);
4234 SetLastError(ERROR_INVALID_FLAGS
);
4238 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4240 ERR("Can't create Printers key\n");
4244 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4245 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4246 RegCloseKey(hkeyPrinters
);
4247 ERR("Can't query Printers key\n");
4250 TRACE("Found %d printers\n", number
);
4254 used
= number
* sizeof(PRINTER_INFO_1W
);
4257 used
= number
* sizeof(PRINTER_INFO_2W
);
4260 used
= number
* sizeof(PRINTER_INFO_4W
);
4263 used
= number
* sizeof(PRINTER_INFO_5W
);
4267 SetLastError(ERROR_INVALID_LEVEL
);
4268 RegCloseKey(hkeyPrinters
);
4271 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4273 for(i
= 0; i
< number
; i
++) {
4274 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4276 ERR("Can't enum key number %d\n", i
);
4277 RegCloseKey(hkeyPrinters
);
4280 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4281 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4283 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4284 RegCloseKey(hkeyPrinters
);
4289 buf
= lpbPrinters
+ used
;
4290 left
= cbBuf
- used
;
4298 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4299 left
, &needed
, unicode
);
4301 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4304 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4305 left
, &needed
, unicode
);
4307 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4310 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4311 left
, &needed
, unicode
);
4313 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4316 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4317 left
, &needed
, unicode
);
4319 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4322 ERR("Shouldn't be here!\n");
4323 RegCloseKey(hkeyPrinter
);
4324 RegCloseKey(hkeyPrinters
);
4327 RegCloseKey(hkeyPrinter
);
4329 RegCloseKey(hkeyPrinters
);
4336 memset(lpbPrinters
, 0, cbBuf
);
4337 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4341 *lpdwReturned
= number
;
4342 SetLastError(ERROR_SUCCESS
);
4347 /******************************************************************
4348 * EnumPrintersW [WINSPOOL.@]
4350 * Enumerates the available printers, print servers and print
4351 * providers, depending on the specified flags, name and level.
4355 * If level is set to 1:
4356 * Returns an array of PRINTER_INFO_1 data structures in the
4357 * lpbPrinters buffer.
4359 * If level is set to 2:
4360 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4361 * Returns an array of PRINTER_INFO_2 data structures in the
4362 * lpbPrinters buffer. Note that according to MSDN also an
4363 * OpenPrinter should be performed on every remote printer.
4365 * If level is set to 4 (officially WinNT only):
4366 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4367 * Fast: Only the registry is queried to retrieve printer names,
4368 * no connection to the driver is made.
4369 * Returns an array of PRINTER_INFO_4 data structures in the
4370 * lpbPrinters buffer.
4372 * If level is set to 5 (officially WinNT4/Win9x only):
4373 * Fast: Only the registry is queried to retrieve printer names,
4374 * no connection to the driver is made.
4375 * Returns an array of PRINTER_INFO_5 data structures in the
4376 * lpbPrinters buffer.
4378 * If level set to 3 or 6+:
4379 * returns zero (failure!)
4381 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4385 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4386 * - Only levels 2, 4 and 5 are implemented at the moment.
4387 * - 16-bit printer drivers are not enumerated.
4388 * - Returned amount of bytes used/needed does not match the real Windoze
4389 * implementation (as in this implementation, all strings are part
4390 * of the buffer, whereas Win32 keeps them somewhere else)
4391 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4394 * - In a regular Wine installation, no registry settings for printers
4395 * exist, which makes this function return an empty list.
4397 BOOL WINAPI
EnumPrintersW(
4398 DWORD dwType
, /* [in] Types of print objects to enumerate */
4399 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4400 DWORD dwLevel
, /* [in] type of printer info structure */
4401 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4402 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4403 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4404 LPDWORD lpdwReturned
/* [out] number of entries returned */
4407 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4408 lpdwNeeded
, lpdwReturned
, TRUE
);
4411 /******************************************************************
4412 * EnumPrintersA [WINSPOOL.@]
4417 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4418 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4421 UNICODE_STRING pNameU
;
4425 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4426 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4428 pNameW
= asciitounicode(&pNameU
, pName
);
4430 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4431 MS Office need this */
4432 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4434 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4436 RtlFreeUnicodeString(&pNameU
);
4438 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4440 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4444 /*****************************************************************************
4445 * WINSPOOL_GetDriverInfoFromReg [internal]
4447 * Enters the information from the registry into the DRIVER_INFO struct
4450 * zero if the printer driver does not exist in the registry
4451 * (only if Level > 1) otherwise nonzero
4453 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4456 const printenv_t
* env
,
4458 LPBYTE ptr
, /* DRIVER_INFO */
4459 LPBYTE pDriverStrings
, /* strings buffer */
4460 DWORD cbBuf
, /* size of string buffer */
4461 LPDWORD pcbNeeded
, /* space needed for str. */
4462 BOOL unicode
) /* type of strings */
4466 WCHAR driverdir
[MAX_PATH
];
4468 LPBYTE strPtr
= pDriverStrings
;
4469 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4471 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers
,
4472 debugstr_w(DriverName
), env
,
4473 Level
, di
, pDriverStrings
, cbBuf
, unicode
);
4475 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4478 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4479 if (*pcbNeeded
<= cbBuf
)
4480 strcpyW((LPWSTR
)strPtr
, DriverName
);
4484 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0, NULL
, NULL
);
4485 if (*pcbNeeded
<= cbBuf
)
4486 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
4489 /* pName for level 1 has a different offset! */
4491 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4495 /* .cVersion and .pName for level > 1 */
4497 di
->cVersion
= env
->driverversion
;
4498 di
->pName
= (LPWSTR
) strPtr
;
4499 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4502 /* Reserve Space for the largest subdir and a Backslash*/
4503 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4504 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4505 /* Should never Fail */
4508 lstrcatW(driverdir
, env
->versionsubdir
);
4509 lstrcatW(driverdir
, backslashW
);
4511 /* dirlen must not include the terminating zero */
4512 dirlen
= (unicode
) ? lstrlenW(driverdir
) * sizeof(WCHAR
) :
4513 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, NULL
, 0, NULL
, NULL
) -1;
4515 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4516 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4517 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4523 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4525 size
= WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, NULL
, 0, NULL
, NULL
);
4528 if (*pcbNeeded
<= cbBuf
) {
4530 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4534 WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, (LPSTR
)strPtr
, size
, NULL
, NULL
);
4536 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4537 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4540 /* .pDriverPath is the Graphics rendering engine.
4541 The full Path is required to avoid a crash in some apps */
4542 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
, unicode
)) {
4544 if (*pcbNeeded
<= cbBuf
)
4545 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
, unicode
);
4547 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4548 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4551 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4552 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
, unicode
)) {
4554 if (*pcbNeeded
<= cbBuf
)
4555 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
, unicode
);
4557 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4558 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4561 /* .pConfigFile is the Driver user Interface */
4562 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
, unicode
)) {
4564 if (*pcbNeeded
<= cbBuf
)
4565 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
, unicode
);
4567 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4568 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4572 RegCloseKey(hkeyDriver
);
4573 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4578 RegCloseKey(hkeyDriver
);
4579 FIXME("level 5: incomplete\n");
4584 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
, unicode
)) {
4586 if (*pcbNeeded
<= cbBuf
)
4587 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
, unicode
);
4589 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4590 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4593 /* .pDependentFiles */
4594 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
, unicode
)) {
4596 if (*pcbNeeded
<= cbBuf
)
4597 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
, unicode
);
4599 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4600 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4602 else if (GetVersion() & 0x80000000) {
4603 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4604 size
= 2 * ((unicode
) ? sizeof(WCHAR
) : 1);
4606 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4608 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4609 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4612 /* .pMonitorName is the optional Language Monitor */
4613 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
, unicode
)) {
4615 if (*pcbNeeded
<= cbBuf
)
4616 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
, unicode
);
4618 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4619 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4622 /* .pDefaultDataType */
4623 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
, unicode
)) {
4625 if(*pcbNeeded
<= cbBuf
)
4626 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
, unicode
);
4628 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4629 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4633 RegCloseKey(hkeyDriver
);
4634 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4638 /* .pszzPreviousNames */
4639 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
, unicode
)) {
4641 if(*pcbNeeded
<= cbBuf
)
4642 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
, unicode
);
4644 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4645 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4649 RegCloseKey(hkeyDriver
);
4650 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4654 /* support is missing, but not important enough for a FIXME */
4655 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4658 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
, unicode
)) {
4660 if(*pcbNeeded
<= cbBuf
)
4661 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
, unicode
);
4663 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4664 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4668 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
, unicode
)) {
4670 if(*pcbNeeded
<= cbBuf
)
4671 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
, unicode
);
4673 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4674 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4677 /* .pszHardwareID */
4678 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
, unicode
)) {
4680 if(*pcbNeeded
<= cbBuf
)
4681 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
, unicode
);
4683 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4684 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4688 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
, unicode
)) {
4690 if(*pcbNeeded
<= cbBuf
)
4691 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
, unicode
);
4693 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4694 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4698 RegCloseKey(hkeyDriver
);
4702 /* support is missing, but not important enough for a FIXME */
4703 TRACE("level 8: incomplete\n");
4705 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4706 RegCloseKey(hkeyDriver
);
4710 /*****************************************************************************
4711 * WINSPOOL_GetPrinterDriver
4713 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPCWSTR pEnvironment
,
4714 DWORD Level
, LPBYTE pDriverInfo
,
4715 DWORD cbBuf
, LPDWORD pcbNeeded
,
4719 WCHAR DriverName
[100];
4720 DWORD ret
, type
, size
, needed
= 0;
4722 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4723 const printenv_t
* env
;
4725 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4726 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4729 if (!(name
= get_opened_printer_name(hPrinter
))) {
4730 SetLastError(ERROR_INVALID_HANDLE
);
4734 if (Level
< 1 || Level
== 7 || Level
> 8) {
4735 SetLastError(ERROR_INVALID_LEVEL
);
4739 env
= validate_envW(pEnvironment
);
4740 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4742 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4744 ERR("Can't create Printers key\n");
4747 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4749 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4750 RegCloseKey(hkeyPrinters
);
4751 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4754 size
= sizeof(DriverName
);
4756 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4757 (LPBYTE
)DriverName
, &size
);
4758 RegCloseKey(hkeyPrinter
);
4759 RegCloseKey(hkeyPrinters
);
4760 if(ret
!= ERROR_SUCCESS
) {
4761 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4765 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
4767 ERR("Can't create Drivers key\n");
4771 size
= di_sizeof
[Level
];
4772 if ((size
<= cbBuf
) && pDriverInfo
)
4773 ptr
= pDriverInfo
+ size
;
4775 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4776 env
, Level
, pDriverInfo
, ptr
,
4777 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4778 &needed
, unicode
)) {
4779 RegCloseKey(hkeyDrivers
);
4783 RegCloseKey(hkeyDrivers
);
4785 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4786 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4787 if(cbBuf
>= needed
) return TRUE
;
4788 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4792 /*****************************************************************************
4793 * GetPrinterDriverA [WINSPOOL.@]
4795 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4796 DWORD Level
, LPBYTE pDriverInfo
,
4797 DWORD cbBuf
, LPDWORD pcbNeeded
)
4800 UNICODE_STRING pEnvW
;
4803 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4804 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
4805 cbBuf
, pcbNeeded
, FALSE
);
4806 RtlFreeUnicodeString(&pEnvW
);
4809 /*****************************************************************************
4810 * GetPrinterDriverW [WINSPOOL.@]
4812 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4813 DWORD Level
, LPBYTE pDriverInfo
,
4814 DWORD cbBuf
, LPDWORD pcbNeeded
)
4816 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
4817 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
4820 /*****************************************************************************
4821 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4823 * Return the PATH for the Printer-Drivers (UNICODE)
4826 * pName [I] Servername (NT only) or NULL (local Computer)
4827 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4828 * Level [I] Structure-Level (must be 1)
4829 * pDriverDirectory [O] PTR to Buffer that receives the Result
4830 * cbBuf [I] Size of Buffer at pDriverDirectory
4831 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4832 * required for pDriverDirectory
4835 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4836 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4837 * if cbBuf is too small
4839 * Native Values returned in pDriverDirectory on Success:
4840 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4841 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4842 *| win9x(Windows 4.0): "%winsysdir%"
4844 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4847 *- Only NULL or "" is supported for pName
4850 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4851 DWORD Level
, LPBYTE pDriverDirectory
,
4852 DWORD cbBuf
, LPDWORD pcbNeeded
)
4854 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4855 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4857 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4860 /* (Level != 1) is ignored in win9x */
4861 SetLastError(ERROR_INVALID_LEVEL
);
4864 if (pcbNeeded
== NULL
) {
4865 /* (pcbNeeded == NULL) is ignored in win9x */
4866 SetLastError(RPC_X_NULL_REF_POINTER
);
4870 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
4871 pDriverDirectory
, cbBuf
, pcbNeeded
);
4876 /*****************************************************************************
4877 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4879 * Return the PATH for the Printer-Drivers (ANSI)
4881 * See GetPrinterDriverDirectoryW.
4884 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4887 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4888 DWORD Level
, LPBYTE pDriverDirectory
,
4889 DWORD cbBuf
, LPDWORD pcbNeeded
)
4891 UNICODE_STRING nameW
, environmentW
;
4894 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4895 WCHAR
*driverDirectoryW
= NULL
;
4897 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4898 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4900 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4902 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4903 else nameW
.Buffer
= NULL
;
4904 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4905 else environmentW
.Buffer
= NULL
;
4907 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4908 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4911 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4912 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4914 *pcbNeeded
= needed
;
4915 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4917 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4919 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4921 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4922 RtlFreeUnicodeString(&environmentW
);
4923 RtlFreeUnicodeString(&nameW
);
4928 /*****************************************************************************
4929 * AddPrinterDriverA [WINSPOOL.@]
4931 * See AddPrinterDriverW.
4934 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4936 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4937 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4940 /******************************************************************************
4941 * AddPrinterDriverW (WINSPOOL.@)
4943 * Install a Printer Driver
4946 * pName [I] Servername or NULL (local Computer)
4947 * level [I] Level for the supplied DRIVER_INFO_*W struct
4948 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4955 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4957 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
4958 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4961 /*****************************************************************************
4962 * AddPrintProcessorA [WINSPOOL.@]
4964 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4965 LPSTR pPrintProcessorName
)
4967 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4968 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4972 /*****************************************************************************
4973 * AddPrintProcessorW [WINSPOOL.@]
4975 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4976 LPWSTR pPrintProcessorName
)
4978 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4979 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4983 /*****************************************************************************
4984 * AddPrintProvidorA [WINSPOOL.@]
4986 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4988 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4992 /*****************************************************************************
4993 * AddPrintProvidorW [WINSPOOL.@]
4995 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4997 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5001 /*****************************************************************************
5002 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5004 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5005 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5007 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5008 pDevModeOutput
, pDevModeInput
);
5012 /*****************************************************************************
5013 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5015 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5016 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5018 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5019 pDevModeOutput
, pDevModeInput
);
5023 /*****************************************************************************
5024 * PrinterProperties [WINSPOOL.@]
5026 * Displays a dialog to set the properties of the printer.
5029 * nonzero on success or zero on failure
5032 * implemented as stub only
5034 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5035 HANDLE hPrinter
/* [in] handle to printer object */
5037 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5038 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5042 /*****************************************************************************
5043 * EnumJobsA [WINSPOOL.@]
5046 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5047 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5050 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5051 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5053 if(pcbNeeded
) *pcbNeeded
= 0;
5054 if(pcReturned
) *pcReturned
= 0;
5059 /*****************************************************************************
5060 * EnumJobsW [WINSPOOL.@]
5063 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5064 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5067 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5068 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5070 if(pcbNeeded
) *pcbNeeded
= 0;
5071 if(pcReturned
) *pcReturned
= 0;
5075 /*****************************************************************************
5076 * WINSPOOL_EnumPrinterDrivers [internal]
5078 * Delivers information about all printer drivers installed on the
5079 * localhost or a given server
5082 * nonzero on success or zero on failure. If the buffer for the returned
5083 * information is too small the function will return an error
5086 * - only implemented for localhost, foreign hosts will return an error
5088 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5089 DWORD Level
, LPBYTE pDriverInfo
,
5090 DWORD cbBuf
, LPDWORD pcbNeeded
,
5091 LPDWORD pcReturned
, BOOL unicode
)
5094 DWORD i
, needed
, number
= 0, size
= 0;
5095 WCHAR DriverNameW
[255];
5097 const printenv_t
* env
;
5099 TRACE("%s,%s,%d,%p,%d,%d\n",
5100 debugstr_w(pName
), debugstr_w(pEnvironment
),
5101 Level
, pDriverInfo
, cbBuf
, unicode
);
5103 /* check for local drivers */
5104 if((pName
) && (pName
[0])) {
5105 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5106 SetLastError(ERROR_ACCESS_DENIED
);
5110 env
= validate_envW(pEnvironment
);
5111 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5113 /* check input parameter */
5114 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5115 SetLastError(ERROR_INVALID_LEVEL
);
5119 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
)) {
5120 SetLastError(RPC_X_NULL_REF_POINTER
);
5124 /* initialize return values */
5126 memset( pDriverInfo
, 0, cbBuf
);
5130 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
5132 ERR("Can't open Drivers key\n");
5136 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
5137 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5138 RegCloseKey(hkeyDrivers
);
5139 ERR("Can't query Drivers key\n");
5142 TRACE("Found %d Drivers\n", number
);
5144 /* get size of single struct
5145 * unicode and ascii structure have the same size
5147 size
= di_sizeof
[Level
];
5149 /* calculate required buffer size */
5150 *pcbNeeded
= size
* number
;
5152 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
5154 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
5155 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
5157 ERR("Can't enum key number %d\n", i
);
5158 RegCloseKey(hkeyDrivers
);
5161 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5163 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
5164 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5165 &needed
, unicode
)) {
5166 RegCloseKey(hkeyDrivers
);
5169 *pcbNeeded
+= needed
;
5172 RegCloseKey(hkeyDrivers
);
5174 if(cbBuf
< *pcbNeeded
){
5175 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5179 *pcReturned
= number
;
5183 /*****************************************************************************
5184 * EnumPrinterDriversW [WINSPOOL.@]
5186 * see function EnumPrinterDrivers for RETURNS, BUGS
5188 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5189 LPBYTE pDriverInfo
, DWORD cbBuf
,
5190 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5192 static const WCHAR allW
[] = {'a','l','l',0};
5194 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
5197 DWORD i
, needed
, returned
, bufsize
= cbBuf
;
5199 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5201 needed
= returned
= 0;
5202 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5203 pDriverInfo
, bufsize
, &needed
, &returned
, TRUE
);
5204 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5208 if (pDriverInfo
) pDriverInfo
+= needed
;
5209 if (pcReturned
) *pcReturned
+= returned
;
5211 if (pcbNeeded
) *pcbNeeded
+= needed
;
5215 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5216 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
5219 /*****************************************************************************
5220 * EnumPrinterDriversA [WINSPOOL.@]
5222 * see function EnumPrinterDrivers for RETURNS, BUGS
5224 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5225 LPBYTE pDriverInfo
, DWORD cbBuf
,
5226 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5229 UNICODE_STRING pNameW
, pEnvironmentW
;
5230 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5232 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5233 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5235 if (pEnvironment
&& !strcmp(pEnvironment
, "all"))
5237 DWORD i
, needed
, returned
, bufsize
= cbBuf
;
5239 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5241 needed
= returned
= 0;
5242 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, all_printenv
[i
]->envname
, Level
,
5243 pDriverInfo
, bufsize
, &needed
, &returned
, FALSE
);
5244 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) break;
5248 if (pDriverInfo
) pDriverInfo
+= needed
;
5249 if (pcReturned
) *pcReturned
+= returned
;
5251 if (pcbNeeded
) *pcbNeeded
+= needed
;
5254 else ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
5255 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
5257 RtlFreeUnicodeString(&pNameW
);
5258 RtlFreeUnicodeString(&pEnvironmentW
);
5263 /******************************************************************************
5264 * EnumPortsA (WINSPOOL.@)
5269 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5270 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5273 LPBYTE bufferW
= NULL
;
5274 LPWSTR nameW
= NULL
;
5276 DWORD numentries
= 0;
5279 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5280 cbBuf
, pcbNeeded
, pcReturned
);
5282 /* convert servername to unicode */
5284 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5285 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5286 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5288 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5289 needed
= cbBuf
* sizeof(WCHAR
);
5290 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5291 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5293 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5294 if (pcbNeeded
) needed
= *pcbNeeded
;
5295 /* HeapReAlloc return NULL, when bufferW was NULL */
5296 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5297 HeapAlloc(GetProcessHeap(), 0, needed
);
5299 /* Try again with the large Buffer */
5300 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5302 needed
= pcbNeeded
? *pcbNeeded
: 0;
5303 numentries
= pcReturned
? *pcReturned
: 0;
5306 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5307 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5310 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5311 DWORD entrysize
= 0;
5314 LPPORT_INFO_2W pi2w
;
5315 LPPORT_INFO_2A pi2a
;
5318 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5320 /* First pass: calculate the size for all Entries */
5321 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5322 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5324 while (index
< numentries
) {
5326 needed
+= entrysize
; /* PORT_INFO_?A */
5327 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5329 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5330 NULL
, 0, NULL
, NULL
);
5332 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5333 NULL
, 0, NULL
, NULL
);
5334 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5335 NULL
, 0, NULL
, NULL
);
5337 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5338 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5339 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5342 /* check for errors and quit on failure */
5343 if (cbBuf
< needed
) {
5344 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5348 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5349 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5350 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5351 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5352 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5354 /* Second Pass: Fill the User Buffer (if we have one) */
5355 while ((index
< numentries
) && pPorts
) {
5357 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5358 pi2a
->pPortName
= ptr
;
5359 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5360 ptr
, cbBuf
, NULL
, NULL
);
5364 pi2a
->pMonitorName
= ptr
;
5365 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5366 ptr
, cbBuf
, NULL
, NULL
);
5370 pi2a
->pDescription
= ptr
;
5371 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5372 ptr
, cbBuf
, NULL
, NULL
);
5376 pi2a
->fPortType
= pi2w
->fPortType
;
5377 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5380 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5381 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5382 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5387 if (pcbNeeded
) *pcbNeeded
= needed
;
5388 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5390 HeapFree(GetProcessHeap(), 0, nameW
);
5391 HeapFree(GetProcessHeap(), 0, bufferW
);
5393 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5394 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5400 /******************************************************************************
5401 * EnumPortsW (WINSPOOL.@)
5403 * Enumerate available Ports
5406 * pName [I] Servername or NULL (local Computer)
5407 * Level [I] Structure-Level (1 or 2)
5408 * pPorts [O] PTR to Buffer that receives the Result
5409 * cbBuf [I] Size of Buffer at pPorts
5410 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5411 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5415 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5418 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5421 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5422 cbBuf
, pcbNeeded
, pcReturned
);
5424 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5426 /* Level is not checked in win9x */
5427 if (!Level
|| (Level
> 2)) {
5428 WARN("level (%d) is ignored in win9x\n", Level
);
5429 SetLastError(ERROR_INVALID_LEVEL
);
5432 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5433 SetLastError(RPC_X_NULL_REF_POINTER
);
5437 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5440 /******************************************************************************
5441 * GetDefaultPrinterW (WINSPOOL.@)
5444 * This function must read the value from data 'device' of key
5445 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5447 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5451 WCHAR
*buffer
, *ptr
;
5455 SetLastError(ERROR_INVALID_PARAMETER
);
5459 /* make the buffer big enough for the stuff from the profile/registry,
5460 * the content must fit into the local buffer to compute the correct
5461 * size even if the extern buffer is too small or not given.
5462 * (20 for ,driver,port) */
5464 len
= max(100, (insize
+ 20));
5465 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5467 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5469 SetLastError (ERROR_FILE_NOT_FOUND
);
5473 TRACE("%s\n", debugstr_w(buffer
));
5475 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5477 SetLastError(ERROR_INVALID_NAME
);
5483 *namesize
= strlenW(buffer
) + 1;
5484 if(!name
|| (*namesize
> insize
))
5486 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5490 strcpyW(name
, buffer
);
5493 HeapFree( GetProcessHeap(), 0, buffer
);
5498 /******************************************************************************
5499 * GetDefaultPrinterA (WINSPOOL.@)
5501 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5505 WCHAR
*bufferW
= NULL
;
5509 SetLastError(ERROR_INVALID_PARAMETER
);
5513 if(name
&& *namesize
) {
5515 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5518 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5523 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5527 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5530 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5533 HeapFree( GetProcessHeap(), 0, bufferW
);
5538 /******************************************************************************
5539 * SetDefaultPrinterW (WINSPOOL.204)
5541 * Set the Name of the Default Printer
5544 * pszPrinter [I] Name of the Printer or NULL
5551 * When the Parameter is NULL or points to an Empty String and
5552 * a Default Printer was already present, then this Function changes nothing.
5553 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5554 * the First enumerated local Printer is used.
5557 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5560 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5562 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5566 /******************************************************************************
5567 * SetDefaultPrinterA (WINSPOOL.202)
5569 * See SetDefaultPrinterW.
5572 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5575 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5577 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5582 /******************************************************************************
5583 * SetPrinterDataExA (WINSPOOL.@)
5585 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5586 LPCSTR pValueName
, DWORD Type
,
5587 LPBYTE pData
, DWORD cbData
)
5589 HKEY hkeyPrinter
, hkeySubkey
;
5592 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5593 debugstr_a(pValueName
), Type
, pData
, cbData
);
5595 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5599 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5601 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5602 RegCloseKey(hkeyPrinter
);
5605 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5606 RegCloseKey(hkeySubkey
);
5607 RegCloseKey(hkeyPrinter
);
5611 /******************************************************************************
5612 * SetPrinterDataExW (WINSPOOL.@)
5614 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5615 LPCWSTR pValueName
, DWORD Type
,
5616 LPBYTE pData
, DWORD cbData
)
5618 HKEY hkeyPrinter
, hkeySubkey
;
5621 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5622 debugstr_w(pValueName
), Type
, pData
, cbData
);
5624 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5628 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5630 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5631 RegCloseKey(hkeyPrinter
);
5634 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5635 RegCloseKey(hkeySubkey
);
5636 RegCloseKey(hkeyPrinter
);
5640 /******************************************************************************
5641 * SetPrinterDataA (WINSPOOL.@)
5643 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5644 LPBYTE pData
, DWORD cbData
)
5646 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5650 /******************************************************************************
5651 * SetPrinterDataW (WINSPOOL.@)
5653 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5654 LPBYTE pData
, DWORD cbData
)
5656 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5660 /******************************************************************************
5661 * GetPrinterDataExA (WINSPOOL.@)
5663 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5664 LPCSTR pValueName
, LPDWORD pType
,
5665 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5667 HKEY hkeyPrinter
, hkeySubkey
;
5670 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5671 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
5674 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5678 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5680 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
5681 RegCloseKey(hkeyPrinter
);
5685 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5686 RegCloseKey(hkeySubkey
);
5687 RegCloseKey(hkeyPrinter
);
5691 /******************************************************************************
5692 * GetPrinterDataExW (WINSPOOL.@)
5694 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5695 LPCWSTR pValueName
, LPDWORD pType
,
5696 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5698 HKEY hkeyPrinter
, hkeySubkey
;
5701 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5702 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
5705 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5709 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5711 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
5712 RegCloseKey(hkeyPrinter
);
5716 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5717 RegCloseKey(hkeySubkey
);
5718 RegCloseKey(hkeyPrinter
);
5722 /******************************************************************************
5723 * GetPrinterDataA (WINSPOOL.@)
5725 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5726 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5728 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5729 pData
, nSize
, pcbNeeded
);
5732 /******************************************************************************
5733 * GetPrinterDataW (WINSPOOL.@)
5735 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5736 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5738 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5739 pData
, nSize
, pcbNeeded
);
5742 /*******************************************************************************
5743 * EnumPrinterDataExW [WINSPOOL.@]
5745 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5746 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5747 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5749 HKEY hkPrinter
, hkSubKey
;
5750 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5751 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5756 PPRINTER_ENUM_VALUESW ppev
;
5758 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5760 if (pKeyName
== NULL
|| *pKeyName
== 0)
5761 return ERROR_INVALID_PARAMETER
;
5763 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5764 if (ret
!= ERROR_SUCCESS
)
5766 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5771 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5772 if (ret
!= ERROR_SUCCESS
)
5774 r
= RegCloseKey (hkPrinter
);
5775 if (r
!= ERROR_SUCCESS
)
5776 WARN ("RegCloseKey returned %i\n", r
);
5777 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5778 debugstr_w (pKeyName
), ret
);
5782 ret
= RegCloseKey (hkPrinter
);
5783 if (ret
!= ERROR_SUCCESS
)
5785 ERR ("RegCloseKey returned %i\n", ret
);
5786 r
= RegCloseKey (hkSubKey
);
5787 if (r
!= ERROR_SUCCESS
)
5788 WARN ("RegCloseKey returned %i\n", r
);
5792 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5793 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5794 if (ret
!= ERROR_SUCCESS
)
5796 r
= RegCloseKey (hkSubKey
);
5797 if (r
!= ERROR_SUCCESS
)
5798 WARN ("RegCloseKey returned %i\n", r
);
5799 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5803 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5804 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5806 if (cValues
== 0) /* empty key */
5808 r
= RegCloseKey (hkSubKey
);
5809 if (r
!= ERROR_SUCCESS
)
5810 WARN ("RegCloseKey returned %i\n", r
);
5811 *pcbEnumValues
= *pnEnumValues
= 0;
5812 return ERROR_SUCCESS
;
5815 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5817 hHeap
= GetProcessHeap ();
5820 ERR ("GetProcessHeap failed\n");
5821 r
= RegCloseKey (hkSubKey
);
5822 if (r
!= ERROR_SUCCESS
)
5823 WARN ("RegCloseKey returned %i\n", r
);
5824 return ERROR_OUTOFMEMORY
;
5827 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5828 if (lpValueName
== NULL
)
5830 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5831 r
= RegCloseKey (hkSubKey
);
5832 if (r
!= ERROR_SUCCESS
)
5833 WARN ("RegCloseKey returned %i\n", r
);
5834 return ERROR_OUTOFMEMORY
;
5837 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5838 if (lpValue
== NULL
)
5840 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5841 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5842 WARN ("HeapFree failed with code %i\n", GetLastError ());
5843 r
= RegCloseKey (hkSubKey
);
5844 if (r
!= ERROR_SUCCESS
)
5845 WARN ("RegCloseKey returned %i\n", r
);
5846 return ERROR_OUTOFMEMORY
;
5849 TRACE ("pass 1: calculating buffer required for all names and values\n");
5851 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5853 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5855 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5857 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5858 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5859 NULL
, NULL
, lpValue
, &cbValueLen
);
5860 if (ret
!= ERROR_SUCCESS
)
5862 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5863 WARN ("HeapFree failed with code %i\n", GetLastError ());
5864 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5865 WARN ("HeapFree failed with code %i\n", GetLastError ());
5866 r
= RegCloseKey (hkSubKey
);
5867 if (r
!= ERROR_SUCCESS
)
5868 WARN ("RegCloseKey returned %i\n", r
);
5869 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5873 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5874 debugstr_w (lpValueName
), dwIndex
,
5875 cbValueNameLen
+ 1, cbValueLen
);
5877 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5878 cbBufSize
+= cbValueLen
;
5881 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5883 *pcbEnumValues
= cbBufSize
;
5884 *pnEnumValues
= cValues
;
5886 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5888 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5889 WARN ("HeapFree failed with code %i\n", GetLastError ());
5890 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5891 WARN ("HeapFree failed with code %i\n", GetLastError ());
5892 r
= RegCloseKey (hkSubKey
);
5893 if (r
!= ERROR_SUCCESS
)
5894 WARN ("RegCloseKey returned %i\n", r
);
5895 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5896 return ERROR_MORE_DATA
;
5899 TRACE ("pass 2: copying all names and values to buffer\n");
5901 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5902 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5904 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5906 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5907 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5908 NULL
, &dwType
, lpValue
, &cbValueLen
);
5909 if (ret
!= ERROR_SUCCESS
)
5911 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5912 WARN ("HeapFree failed with code %i\n", GetLastError ());
5913 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5914 WARN ("HeapFree failed with code %i\n", GetLastError ());
5915 r
= RegCloseKey (hkSubKey
);
5916 if (r
!= ERROR_SUCCESS
)
5917 WARN ("RegCloseKey returned %i\n", r
);
5918 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5922 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5923 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5924 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5925 pEnumValues
+= cbValueNameLen
;
5927 /* return # of *bytes* (including trailing \0), not # of chars */
5928 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5930 ppev
[dwIndex
].dwType
= dwType
;
5932 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5933 ppev
[dwIndex
].pData
= pEnumValues
;
5934 pEnumValues
+= cbValueLen
;
5936 ppev
[dwIndex
].cbData
= cbValueLen
;
5938 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5939 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5942 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5944 ret
= GetLastError ();
5945 ERR ("HeapFree failed with code %i\n", ret
);
5946 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5947 WARN ("HeapFree failed with code %i\n", GetLastError ());
5948 r
= RegCloseKey (hkSubKey
);
5949 if (r
!= ERROR_SUCCESS
)
5950 WARN ("RegCloseKey returned %i\n", r
);
5954 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5956 ret
= GetLastError ();
5957 ERR ("HeapFree failed with code %i\n", ret
);
5958 r
= RegCloseKey (hkSubKey
);
5959 if (r
!= ERROR_SUCCESS
)
5960 WARN ("RegCloseKey returned %i\n", r
);
5964 ret
= RegCloseKey (hkSubKey
);
5965 if (ret
!= ERROR_SUCCESS
)
5967 ERR ("RegCloseKey returned %i\n", ret
);
5971 return ERROR_SUCCESS
;
5974 /*******************************************************************************
5975 * EnumPrinterDataExA [WINSPOOL.@]
5977 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5978 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5979 * what Windows 2000 SP1 does.
5982 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5983 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5984 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5988 DWORD ret
, dwIndex
, dwBufSize
;
5992 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5994 if (pKeyName
== NULL
|| *pKeyName
== 0)
5995 return ERROR_INVALID_PARAMETER
;
5997 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6000 ret
= GetLastError ();
6001 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6005 hHeap
= GetProcessHeap ();
6008 ERR ("GetProcessHeap failed\n");
6009 return ERROR_OUTOFMEMORY
;
6012 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6013 if (pKeyNameW
== NULL
)
6015 ERR ("Failed to allocate %i bytes from process heap\n",
6016 (LONG
)(len
* sizeof (WCHAR
)));
6017 return ERROR_OUTOFMEMORY
;
6020 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6022 ret
= GetLastError ();
6023 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6024 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6025 WARN ("HeapFree failed with code %i\n", GetLastError ());
6029 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6030 pcbEnumValues
, pnEnumValues
);
6031 if (ret
!= ERROR_SUCCESS
)
6033 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6034 WARN ("HeapFree failed with code %i\n", GetLastError ());
6035 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6039 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6041 ret
= GetLastError ();
6042 ERR ("HeapFree failed with code %i\n", ret
);
6046 if (*pnEnumValues
== 0) /* empty key */
6047 return ERROR_SUCCESS
;
6050 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6052 PPRINTER_ENUM_VALUESW ppev
=
6053 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6055 if (dwBufSize
< ppev
->cbValueName
)
6056 dwBufSize
= ppev
->cbValueName
;
6058 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6059 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6060 dwBufSize
= ppev
->cbData
;
6063 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6065 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6066 if (pBuffer
== NULL
)
6068 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6069 return ERROR_OUTOFMEMORY
;
6072 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6074 PPRINTER_ENUM_VALUESW ppev
=
6075 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6077 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6078 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6082 ret
= GetLastError ();
6083 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6084 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6085 WARN ("HeapFree failed with code %i\n", GetLastError ());
6089 memcpy (ppev
->pValueName
, pBuffer
, len
);
6091 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6093 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6094 ppev
->dwType
!= REG_MULTI_SZ
)
6097 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6098 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6101 ret
= GetLastError ();
6102 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6103 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6104 WARN ("HeapFree failed with code %i\n", GetLastError ());
6108 memcpy (ppev
->pData
, pBuffer
, len
);
6110 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6111 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6114 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6116 ret
= GetLastError ();
6117 ERR ("HeapFree failed with code %i\n", ret
);
6121 return ERROR_SUCCESS
;
6124 /******************************************************************************
6125 * AbortPrinter (WINSPOOL.@)
6127 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6129 FIXME("(%p), stub!\n", hPrinter
);
6133 /******************************************************************************
6134 * AddPortA (WINSPOOL.@)
6139 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6141 LPWSTR nameW
= NULL
;
6142 LPWSTR monitorW
= NULL
;
6146 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6149 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6150 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6151 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6155 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6156 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6157 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6159 res
= AddPortW(nameW
, hWnd
, monitorW
);
6160 HeapFree(GetProcessHeap(), 0, nameW
);
6161 HeapFree(GetProcessHeap(), 0, monitorW
);
6165 /******************************************************************************
6166 * AddPortW (WINSPOOL.@)
6168 * Add a Port for a specific Monitor
6171 * pName [I] Servername or NULL (local Computer)
6172 * hWnd [I] Handle to parent Window for the Dialog-Box
6173 * pMonitorName [I] Name of the Monitor that manage the Port
6180 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6186 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6188 if (pName
&& pName
[0]) {
6189 SetLastError(ERROR_INVALID_PARAMETER
);
6193 if (!pMonitorName
) {
6194 SetLastError(RPC_X_NULL_REF_POINTER
);
6198 /* an empty Monitorname is Invalid */
6199 if (!pMonitorName
[0]) {
6200 SetLastError(ERROR_NOT_SUPPORTED
);
6204 pm
= monitor_load(pMonitorName
, NULL
);
6205 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
6206 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
6207 TRACE("got %d with %u\n", res
, GetLastError());
6212 pui
= monitor_loadui(pm
);
6213 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
6214 TRACE("use %p: %s\n", pui
, debugstr_w(pui
->dllname
));
6215 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
6216 TRACE("got %d with %u\n", res
, GetLastError());
6221 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName
),
6222 pm
, debugstr_w(pm
? pm
->dllname
: NULL
), pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
6224 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6225 SetLastError(ERROR_NOT_SUPPORTED
);
6228 monitor_unload(pui
);
6231 TRACE("returning %d with %u\n", res
, GetLastError());
6235 /******************************************************************************
6236 * AddPortExA (WINSPOOL.@)
6241 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6244 PORT_INFO_2A
* pi2A
;
6245 LPWSTR nameW
= NULL
;
6246 LPWSTR monitorW
= NULL
;
6250 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6252 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6253 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6255 if ((level
< 1) || (level
> 2)) {
6256 SetLastError(ERROR_INVALID_LEVEL
);
6261 SetLastError(ERROR_INVALID_PARAMETER
);
6266 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6267 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6268 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6272 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6273 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6274 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6277 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6279 if (pi2A
->pPortName
) {
6280 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6281 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6282 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6286 if (pi2A
->pMonitorName
) {
6287 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6288 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6289 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6292 if (pi2A
->pDescription
) {
6293 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6294 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6295 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6297 pi2W
.fPortType
= pi2A
->fPortType
;
6298 pi2W
.Reserved
= pi2A
->Reserved
;
6301 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6303 HeapFree(GetProcessHeap(), 0, nameW
);
6304 HeapFree(GetProcessHeap(), 0, monitorW
);
6305 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6306 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6307 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6312 /******************************************************************************
6313 * AddPortExW (WINSPOOL.@)
6315 * Add a Port for a specific Monitor, without presenting a user interface
6318 * pName [I] Servername or NULL (local Computer)
6319 * level [I] Structure-Level (1 or 2) for pBuffer
6320 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6321 * pMonitorName [I] Name of the Monitor that manage the Port
6328 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6334 pi2
= (PORT_INFO_2W
*) pBuffer
;
6336 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6337 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6338 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6339 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6342 if ((level
< 1) || (level
> 2)) {
6343 SetLastError(ERROR_INVALID_LEVEL
);
6347 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6348 SetLastError(ERROR_INVALID_PARAMETER
);
6352 /* load the Monitor */
6353 pm
= monitor_load(pMonitorName
, NULL
);
6355 SetLastError(ERROR_INVALID_PARAMETER
);
6359 if (pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
6360 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6361 TRACE("got %u with %u\n", res
, GetLastError());
6365 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName
), pm
->monitor
);
6371 /******************************************************************************
6372 * AddPrinterConnectionA (WINSPOOL.@)
6374 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6376 FIXME("%s\n", debugstr_a(pName
));
6380 /******************************************************************************
6381 * AddPrinterConnectionW (WINSPOOL.@)
6383 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6385 FIXME("%s\n", debugstr_w(pName
));
6389 /******************************************************************************
6390 * AddPrinterDriverExW (WINSPOOL.@)
6392 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6395 * pName [I] Servername or NULL (local Computer)
6396 * level [I] Level for the supplied DRIVER_INFO_*W struct
6397 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6398 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6405 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6407 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6409 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6411 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6412 SetLastError(ERROR_INVALID_LEVEL
);
6417 SetLastError(ERROR_INVALID_PARAMETER
);
6421 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6424 /******************************************************************************
6425 * AddPrinterDriverExA (WINSPOOL.@)
6427 * See AddPrinterDriverExW.
6430 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6432 DRIVER_INFO_8A
*diA
;
6434 LPWSTR nameW
= NULL
;
6439 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6441 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6442 ZeroMemory(&diW
, sizeof(diW
));
6444 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6445 SetLastError(ERROR_INVALID_LEVEL
);
6450 SetLastError(ERROR_INVALID_PARAMETER
);
6454 /* convert servername to unicode */
6456 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6457 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6458 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6462 diW
.cVersion
= diA
->cVersion
;
6465 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6466 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6467 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6470 if (diA
->pEnvironment
) {
6471 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6472 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6473 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6476 if (diA
->pDriverPath
) {
6477 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6478 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6479 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6482 if (diA
->pDataFile
) {
6483 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6484 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6485 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6488 if (diA
->pConfigFile
) {
6489 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6490 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6491 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6494 if ((Level
> 2) && diA
->pDependentFiles
) {
6495 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6496 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6497 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6498 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6501 if ((Level
> 2) && diA
->pMonitorName
) {
6502 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6503 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6504 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6507 if ((Level
> 3) && diA
->pDefaultDataType
) {
6508 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6509 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6510 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6513 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6514 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6515 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6516 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6517 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6520 if ((Level
> 5) && diA
->pszMfgName
) {
6521 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6522 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6523 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6526 if ((Level
> 5) && diA
->pszOEMUrl
) {
6527 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6528 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6529 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6532 if ((Level
> 5) && diA
->pszHardwareID
) {
6533 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6534 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6535 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6538 if ((Level
> 5) && diA
->pszProvider
) {
6539 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6540 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6541 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6545 FIXME("level %u is incomplete\n", Level
);
6548 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6549 TRACE("got %u with %u\n", res
, GetLastError());
6550 HeapFree(GetProcessHeap(), 0, nameW
);
6551 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6552 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6553 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6554 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6555 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6556 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6557 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6558 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6559 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6560 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6561 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6562 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6563 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6565 TRACE("=> %u with %u\n", res
, GetLastError());
6569 /******************************************************************************
6570 * ConfigurePortA (WINSPOOL.@)
6572 * See ConfigurePortW.
6575 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6577 LPWSTR nameW
= NULL
;
6578 LPWSTR portW
= NULL
;
6582 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6584 /* convert servername to unicode */
6586 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6587 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6588 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6591 /* convert portname to unicode */
6593 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6594 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6595 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6598 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6599 HeapFree(GetProcessHeap(), 0, nameW
);
6600 HeapFree(GetProcessHeap(), 0, portW
);
6604 /******************************************************************************
6605 * ConfigurePortW (WINSPOOL.@)
6607 * Display the Configuration-Dialog for a specific Port
6610 * pName [I] Servername or NULL (local Computer)
6611 * hWnd [I] Handle to parent Window for the Dialog-Box
6612 * pPortName [I] Name of the Port, that should be configured
6619 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6625 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6627 if (pName
&& pName
[0]) {
6628 SetLastError(ERROR_INVALID_PARAMETER
);
6633 SetLastError(RPC_X_NULL_REF_POINTER
);
6637 /* an empty Portname is Invalid, but can popup a Dialog */
6638 if (!pPortName
[0]) {
6639 SetLastError(ERROR_NOT_SUPPORTED
);
6643 pm
= monitor_load_by_port(pPortName
);
6644 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
6645 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
6646 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
6647 TRACE("got %d with %u\n", res
, GetLastError());
6651 pui
= monitor_loadui(pm
);
6652 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
6653 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
6654 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
6655 TRACE("got %d with %u\n", res
, GetLastError());
6659 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
6660 pm
, debugstr_w(pm
? pm
->dllname
: NULL
), pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
6662 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6663 SetLastError(ERROR_NOT_SUPPORTED
);
6666 monitor_unload(pui
);
6670 TRACE("returning %d with %u\n", res
, GetLastError());
6674 /******************************************************************************
6675 * ConnectToPrinterDlg (WINSPOOL.@)
6677 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6679 FIXME("%p %x\n", hWnd
, Flags
);
6683 /******************************************************************************
6684 * DeletePrinterConnectionA (WINSPOOL.@)
6686 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6688 FIXME("%s\n", debugstr_a(pName
));
6692 /******************************************************************************
6693 * DeletePrinterConnectionW (WINSPOOL.@)
6695 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6697 FIXME("%s\n", debugstr_w(pName
));
6701 /******************************************************************************
6702 * DeletePrinterDriverExW (WINSPOOL.@)
6704 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6705 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6710 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6711 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6713 if(pName
&& pName
[0])
6715 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6716 SetLastError(ERROR_INVALID_PARAMETER
);
6722 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6723 SetLastError(ERROR_INVALID_PARAMETER
);
6727 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
6731 ERR("Can't open drivers key\n");
6735 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6738 RegCloseKey(hkey_drivers
);
6743 /******************************************************************************
6744 * DeletePrinterDriverExA (WINSPOOL.@)
6746 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6747 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6749 UNICODE_STRING NameW
, EnvW
, DriverW
;
6752 asciitounicode(&NameW
, pName
);
6753 asciitounicode(&EnvW
, pEnvironment
);
6754 asciitounicode(&DriverW
, pDriverName
);
6756 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6758 RtlFreeUnicodeString(&DriverW
);
6759 RtlFreeUnicodeString(&EnvW
);
6760 RtlFreeUnicodeString(&NameW
);
6765 /******************************************************************************
6766 * DeletePrinterDataExW (WINSPOOL.@)
6768 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6771 FIXME("%p %s %s\n", hPrinter
,
6772 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6773 return ERROR_INVALID_PARAMETER
;
6776 /******************************************************************************
6777 * DeletePrinterDataExA (WINSPOOL.@)
6779 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6782 FIXME("%p %s %s\n", hPrinter
,
6783 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6784 return ERROR_INVALID_PARAMETER
;
6787 /******************************************************************************
6788 * DeletePrintProcessorA (WINSPOOL.@)
6790 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6792 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6793 debugstr_a(pPrintProcessorName
));
6797 /******************************************************************************
6798 * DeletePrintProcessorW (WINSPOOL.@)
6800 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6802 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6803 debugstr_w(pPrintProcessorName
));
6807 /******************************************************************************
6808 * DeletePrintProvidorA (WINSPOOL.@)
6810 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6812 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6813 debugstr_a(pPrintProviderName
));
6817 /******************************************************************************
6818 * DeletePrintProvidorW (WINSPOOL.@)
6820 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6822 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6823 debugstr_w(pPrintProviderName
));
6827 /******************************************************************************
6828 * EnumFormsA (WINSPOOL.@)
6830 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6831 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6833 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6834 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6838 /******************************************************************************
6839 * EnumFormsW (WINSPOOL.@)
6841 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6842 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6844 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6845 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6849 /*****************************************************************************
6850 * EnumMonitorsA [WINSPOOL.@]
6852 * See EnumMonitorsW.
6855 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6856 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6859 LPBYTE bufferW
= NULL
;
6860 LPWSTR nameW
= NULL
;
6862 DWORD numentries
= 0;
6865 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6866 cbBuf
, pcbNeeded
, pcReturned
);
6868 /* convert servername to unicode */
6870 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6871 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6872 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6874 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6875 needed
= cbBuf
* sizeof(WCHAR
);
6876 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6877 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6879 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6880 if (pcbNeeded
) needed
= *pcbNeeded
;
6881 /* HeapReAlloc return NULL, when bufferW was NULL */
6882 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6883 HeapAlloc(GetProcessHeap(), 0, needed
);
6885 /* Try again with the large Buffer */
6886 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6888 numentries
= pcReturned
? *pcReturned
: 0;
6891 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6892 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6895 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6896 DWORD entrysize
= 0;
6899 LPMONITOR_INFO_2W mi2w
;
6900 LPMONITOR_INFO_2A mi2a
;
6902 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6903 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6905 /* First pass: calculate the size for all Entries */
6906 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6907 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6909 while (index
< numentries
) {
6911 needed
+= entrysize
; /* MONITOR_INFO_?A */
6912 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6914 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6915 NULL
, 0, NULL
, NULL
);
6917 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6918 NULL
, 0, NULL
, NULL
);
6919 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6920 NULL
, 0, NULL
, NULL
);
6922 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6923 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6924 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6927 /* check for errors and quit on failure */
6928 if (cbBuf
< needed
) {
6929 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6933 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6934 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6935 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6936 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6937 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6939 /* Second Pass: Fill the User Buffer (if we have one) */
6940 while ((index
< numentries
) && pMonitors
) {
6942 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6944 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6945 ptr
, cbBuf
, NULL
, NULL
);
6949 mi2a
->pEnvironment
= ptr
;
6950 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6951 ptr
, cbBuf
, NULL
, NULL
);
6955 mi2a
->pDLLName
= ptr
;
6956 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6957 ptr
, cbBuf
, NULL
, NULL
);
6961 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6962 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6963 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6967 if (pcbNeeded
) *pcbNeeded
= needed
;
6968 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6970 HeapFree(GetProcessHeap(), 0, nameW
);
6971 HeapFree(GetProcessHeap(), 0, bufferW
);
6973 TRACE("returning %d with %d (%d byte for %d entries)\n",
6974 (res
), GetLastError(), needed
, numentries
);
6980 /*****************************************************************************
6981 * EnumMonitorsW [WINSPOOL.@]
6983 * Enumerate available Port-Monitors
6986 * pName [I] Servername or NULL (local Computer)
6987 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6988 * pMonitors [O] PTR to Buffer that receives the Result
6989 * cbBuf [I] Size of Buffer at pMonitors
6990 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6991 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6995 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6998 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6999 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7002 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7003 cbBuf
, pcbNeeded
, pcReturned
);
7005 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7007 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
7008 SetLastError(RPC_X_NULL_REF_POINTER
);
7012 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
7015 /******************************************************************************
7016 * SpoolerInit (WINSPOOL.@)
7018 * Initialize the Spooler
7025 * The function fails on windows, when the spooler service is not running
7028 BOOL WINAPI
SpoolerInit(void)
7031 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7035 /******************************************************************************
7036 * XcvDataW (WINSPOOL.@)
7038 * Execute commands in the Printmonitor DLL
7041 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7042 * pszDataName [i] Name of the command to execute
7043 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7044 * cbInputData [i] Size in Bytes of Buffer at pInputData
7045 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7046 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7047 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7048 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7055 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7056 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7058 * Minimal List of commands, that a Printmonitor DLL should support:
7060 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7061 *| "AddPort" : Add a Port
7062 *| "DeletePort": Delete a Port
7064 * Many Printmonitors support additional commands. Examples for localspl.dll:
7065 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7066 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7069 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7070 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7071 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7073 opened_printer_t
*printer
;
7075 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7076 pInputData
, cbInputData
, pOutputData
,
7077 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7079 printer
= get_opened_printer(hXcv
);
7080 if (!printer
|| (!printer
->hXcv
)) {
7081 SetLastError(ERROR_INVALID_HANDLE
);
7085 if (!pcbOutputNeeded
) {
7086 SetLastError(ERROR_INVALID_PARAMETER
);
7090 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7091 SetLastError(RPC_X_NULL_REF_POINTER
);
7095 *pcbOutputNeeded
= 0;
7097 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
7098 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
7103 /*****************************************************************************
7104 * EnumPrinterDataA [WINSPOOL.@]
7107 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7108 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7109 DWORD cbData
, LPDWORD pcbData
)
7111 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7112 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7113 return ERROR_NO_MORE_ITEMS
;
7116 /*****************************************************************************
7117 * EnumPrinterDataW [WINSPOOL.@]
7120 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7121 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7122 DWORD cbData
, LPDWORD pcbData
)
7124 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7125 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7126 return ERROR_NO_MORE_ITEMS
;
7129 /*****************************************************************************
7130 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7133 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7134 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7135 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7137 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7138 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7139 pcbNeeded
, pcReturned
);
7143 /*****************************************************************************
7144 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7147 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7148 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7149 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7151 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7152 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7153 pcbNeeded
, pcReturned
);
7157 /*****************************************************************************
7158 * EnumPrintProcessorsA [WINSPOOL.@]
7161 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7162 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7164 FIXME("Stub: %s %s %d %p %d %p %p\n", pName
, pEnvironment
, Level
,
7165 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
7169 /*****************************************************************************
7170 * EnumPrintProcessorsW [WINSPOOL.@]
7173 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7174 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7176 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7177 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
7178 cbBuf
, pcbNeeded
, pcbReturned
);
7182 /*****************************************************************************
7183 * ExtDeviceMode [WINSPOOL.@]
7186 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7187 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7190 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7191 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7192 debugstr_a(pProfile
), fMode
);
7196 /*****************************************************************************
7197 * FindClosePrinterChangeNotification [WINSPOOL.@]
7200 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7202 FIXME("Stub: %p\n", hChange
);
7206 /*****************************************************************************
7207 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7210 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7211 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7213 FIXME("Stub: %p %x %x %p\n",
7214 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7215 return INVALID_HANDLE_VALUE
;
7218 /*****************************************************************************
7219 * FindNextPrinterChangeNotification [WINSPOOL.@]
7222 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7223 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7225 FIXME("Stub: %p %p %p %p\n",
7226 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7230 /*****************************************************************************
7231 * FreePrinterNotifyInfo [WINSPOOL.@]
7234 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7236 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7240 /*****************************************************************************
7243 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7244 * ansi depending on the unicode parameter.
7246 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7256 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7259 memcpy(ptr
, str
, *size
);
7266 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7269 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7276 /*****************************************************************************
7279 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7280 LPDWORD pcbNeeded
, BOOL unicode
)
7282 DWORD size
, left
= cbBuf
;
7283 BOOL space
= (cbBuf
> 0);
7290 ji1
->JobId
= job
->job_id
;
7293 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7294 if(space
&& size
<= left
)
7296 ji1
->pDocument
= (LPWSTR
)ptr
;
7307 /*****************************************************************************
7310 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7311 LPDWORD pcbNeeded
, BOOL unicode
)
7313 DWORD size
, left
= cbBuf
;
7314 BOOL space
= (cbBuf
> 0);
7321 ji2
->JobId
= job
->job_id
;
7324 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7325 if(space
&& size
<= left
)
7327 ji2
->pDocument
= (LPWSTR
)ptr
;
7338 /*****************************************************************************
7341 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7342 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7345 DWORD needed
= 0, size
;
7349 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7351 EnterCriticalSection(&printer_handles_cs
);
7352 job
= get_job(hPrinter
, JobId
);
7359 size
= sizeof(JOB_INFO_1W
);
7364 memset(pJob
, 0, size
);
7368 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7373 size
= sizeof(JOB_INFO_2W
);
7378 memset(pJob
, 0, size
);
7382 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7387 size
= sizeof(JOB_INFO_3
);
7391 memset(pJob
, 0, size
);
7400 SetLastError(ERROR_INVALID_LEVEL
);
7404 *pcbNeeded
= needed
;
7406 LeaveCriticalSection(&printer_handles_cs
);
7410 /*****************************************************************************
7411 * GetJobA [WINSPOOL.@]
7414 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7415 DWORD cbBuf
, LPDWORD pcbNeeded
)
7417 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7420 /*****************************************************************************
7421 * GetJobW [WINSPOOL.@]
7424 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7425 DWORD cbBuf
, LPDWORD pcbNeeded
)
7427 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7430 /*****************************************************************************
7433 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7435 char *unixname
, *queue
, *cmd
;
7436 char fmt
[] = "lpr -P%s %s";
7440 if(!(unixname
= wine_get_unix_file_name(filename
)))
7443 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7444 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7445 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7447 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7448 sprintf(cmd
, fmt
, queue
, unixname
);
7450 TRACE("printing with: %s\n", cmd
);
7453 HeapFree(GetProcessHeap(), 0, cmd
);
7454 HeapFree(GetProcessHeap(), 0, queue
);
7455 HeapFree(GetProcessHeap(), 0, unixname
);
7459 /*****************************************************************************
7462 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7464 #ifdef SONAME_LIBCUPS
7467 char *unixname
, *queue
, *unix_doc_title
;
7471 if(!(unixname
= wine_get_unix_file_name(filename
)))
7474 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7475 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7476 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7478 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7479 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
7480 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
7482 TRACE("printing via cups\n");
7483 ret
= pcupsPrintFile(queue
, unixname
, unix_doc_title
, 0, NULL
);
7484 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
7485 HeapFree(GetProcessHeap(), 0, queue
);
7486 HeapFree(GetProcessHeap(), 0, unixname
);
7492 return schedule_lpr(printer_name
, filename
);
7496 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7503 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7507 if(HIWORD(wparam
) == BN_CLICKED
)
7509 if(LOWORD(wparam
) == IDOK
)
7512 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7515 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7516 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7518 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7520 WCHAR caption
[200], message
[200];
7523 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7524 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7525 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7526 if(mb_ret
== IDCANCEL
)
7528 HeapFree(GetProcessHeap(), 0, filename
);
7532 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7533 if(hf
== INVALID_HANDLE_VALUE
)
7535 WCHAR caption
[200], message
[200];
7537 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7538 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7539 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7540 HeapFree(GetProcessHeap(), 0, filename
);
7544 DeleteFileW(filename
);
7545 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7547 EndDialog(hwnd
, IDOK
);
7550 if(LOWORD(wparam
) == IDCANCEL
)
7552 EndDialog(hwnd
, IDCANCEL
);
7561 /*****************************************************************************
7564 static BOOL
get_filename(LPWSTR
*filename
)
7566 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7567 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7570 /*****************************************************************************
7573 static BOOL
schedule_file(LPCWSTR filename
)
7575 LPWSTR output
= NULL
;
7577 if(get_filename(&output
))
7580 TRACE("copy to %s\n", debugstr_w(output
));
7581 r
= CopyFileW(filename
, output
, FALSE
);
7582 HeapFree(GetProcessHeap(), 0, output
);
7588 /*****************************************************************************
7591 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7594 char *unixname
, *cmdA
;
7596 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7600 if(!(unixname
= wine_get_unix_file_name(filename
)))
7603 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7604 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7605 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7607 TRACE("printing with: %s\n", cmdA
);
7609 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7614 ERR("pipe() failed!\n");
7624 /* reset signals that we previously set to SIG_IGN */
7625 signal(SIGPIPE
, SIG_DFL
);
7626 signal(SIGCHLD
, SIG_DFL
);
7628 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
7632 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7633 write(fds
[1], buf
, no_read
);
7638 if(file_fd
!= -1) close(file_fd
);
7639 if(fds
[0] != -1) close(fds
[0]);
7640 if(fds
[1] != -1) close(fds
[1]);
7642 HeapFree(GetProcessHeap(), 0, cmdA
);
7643 HeapFree(GetProcessHeap(), 0, unixname
);
7650 /*****************************************************************************
7653 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7655 int in_fd
, out_fd
, no_read
;
7658 char *unixname
, *outputA
;
7661 if(!(unixname
= wine_get_unix_file_name(filename
)))
7664 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7665 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7666 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7668 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7669 in_fd
= open(unixname
, O_RDONLY
);
7670 if(out_fd
== -1 || in_fd
== -1)
7673 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7674 write(out_fd
, buf
, no_read
);
7678 if(in_fd
!= -1) close(in_fd
);
7679 if(out_fd
!= -1) close(out_fd
);
7680 HeapFree(GetProcessHeap(), 0, outputA
);
7681 HeapFree(GetProcessHeap(), 0, unixname
);
7685 /*****************************************************************************
7686 * ScheduleJob [WINSPOOL.@]
7689 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7691 opened_printer_t
*printer
;
7693 struct list
*cursor
, *cursor2
;
7695 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7696 EnterCriticalSection(&printer_handles_cs
);
7697 printer
= get_opened_printer(hPrinter
);
7701 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7703 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7706 if(job
->job_id
!= dwJobID
) continue;
7708 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7709 if(hf
!= INVALID_HANDLE_VALUE
)
7711 PRINTER_INFO_5W
*pi5
;
7715 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7716 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7718 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7719 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7720 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7721 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7722 debugstr_w(pi5
->pPortName
));
7726 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7727 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7729 DWORD type
, count
= sizeof(output
);
7730 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
7733 if(output
[0] == '|')
7735 ret
= schedule_pipe(output
+ 1, job
->filename
);
7739 ret
= schedule_unixfile(output
, job
->filename
);
7741 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
7743 ret
= schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
7745 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
7747 ret
= schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7749 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
7751 ret
= schedule_file(job
->filename
);
7755 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
7757 HeapFree(GetProcessHeap(), 0, pi5
);
7759 DeleteFileW(job
->filename
);
7761 list_remove(cursor
);
7762 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7763 HeapFree(GetProcessHeap(), 0, job
->filename
);
7764 HeapFree(GetProcessHeap(), 0, job
);
7768 LeaveCriticalSection(&printer_handles_cs
);
7772 /*****************************************************************************
7773 * StartDocDlgA [WINSPOOL.@]
7775 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7777 UNICODE_STRING usBuffer
;
7780 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7783 docW
.cbSize
= sizeof(docW
);
7784 if (doc
->lpszDocName
)
7786 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7787 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7789 if (doc
->lpszOutput
)
7791 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7792 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7794 if (doc
->lpszDatatype
)
7796 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7797 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7799 docW
.fwType
= doc
->fwType
;
7801 retW
= StartDocDlgW(hPrinter
, &docW
);
7805 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7806 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7807 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7808 HeapFree(GetProcessHeap(), 0, retW
);
7811 HeapFree(GetProcessHeap(), 0, datatypeW
);
7812 HeapFree(GetProcessHeap(), 0, outputW
);
7813 HeapFree(GetProcessHeap(), 0, docnameW
);
7818 /*****************************************************************************
7819 * StartDocDlgW [WINSPOOL.@]
7821 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7822 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7823 * port is "FILE:". Also returns the full path if passed a relative path.
7825 * The caller should free the returned string from the process heap.
7827 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7832 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7834 PRINTER_INFO_5W
*pi5
;
7835 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7836 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7838 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7839 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7840 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7842 HeapFree(GetProcessHeap(), 0, pi5
);
7845 HeapFree(GetProcessHeap(), 0, pi5
);
7848 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7852 if (get_filename(&name
))
7854 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7856 HeapFree(GetProcessHeap(), 0, name
);
7859 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7860 GetFullPathNameW(name
, len
, ret
, NULL
);
7861 HeapFree(GetProcessHeap(), 0, name
);
7866 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7869 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7870 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7872 attr
= GetFileAttributesW(ret
);
7873 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7875 HeapFree(GetProcessHeap(), 0, ret
);