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 /* ############################### */
114 HANDLE backend_printer
;
123 WCHAR
*document_title
;
131 LPCWSTR versionregpath
;
132 LPCWSTR versionsubdir
;
135 /* ############################### */
137 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
138 static monitor_t
* pm_localport
;
140 static opened_printer_t
**printer_handles
;
141 static UINT nb_printer_handles
;
142 static LONG next_job_id
= 1;
144 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
145 WORD fwCapability
, LPSTR lpszOutput
,
147 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
148 LPSTR lpszDevice
, LPSTR lpszPort
,
149 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
152 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
153 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
154 'c','o','n','t','r','o','l','\\',
155 'P','r','i','n','t','\\',
156 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
157 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
159 static const WCHAR MonitorsW
[] = { 'S','y','s','t','e','m','\\',
160 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
161 'C','o','n','t','r','o','l','\\',
162 'P','r','i','n','t','\\',
163 'M','o','n','i','t','o','r','s','\\',0};
165 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
166 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
167 'C','o','n','t','r','o','l','\\',
168 'P','r','i','n','t','\\',
169 'P','r','i','n','t','e','r','s',0};
171 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
173 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
174 'M','i','c','r','o','s','o','f','t','\\',
175 'W','i','n','d','o','w','s',' ','N','T','\\',
176 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
177 'W','i','n','d','o','w','s',0};
179 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
180 'M','i','c','r','o','s','o','f','t','\\',
181 'W','i','n','d','o','w','s',' ','N','T','\\',
182 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
183 'D','e','v','i','c','e','s',0};
185 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
186 'M','i','c','r','o','s','o','f','t','\\',
187 'W','i','n','d','o','w','s',' ','N','T','\\',
188 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
189 'P','o','r','t','s',0};
191 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
192 'M','i','c','r','o','s','o','f','t','\\',
193 'W','i','n','d','o','w','s',' ','N','T','\\',
194 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
195 'P','r','i','n','t','e','r','P','o','r','t','s',0};
197 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
198 static const WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
199 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
200 static const WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
201 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
202 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
203 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
204 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
205 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
206 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
207 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
209 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
210 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
212 static const WCHAR backslashW
[] = {'\\',0};
213 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
214 'i','o','n',' ','F','i','l','e',0};
215 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
216 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
217 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
218 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
219 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
220 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
221 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
222 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
223 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
224 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
225 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
226 static const WCHAR MonitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
227 static const WCHAR NameW
[] = {'N','a','m','e',0};
228 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
229 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
230 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
231 static const WCHAR PortW
[] = {'P','o','r','t',0};
232 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
233 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
234 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
235 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
236 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
237 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
238 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
239 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
240 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
241 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
242 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
243 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
244 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
245 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
246 static const WCHAR emptyStringW
[] = {0};
247 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
248 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
250 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
252 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
253 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
254 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
256 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
257 'D','o','c','u','m','e','n','t',0};
259 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
260 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
261 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
262 0, sizeof(DRIVER_INFO_8W
)};
265 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
266 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
267 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
268 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
269 sizeof(PRINTER_INFO_9W
)};
271 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
272 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
273 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
275 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
277 /******************************************************************
278 * validate the user-supplied printing-environment [internal]
281 * env [I] PTR to Environment-String or NULL
285 * Success: PTR to printenv_t
288 * An empty string is handled the same way as NULL.
289 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
293 static const printenv_t
* validate_envW(LPCWSTR env
)
295 const printenv_t
*result
= NULL
;
298 TRACE("testing %s\n", debugstr_w(env
));
301 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
303 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
305 result
= all_printenv
[i
];
310 if (result
== NULL
) {
311 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
312 SetLastError(ERROR_INVALID_ENVIRONMENT
);
314 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
318 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
320 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
326 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
327 if passed a NULL string. This returns NULLs to the result.
329 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
333 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
334 return usBufferPtr
->Buffer
;
336 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
340 static LPWSTR
strdupW(LPCWSTR p
)
346 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
347 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
352 static LPSTR
strdupWtoA( LPCWSTR str
)
357 if (!str
) return NULL
;
358 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
359 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
360 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
364 /******************************************************************
365 * Return the number of bytes for an multi_sz string.
366 * The result includes all \0s
367 * (specifically the extra \0, that is needed as multi_sz terminator).
370 static int multi_sz_lenW(const WCHAR
*str
)
372 const WCHAR
*ptr
= str
;
376 ptr
+= lstrlenW(ptr
) + 1;
379 return (ptr
- str
+ 1) * sizeof(WCHAR
);
382 /* ################################ */
384 static int multi_sz_lenA(const char *str
)
386 const char *ptr
= str
;
390 ptr
+= lstrlenA(ptr
) + 1;
393 return ptr
- str
+ 1;
397 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
400 /* If forcing, or no profile string entry for device yet, set the entry
402 * The always change entry if not WINEPS yet is discussable.
405 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
407 !strstr(qbuf
,"WINEPS.DRV")
409 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
412 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
413 WriteProfileStringA("windows","device",buf
);
414 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
415 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
418 HeapFree(GetProcessHeap(),0,buf
);
422 static BOOL
add_printer_driver(const char *name
)
426 static char driver_9x
[] = "wineps16.drv",
427 driver_nt
[] = "wineps.drv",
428 env_9x
[] = "Windows 4.0",
429 env_nt
[] = "Windows NT x86",
430 data_file
[] = "generic.ppd",
431 default_data_type
[] = "RAW";
433 ZeroMemory(&di3a
, sizeof(DRIVER_INFO_3A
));
435 di3a
.pName
= (char *)name
;
436 di3a
.pEnvironment
= env_nt
;
437 di3a
.pDriverPath
= driver_nt
;
438 di3a
.pDataFile
= data_file
;
439 di3a
.pConfigFile
= driver_nt
;
440 di3a
.pDefaultDataType
= default_data_type
;
442 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
443 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
446 di3a
.pEnvironment
= env_9x
;
447 di3a
.pDriverPath
= driver_9x
;
448 di3a
.pConfigFile
= driver_9x
;
449 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
450 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
455 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a
.pDriverPath
),
456 debugstr_a(di3a
.pEnvironment
), GetLastError());
460 #ifdef SONAME_LIBCUPS
461 static typeof(cupsFreeDests
) *pcupsFreeDests
;
462 static typeof(cupsGetDests
) *pcupsGetDests
;
463 static typeof(cupsGetPPD
) *pcupsGetPPD
;
464 static typeof(cupsPrintFile
) *pcupsPrintFile
;
465 static void *cupshandle
;
467 static BOOL
CUPS_LoadPrinters(void)
470 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
472 PRINTER_INFO_2A pinfo2a
;
474 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
477 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
479 TRACE("%s\n", loaderror
);
482 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
485 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
486 if (!p##x) return FALSE;
488 DYNCUPS(cupsFreeDests
);
490 DYNCUPS(cupsGetDests
);
491 DYNCUPS(cupsPrintFile
);
494 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
496 ERR("Can't create Printers key\n");
500 nrofdests
= pcupsGetDests(&dests
);
501 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
502 for (i
=0;i
<nrofdests
;i
++) {
503 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
504 port
= HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests
[i
].name
)+1);
505 sprintf(port
,"LPR:%s", dests
[i
].name
);
506 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
507 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port
));
508 sprintf(devline
, "WINEPS.DRV,%s", port
);
509 WriteProfileStringA("devices", dests
[i
].name
, devline
);
510 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
511 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
515 lstrcatA(devline
, ",15,45");
516 WriteProfileStringA("PrinterPorts", dests
[i
].name
, devline
);
517 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
518 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
522 HeapFree(GetProcessHeap(), 0, devline
);
524 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
525 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
526 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
528 TRACE("Printer already exists\n");
529 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
530 RegCloseKey(hkeyPrinter
);
532 static CHAR data_type
[] = "RAW",
533 print_proc
[] = "WinPrint",
534 comment
[] = "WINEPS Printer using CUPS",
535 location
[] = "<physical location of printer>",
536 params
[] = "<parameters?>",
537 share_name
[] = "<share name?>",
538 sep_file
[] = "<sep file?>";
540 add_printer_driver(dests
[i
].name
);
542 memset(&pinfo2a
,0,sizeof(pinfo2a
));
543 pinfo2a
.pPrinterName
= dests
[i
].name
;
544 pinfo2a
.pDatatype
= data_type
;
545 pinfo2a
.pPrintProcessor
= print_proc
;
546 pinfo2a
.pDriverName
= dests
[i
].name
;
547 pinfo2a
.pComment
= comment
;
548 pinfo2a
.pLocation
= location
;
549 pinfo2a
.pPortName
= port
;
550 pinfo2a
.pParameters
= params
;
551 pinfo2a
.pShareName
= share_name
;
552 pinfo2a
.pSepFile
= sep_file
;
554 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
555 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
556 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
559 HeapFree(GetProcessHeap(),0,port
);
562 if (dests
[i
].is_default
) {
563 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
567 if (hadprinter
& !haddefault
)
568 WINSPOOL_SetDefaultPrinter(dests
[0].name
, dests
[0].name
, TRUE
);
569 pcupsFreeDests(nrofdests
, dests
);
570 RegCloseKey(hkeyPrinters
);
576 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
577 PRINTER_INFO_2A pinfo2a
;
578 char *e
,*s
,*name
,*prettyname
,*devname
;
579 BOOL ret
= FALSE
, set_default
= FALSE
;
580 char *port
= NULL
, *devline
,*env_default
;
581 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
583 while (isspace(*pent
)) pent
++;
584 s
= strchr(pent
,':');
586 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
594 TRACE("name=%s entry=%s\n",name
, pent
);
596 if(ispunct(*name
)) { /* a tc entry, not a real printer */
597 TRACE("skipping tc entry\n");
601 if(strstr(pent
,":server")) { /* server only version so skip */
602 TRACE("skipping server entry\n");
606 /* Determine whether this is a postscript printer. */
609 env_default
= getenv("PRINTER");
611 /* Get longest name, usually the one at the right for later display. */
612 while((s
=strchr(prettyname
,'|'))) {
615 while(isspace(*--e
)) *e
= '\0';
616 TRACE("\t%s\n", debugstr_a(prettyname
));
617 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
618 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
621 e
= prettyname
+ strlen(prettyname
);
622 while(isspace(*--e
)) *e
= '\0';
623 TRACE("\t%s\n", debugstr_a(prettyname
));
624 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
626 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
627 * if it is too long, we use it as comment below. */
628 devname
= prettyname
;
629 if (strlen(devname
)>=CCHDEVICENAME
-1)
631 if (strlen(devname
)>=CCHDEVICENAME
-1) {
636 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
637 sprintf(port
,"LPR:%s",name
);
639 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
640 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port
));
641 sprintf(devline
, "WINEPS.DRV,%s", port
);
642 WriteProfileStringA("devices", devname
, devline
);
643 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
644 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
648 lstrcatA(devline
, ",15,45");
649 WriteProfileStringA("PrinterPorts", devname
, devline
);
650 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
651 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
655 HeapFree(GetProcessHeap(),0,devline
);
657 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
659 ERR("Can't create Printers key\n");
663 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
664 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
666 TRACE("Printer already exists\n");
667 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
668 RegCloseKey(hkeyPrinter
);
670 static CHAR data_type
[] = "RAW",
671 print_proc
[] = "WinPrint",
672 comment
[] = "WINEPS Printer using LPR",
673 params
[] = "<parameters?>",
674 share_name
[] = "<share name?>",
675 sep_file
[] = "<sep file?>";
677 add_printer_driver(devname
);
679 memset(&pinfo2a
,0,sizeof(pinfo2a
));
680 pinfo2a
.pPrinterName
= devname
;
681 pinfo2a
.pDatatype
= data_type
;
682 pinfo2a
.pPrintProcessor
= print_proc
;
683 pinfo2a
.pDriverName
= devname
;
684 pinfo2a
.pComment
= comment
;
685 pinfo2a
.pLocation
= prettyname
;
686 pinfo2a
.pPortName
= port
;
687 pinfo2a
.pParameters
= params
;
688 pinfo2a
.pShareName
= share_name
;
689 pinfo2a
.pSepFile
= sep_file
;
691 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
692 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
693 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
696 RegCloseKey(hkeyPrinters
);
698 if (isfirst
|| set_default
)
699 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
702 HeapFree(GetProcessHeap(), 0, port
);
703 HeapFree(GetProcessHeap(), 0, name
);
708 PRINTCAP_LoadPrinters(void) {
709 BOOL hadprinter
= FALSE
;
713 BOOL had_bash
= FALSE
;
715 f
= fopen("/etc/printcap","r");
719 while(fgets(buf
,sizeof(buf
),f
)) {
722 end
=strchr(buf
,'\n');
726 while(isspace(*start
)) start
++;
727 if(*start
== '#' || *start
== '\0')
730 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
731 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
732 HeapFree(GetProcessHeap(),0,pent
);
736 if (end
&& *--end
== '\\') {
743 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
746 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
752 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
753 HeapFree(GetProcessHeap(),0,pent
);
759 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
762 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
763 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
765 return ERROR_FILE_NOT_FOUND
;
768 /******************************************************************
769 * monitor_unload [internal]
771 * release a printmonitor and unload it from memory, when needed
774 static void monitor_unload(monitor_t
* pm
)
776 if (pm
== NULL
) return;
777 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
779 EnterCriticalSection(&monitor_handles_cs
);
781 if (pm
->refcount
) pm
->refcount
--;
783 if (pm
->refcount
== 0) {
784 list_remove(&pm
->entry
);
785 FreeLibrary(pm
->hdll
);
786 HeapFree(GetProcessHeap(), 0, pm
->name
);
787 HeapFree(GetProcessHeap(), 0, pm
->dllname
);
788 HeapFree(GetProcessHeap(), 0, pm
);
790 LeaveCriticalSection(&monitor_handles_cs
);
793 /******************************************************************
794 * monitor_load [internal]
796 * load a printmonitor, get the dllname from the registry, when needed
797 * initialize the monitor and dump found function-pointers
799 * On failure, SetLastError() is called and NULL is returned
802 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
804 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
805 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
806 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
807 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
808 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
810 monitor_t
* pm
= NULL
;
812 LPWSTR regroot
= NULL
;
813 LPWSTR driver
= dllname
;
815 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
816 /* Is the Monitor already loaded? */
817 EnterCriticalSection(&monitor_handles_cs
);
820 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
822 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
830 pm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(monitor_t
));
831 if (pm
== NULL
) goto cleanup
;
832 list_add_tail(&monitor_handles
, &pm
->entry
);
836 if (pm
->name
== NULL
) {
837 /* Load the monitor */
838 LPMONITOREX pmonitorEx
;
842 len
= lstrlenW(MonitorsW
) + lstrlenW(name
) + 2;
843 regroot
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
847 lstrcpyW(regroot
, MonitorsW
);
848 lstrcatW(regroot
, name
);
849 /* Get the Driver from the Registry */
850 if (driver
== NULL
) {
853 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
854 if (RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, NULL
,
855 &namesize
) == ERROR_SUCCESS
) {
856 driver
= HeapAlloc(GetProcessHeap(), 0, namesize
);
857 RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
864 pm
->name
= strdupW(name
);
865 pm
->dllname
= strdupW(driver
);
867 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
869 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
874 pm
->hdll
= LoadLibraryW(driver
);
875 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
877 if (pm
->hdll
== NULL
) {
879 SetLastError(ERROR_MOD_NOT_FOUND
);
884 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
885 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
886 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
887 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
888 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
891 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
892 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
893 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
894 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
895 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
897 if (pInitializePrintMonitorUI
!= NULL
) {
898 pm
->monitorUI
= pInitializePrintMonitorUI();
899 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
901 TRACE( "0x%08x: dwMonitorSize (%d)\n",
902 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
907 if (pInitializePrintMonitor
&& regroot
) {
908 pmonitorEx
= pInitializePrintMonitor(regroot
);
909 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
910 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
913 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
914 pm
->monitor
= &(pmonitorEx
->Monitor
);
919 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
923 if (!pm
->monitor
&& regroot
) {
924 if (pInitializePrintMonitor2
!= NULL
) {
925 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
927 if (pInitializeMonitorEx
!= NULL
) {
928 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
930 if (pInitializeMonitor
!= NULL
) {
931 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
934 if (!pm
->monitor
&& !pm
->monitorUI
) {
936 SetLastError(ERROR_PROC_NOT_FOUND
);
941 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, LocalPortW
) == 0)) {
945 LeaveCriticalSection(&monitor_handles_cs
);
946 if (driver
!= dllname
) HeapFree(GetProcessHeap(), 0, driver
);
947 HeapFree(GetProcessHeap(), 0, regroot
);
948 TRACE("=> %p\n", pm
);
952 /******************************************************************
953 * monitor_loadui [internal]
955 * load the userinterface-dll for a given portmonitor
957 * On failure, NULL is returned
960 static monitor_t
* monitor_loadui(monitor_t
* pm
)
962 monitor_t
* pui
= NULL
;
963 LPWSTR buffer
[MAX_PATH
];
968 if (pm
== NULL
) return NULL
;
969 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
971 /* Try the Portmonitor first; works for many monitors */
973 EnterCriticalSection(&monitor_handles_cs
);
975 LeaveCriticalSection(&monitor_handles_cs
);
979 /* query the userinterface-dllname from the Portmonitor */
980 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
981 /* building (",XcvMonitor %s",pm->name) not needed yet */
982 res
= pm
->monitor
->pfnXcvOpenPort(emptyStringW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
983 TRACE("got %u with %p\n", res
, hXcv
);
985 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, MonitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
986 TRACE("got %u with %s\n", res
, debugstr_w((LPWSTR
) buffer
));
987 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, (LPWSTR
) buffer
);
988 pm
->monitor
->pfnXcvClosePort(hXcv
);
995 /******************************************************************
996 * monitor_load_by_port [internal]
998 * load a printmonitor for a given port
1000 * On failure, NULL is returned
1003 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
1008 monitor_t
* pm
= NULL
;
1009 DWORD registered
= 0;
1013 TRACE("(%s)\n", debugstr_w(portname
));
1015 /* Try the Local Monitor first */
1016 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
) == ERROR_SUCCESS
) {
1017 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
1018 /* found the portname */
1020 return monitor_load(LocalPortW
, NULL
);
1025 len
= MAX_PATH
+ lstrlenW(bs_Ports_bsW
) + lstrlenW(portname
) + 1;
1026 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1027 if (buffer
== NULL
) return NULL
;
1029 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
1030 EnterCriticalSection(&monitor_handles_cs
);
1031 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1033 while ((pm
== NULL
) && (id
< registered
)) {
1035 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
1036 TRACE("testing %s\n", debugstr_w(buffer
));
1037 len
= lstrlenW(buffer
);
1038 lstrcatW(buffer
, bs_Ports_bsW
);
1039 lstrcatW(buffer
, portname
);
1040 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
1042 buffer
[len
] = '\0'; /* use only the Monitor-Name */
1043 pm
= monitor_load(buffer
, NULL
);
1047 LeaveCriticalSection(&monitor_handles_cs
);
1050 HeapFree(GetProcessHeap(), 0, buffer
);
1054 /******************************************************************
1055 * get_servername_from_name (internal)
1057 * for an external server, a copy of the serverpart from the full name is returned
1060 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1064 WCHAR buffer
[MAX_PATH
];
1067 if (name
== NULL
) return NULL
;
1068 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1070 server
= strdupW(&name
[2]); /* skip over both backslash */
1071 if (server
== NULL
) return NULL
;
1073 /* strip '\' and the printername */
1074 ptr
= strchrW(server
, '\\');
1075 if (ptr
) ptr
[0] = '\0';
1077 TRACE("found %s\n", debugstr_w(server
));
1079 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1080 if (GetComputerNameW(buffer
, &len
)) {
1081 if (lstrcmpW(buffer
, server
) == 0) {
1082 /* The requested Servername is our computername */
1083 HeapFree(GetProcessHeap(), 0, server
);
1090 /******************************************************************
1091 * get_basename_from_name (internal)
1093 * skip over the serverpart from the full name
1096 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1098 if (name
== NULL
) return NULL
;
1099 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1100 /* skip over the servername and search for the following '\' */
1101 name
= strchrW(&name
[2], '\\');
1102 if ((name
) && (name
[1])) {
1103 /* found a separator ('\') followed by a name:
1104 skip over the separator and return the rest */
1109 /* no basename present (we found only a servername) */
1116 /******************************************************************
1117 * get_opened_printer_entry
1118 * Get the first place empty in the opened printer table
1121 * - pDefault is ignored
1123 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1125 UINT_PTR handle
= nb_printer_handles
, i
;
1126 jobqueue_t
*queue
= NULL
;
1127 opened_printer_t
*printer
= NULL
;
1129 LPCWSTR printername
;
1134 if ((backend
== NULL
) && !load_backend()) return NULL
;
1136 servername
= get_servername_from_name(name
);
1138 FIXME("server %s not supported\n", debugstr_w(servername
));
1139 HeapFree(GetProcessHeap(), 0, servername
);
1140 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1144 printername
= get_basename_from_name(name
);
1145 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1147 /* an empty printername is invalid */
1148 if (printername
&& (!printername
[0])) {
1149 SetLastError(ERROR_INVALID_PARAMETER
);
1153 EnterCriticalSection(&printer_handles_cs
);
1155 for (i
= 0; i
< nb_printer_handles
; i
++)
1157 if (!printer_handles
[i
])
1159 if(handle
== nb_printer_handles
)
1164 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1165 queue
= printer_handles
[i
]->queue
;
1169 if (handle
>= nb_printer_handles
)
1171 opened_printer_t
**new_array
;
1172 if (printer_handles
)
1173 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1174 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1176 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1177 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1184 printer_handles
= new_array
;
1185 nb_printer_handles
+= 16;
1188 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1194 /* get a printer handle from the backend */
1195 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
1200 /* clone the base name. This is NULL for the printserver */
1201 printer
->printername
= strdupW(printername
);
1203 /* clone the full name */
1204 printer
->name
= strdupW(name
);
1205 if (name
&& (!printer
->name
)) {
1211 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1212 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1213 /* OpenPrinter(",XcvMonitor " detected */
1214 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1215 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1216 if (printer
->pm
== NULL
) {
1217 SetLastError(ERROR_UNKNOWN_PORT
);
1224 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1225 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1226 /* OpenPrinter(",XcvPort " detected */
1227 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1228 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1229 if (printer
->pm
== NULL
) {
1230 SetLastError(ERROR_UNKNOWN_PORT
);
1238 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1239 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1240 pDefault
? pDefault
->DesiredAccess
: 0,
1243 if (printer
->hXcv
== NULL
) {
1244 SetLastError(ERROR_INVALID_PARAMETER
);
1251 /* Does the Printer exist? */
1252 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1253 ERR("Can't create Printers key\n");
1257 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1258 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1259 RegCloseKey(hkeyPrinters
);
1260 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1264 RegCloseKey(hkeyPrinter
);
1265 RegCloseKey(hkeyPrinters
);
1270 TRACE("using the local printserver\n");
1274 printer
->queue
= queue
;
1277 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1278 if (!printer
->queue
) {
1282 list_init(&printer
->queue
->jobs
);
1283 printer
->queue
->ref
= 0;
1285 InterlockedIncrement(&printer
->queue
->ref
);
1287 printer_handles
[handle
] = printer
;
1290 LeaveCriticalSection(&printer_handles_cs
);
1291 if (!handle
&& printer
) {
1292 /* Something failed: Free all resources */
1293 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1294 monitor_unload(printer
->pm
);
1295 HeapFree(GetProcessHeap(), 0, printer
->printername
);
1296 HeapFree(GetProcessHeap(), 0, printer
->name
);
1297 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1298 HeapFree(GetProcessHeap(), 0, printer
);
1301 return (HANDLE
)handle
;
1304 /******************************************************************
1305 * get_opened_printer
1306 * Get the pointer to the opened printer referred by the handle
1308 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
1310 UINT_PTR idx
= (UINT_PTR
)hprn
;
1311 opened_printer_t
*ret
= NULL
;
1313 EnterCriticalSection(&printer_handles_cs
);
1315 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
1316 ret
= printer_handles
[idx
- 1];
1318 LeaveCriticalSection(&printer_handles_cs
);
1322 /******************************************************************
1323 * get_opened_printer_name
1324 * Get the pointer to the opened printer name referred by the handle
1326 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
1328 opened_printer_t
*printer
= get_opened_printer(hprn
);
1329 if(!printer
) return NULL
;
1330 return printer
->name
;
1333 /******************************************************************
1334 * WINSPOOL_GetOpenedPrinterRegKey
1337 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
1339 LPCWSTR name
= get_opened_printer_name(hPrinter
);
1343 if(!name
) return ERROR_INVALID_HANDLE
;
1345 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
1349 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
1351 ERR("Can't find opened printer %s in registry\n",
1353 RegCloseKey(hkeyPrinters
);
1354 return ERROR_INVALID_PRINTER_NAME
; /* ? */
1356 RegCloseKey(hkeyPrinters
);
1357 return ERROR_SUCCESS
;
1360 void WINSPOOL_LoadSystemPrinters(void)
1362 HKEY hkey
, hkeyPrinters
;
1364 DWORD needed
, num
, i
;
1365 WCHAR PrinterName
[256];
1368 /* This ensures that all printer entries have a valid Name value. If causes
1369 problems later if they don't. If one is found to be missed we create one
1370 and set it equal to the name of the key */
1371 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1372 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1373 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1374 for(i
= 0; i
< num
; i
++) {
1375 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1376 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1377 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1378 set_reg_szW(hkey
, NameW
, PrinterName
);
1385 RegCloseKey(hkeyPrinters
);
1388 /* We want to avoid calling AddPrinter on printers as much as
1389 possible, because on cups printers this will (eventually) lead
1390 to a call to cupsGetPPD which takes forever, even with non-cups
1391 printers AddPrinter takes a while. So we'll tag all printers that
1392 were automatically added last time around, if they still exist
1393 we'll leave them be otherwise we'll delete them. */
1394 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1396 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1397 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1398 for(i
= 0; i
< num
; i
++) {
1399 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1400 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1401 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1403 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1411 HeapFree(GetProcessHeap(), 0, pi
);
1415 #ifdef SONAME_LIBCUPS
1416 done
= CUPS_LoadPrinters();
1419 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1420 PRINTCAP_LoadPrinters();
1422 /* Now enumerate the list again and delete any printers that are still tagged */
1423 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1425 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1426 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1427 for(i
= 0; i
< num
; i
++) {
1428 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1429 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1430 BOOL delete_driver
= FALSE
;
1431 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1432 DWORD dw
, type
, size
= sizeof(dw
);
1433 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1434 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1435 DeletePrinter(hprn
);
1436 delete_driver
= TRUE
;
1442 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1447 HeapFree(GetProcessHeap(), 0, pi
);
1454 /******************************************************************
1457 * Get the pointer to the specified job.
1458 * Should hold the printer_handles_cs before calling.
1460 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1462 opened_printer_t
*printer
= get_opened_printer(hprn
);
1465 if(!printer
) return NULL
;
1466 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1468 if(job
->job_id
== JobId
)
1474 /***********************************************************
1477 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1480 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1483 Formname
= (dmA
->dmSize
> off_formname
);
1484 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1485 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1486 dmW
->dmDeviceName
, CCHDEVICENAME
);
1488 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1489 dmA
->dmSize
- CCHDEVICENAME
);
1491 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1492 off_formname
- CCHDEVICENAME
);
1493 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1494 dmW
->dmFormName
, CCHFORMNAME
);
1495 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1496 (off_formname
+ CCHFORMNAME
));
1499 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1500 dmA
->dmDriverExtra
);
1504 /***********************************************************
1506 * Creates an ansi copy of supplied devmode
1508 static LPDEVMODEA
DEVMODEdupWtoA(const DEVMODEW
*dmW
)
1513 if (!dmW
) return NULL
;
1514 size
= dmW
->dmSize
- CCHDEVICENAME
-
1515 ((dmW
->dmSize
> FIELD_OFFSET(DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
1517 dmA
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1518 if (!dmA
) return NULL
;
1520 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1521 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1523 if (FIELD_OFFSET(DEVMODEW
, dmFormName
) >= dmW
->dmSize
) {
1524 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1525 dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1529 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1530 FIELD_OFFSET(DEVMODEW
, dmFormName
) - FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1531 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1532 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1534 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmLogPixels
));
1538 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
1542 /******************************************************************
1543 * convert_printerinfo_W_to_A [internal]
1546 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1547 DWORD level
, DWORD outlen
, DWORD numentries
)
1553 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1555 len
= pi_sizeof
[level
] * numentries
;
1556 ptr
= (LPSTR
) out
+ len
;
1559 /* copy the numbers of all PRINTER_INFO_* first */
1560 memcpy(out
, pPrintersW
, len
);
1562 while (id
< numentries
) {
1566 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1567 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1569 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1570 if (piW
->pDescription
) {
1571 piA
->pDescription
= ptr
;
1572 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1573 ptr
, outlen
, NULL
, NULL
);
1579 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1580 ptr
, outlen
, NULL
, NULL
);
1584 if (piW
->pComment
) {
1585 piA
->pComment
= ptr
;
1586 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1587 ptr
, outlen
, NULL
, NULL
);
1596 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1597 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1600 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1601 if (piW
->pServerName
) {
1602 piA
->pServerName
= ptr
;
1603 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1604 ptr
, outlen
, NULL
, NULL
);
1608 if (piW
->pPrinterName
) {
1609 piA
->pPrinterName
= ptr
;
1610 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1611 ptr
, outlen
, NULL
, NULL
);
1615 if (piW
->pShareName
) {
1616 piA
->pShareName
= ptr
;
1617 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1618 ptr
, outlen
, NULL
, NULL
);
1622 if (piW
->pPortName
) {
1623 piA
->pPortName
= ptr
;
1624 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1625 ptr
, outlen
, NULL
, NULL
);
1629 if (piW
->pDriverName
) {
1630 piA
->pDriverName
= ptr
;
1631 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1632 ptr
, outlen
, NULL
, NULL
);
1636 if (piW
->pComment
) {
1637 piA
->pComment
= ptr
;
1638 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1639 ptr
, outlen
, NULL
, NULL
);
1643 if (piW
->pLocation
) {
1644 piA
->pLocation
= ptr
;
1645 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1646 ptr
, outlen
, NULL
, NULL
);
1651 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1653 /* align DEVMODEA to a DWORD boundary */
1654 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1658 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1659 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1660 memcpy(ptr
, dmA
, len
);
1661 HeapFree(GetProcessHeap(), 0, dmA
);
1667 if (piW
->pSepFile
) {
1668 piA
->pSepFile
= ptr
;
1669 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1670 ptr
, outlen
, NULL
, NULL
);
1674 if (piW
->pPrintProcessor
) {
1675 piA
->pPrintProcessor
= ptr
;
1676 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1677 ptr
, outlen
, NULL
, NULL
);
1681 if (piW
->pDatatype
) {
1682 piA
->pDatatype
= ptr
;
1683 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1684 ptr
, outlen
, NULL
, NULL
);
1688 if (piW
->pParameters
) {
1689 piA
->pParameters
= ptr
;
1690 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1691 ptr
, outlen
, NULL
, NULL
);
1695 if (piW
->pSecurityDescriptor
) {
1696 piA
->pSecurityDescriptor
= NULL
;
1697 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1704 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1705 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1707 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1709 if (piW
->pPrinterName
) {
1710 piA
->pPrinterName
= ptr
;
1711 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1712 ptr
, outlen
, NULL
, NULL
);
1716 if (piW
->pServerName
) {
1717 piA
->pServerName
= ptr
;
1718 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1719 ptr
, outlen
, NULL
, NULL
);
1728 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1729 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1731 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1733 if (piW
->pPrinterName
) {
1734 piA
->pPrinterName
= ptr
;
1735 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1736 ptr
, outlen
, NULL
, NULL
);
1740 if (piW
->pPortName
) {
1741 piA
->pPortName
= ptr
;
1742 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1743 ptr
, outlen
, NULL
, NULL
);
1751 FIXME("for level %u\n", level
);
1753 pPrintersW
+= pi_sizeof
[level
];
1754 out
+= pi_sizeof
[level
];
1759 /***********************************************************
1760 * PRINTER_INFO_2AtoW
1761 * Creates a unicode copy of PRINTER_INFO_2A on heap
1763 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1765 LPPRINTER_INFO_2W piW
;
1766 UNICODE_STRING usBuffer
;
1768 if(!piA
) return NULL
;
1769 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1770 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1772 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1773 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1774 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1775 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1776 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1777 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1778 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1779 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1780 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1781 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1782 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1783 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1787 /***********************************************************
1788 * FREE_PRINTER_INFO_2W
1789 * Free PRINTER_INFO_2W and all strings
1791 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1795 HeapFree(heap
,0,piW
->pServerName
);
1796 HeapFree(heap
,0,piW
->pPrinterName
);
1797 HeapFree(heap
,0,piW
->pShareName
);
1798 HeapFree(heap
,0,piW
->pPortName
);
1799 HeapFree(heap
,0,piW
->pDriverName
);
1800 HeapFree(heap
,0,piW
->pComment
);
1801 HeapFree(heap
,0,piW
->pLocation
);
1802 HeapFree(heap
,0,piW
->pDevMode
);
1803 HeapFree(heap
,0,piW
->pSepFile
);
1804 HeapFree(heap
,0,piW
->pPrintProcessor
);
1805 HeapFree(heap
,0,piW
->pDatatype
);
1806 HeapFree(heap
,0,piW
->pParameters
);
1807 HeapFree(heap
,0,piW
);
1811 /******************************************************************
1812 * DeviceCapabilities [WINSPOOL.@]
1813 * DeviceCapabilitiesA [WINSPOOL.@]
1816 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1817 LPSTR pOutput
, LPDEVMODEA lpdm
)
1821 if (!GDI_CallDeviceCapabilities16
)
1823 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1825 if (!GDI_CallDeviceCapabilities16
) return -1;
1827 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1829 /* If DC_PAPERSIZE map POINT16s to POINTs */
1830 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1831 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1832 POINT
*pt
= (POINT
*)pOutput
;
1834 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1835 for(i
= 0; i
< ret
; i
++, pt
++)
1840 HeapFree( GetProcessHeap(), 0, tmp
);
1846 /*****************************************************************************
1847 * DeviceCapabilitiesW [WINSPOOL.@]
1849 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1852 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1853 WORD fwCapability
, LPWSTR pOutput
,
1854 const DEVMODEW
*pDevMode
)
1856 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
1857 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1858 LPSTR pPortA
= strdupWtoA(pPort
);
1861 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1862 fwCapability
== DC_FILEDEPENDENCIES
||
1863 fwCapability
== DC_PAPERNAMES
)) {
1864 /* These need A -> W translation */
1867 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1871 switch(fwCapability
) {
1876 case DC_FILEDEPENDENCIES
:
1880 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1881 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1883 for(i
= 0; i
< ret
; i
++)
1884 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1885 pOutput
+ (i
* size
), size
);
1886 HeapFree(GetProcessHeap(), 0, pOutputA
);
1888 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1889 (LPSTR
)pOutput
, dmA
);
1891 HeapFree(GetProcessHeap(),0,pPortA
);
1892 HeapFree(GetProcessHeap(),0,pDeviceA
);
1893 HeapFree(GetProcessHeap(),0,dmA
);
1897 /******************************************************************
1898 * DocumentPropertiesA [WINSPOOL.@]
1900 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1902 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1903 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1904 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1906 LPSTR lpName
= pDeviceName
;
1907 static CHAR port
[] = "LPT1:";
1910 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1911 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1915 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1917 ERR("no name from hPrinter?\n");
1918 SetLastError(ERROR_INVALID_HANDLE
);
1921 lpName
= strdupWtoA(lpNameW
);
1924 if (!GDI_CallExtDeviceMode16
)
1926 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1928 if (!GDI_CallExtDeviceMode16
) {
1929 ERR("No CallExtDeviceMode16?\n");
1933 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1934 pDevModeInput
, NULL
, fMode
);
1937 HeapFree(GetProcessHeap(),0,lpName
);
1942 /*****************************************************************************
1943 * DocumentPropertiesW (WINSPOOL.@)
1945 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1947 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1949 LPDEVMODEW pDevModeOutput
,
1950 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1953 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1954 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
1955 LPDEVMODEA pDevModeOutputA
= NULL
;
1958 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1959 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1961 if(pDevModeOutput
) {
1962 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1963 if(ret
< 0) return ret
;
1964 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1966 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1967 pDevModeInputA
, fMode
);
1968 if(pDevModeOutput
) {
1969 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1970 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1972 if(fMode
== 0 && ret
> 0)
1973 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1974 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1975 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1979 /******************************************************************
1980 * OpenPrinterA [WINSPOOL.@]
1985 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1986 LPPRINTER_DEFAULTSA pDefault
)
1988 UNICODE_STRING lpPrinterNameW
;
1989 UNICODE_STRING usBuffer
;
1990 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1991 PWSTR pwstrPrinterNameW
;
1994 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1997 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1998 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1999 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
2000 pDefaultW
= &DefaultW
;
2002 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
2004 RtlFreeUnicodeString(&usBuffer
);
2005 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
2007 RtlFreeUnicodeString(&lpPrinterNameW
);
2011 /******************************************************************
2012 * OpenPrinterW [WINSPOOL.@]
2014 * Open a Printer / Printserver or a Printer-Object
2017 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2018 * phPrinter [O] The resulting Handle is stored here
2019 * pDefault [I] PTR to Default Printer Settings or NULL
2026 * lpPrinterName is one of:
2027 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2028 *| Printer: "PrinterName"
2029 *| Printer-Object: "PrinterName,Job xxx"
2030 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2031 *| XcvPort: "Servername,XcvPort PortName"
2034 *| Printer-Object not supported
2035 *| pDefaults is ignored
2038 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2041 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2043 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2044 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
2048 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2049 SetLastError(ERROR_INVALID_PARAMETER
);
2053 /* Get the unique handle of the printer or Printserver */
2054 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2055 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2056 return (*phPrinter
!= 0);
2059 /******************************************************************
2060 * AddMonitorA [WINSPOOL.@]
2065 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2067 LPWSTR nameW
= NULL
;
2070 LPMONITOR_INFO_2A mi2a
;
2071 MONITOR_INFO_2W mi2w
;
2073 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2074 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2075 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
2076 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
2077 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
2080 SetLastError(ERROR_INVALID_LEVEL
);
2084 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2090 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2091 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2092 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2095 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2097 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2098 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2099 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2101 if (mi2a
->pEnvironment
) {
2102 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2103 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2104 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2106 if (mi2a
->pDLLName
) {
2107 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2108 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2109 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2112 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2114 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2115 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2116 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2118 HeapFree(GetProcessHeap(), 0, nameW
);
2122 /******************************************************************************
2123 * AddMonitorW [WINSPOOL.@]
2125 * Install a Printmonitor
2128 * pName [I] Servername or NULL (local Computer)
2129 * Level [I] Structure-Level (Must be 2)
2130 * pMonitors [I] PTR to MONITOR_INFO_2
2137 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2140 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2142 LPMONITOR_INFO_2W mi2w
;
2144 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2145 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2146 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
2147 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
2148 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
2150 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2153 SetLastError(ERROR_INVALID_LEVEL
);
2157 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2162 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2165 /******************************************************************
2166 * DeletePrinterDriverA [WINSPOOL.@]
2169 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2171 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2174 /******************************************************************
2175 * DeletePrinterDriverW [WINSPOOL.@]
2178 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2180 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2183 /******************************************************************
2184 * DeleteMonitorA [WINSPOOL.@]
2186 * See DeleteMonitorW.
2189 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2191 LPWSTR nameW
= NULL
;
2192 LPWSTR EnvironmentW
= NULL
;
2193 LPWSTR MonitorNameW
= NULL
;
2198 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2199 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2200 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2204 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2205 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2206 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2209 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2210 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2211 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2214 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2216 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2217 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2218 HeapFree(GetProcessHeap(), 0, nameW
);
2222 /******************************************************************
2223 * DeleteMonitorW [WINSPOOL.@]
2225 * Delete a specific Printmonitor from a Printing-Environment
2228 * pName [I] Servername or NULL (local Computer)
2229 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2230 * pMonitorName [I] Name of the Monitor, that should be deleted
2237 * pEnvironment is ignored in Windows for the local Computer.
2240 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2243 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2244 debugstr_w(pMonitorName
));
2246 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2248 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2252 /******************************************************************
2253 * DeletePortA [WINSPOOL.@]
2258 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2260 LPWSTR nameW
= NULL
;
2261 LPWSTR portW
= NULL
;
2265 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2267 /* convert servername to unicode */
2269 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2270 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2271 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2274 /* convert portname to unicode */
2276 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2277 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2278 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2281 res
= DeletePortW(nameW
, hWnd
, portW
);
2282 HeapFree(GetProcessHeap(), 0, nameW
);
2283 HeapFree(GetProcessHeap(), 0, portW
);
2287 /******************************************************************
2288 * DeletePortW [WINSPOOL.@]
2290 * Delete a specific Port
2293 * pName [I] Servername or NULL (local Computer)
2294 * hWnd [I] Handle to parent Window for the Dialog-Box
2295 * pPortName [I] Name of the Port, that should be deleted
2302 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2308 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2310 if (pName
&& pName
[0]) {
2311 SetLastError(ERROR_INVALID_PARAMETER
);
2316 SetLastError(RPC_X_NULL_REF_POINTER
);
2320 /* an empty Portname is Invalid */
2321 if (!pPortName
[0]) {
2322 SetLastError(ERROR_NOT_SUPPORTED
);
2326 pm
= monitor_load_by_port(pPortName
);
2327 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
2328 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2329 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
2330 TRACE("got %d with %u\n", res
, GetLastError());
2334 pui
= monitor_loadui(pm
);
2335 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2336 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2337 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2338 TRACE("got %d with %u\n", res
, GetLastError());
2342 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
2343 pm
, debugstr_w(pm
? pm
->dllname
: NULL
), pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
2345 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2346 SetLastError(ERROR_NOT_SUPPORTED
);
2349 monitor_unload(pui
);
2353 TRACE("returning %d with %u\n", res
, GetLastError());
2357 /******************************************************************************
2358 * SetPrinterW [WINSPOOL.@]
2360 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2362 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2363 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2367 /******************************************************************************
2368 * WritePrinter [WINSPOOL.@]
2370 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2372 opened_printer_t
*printer
;
2375 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2377 EnterCriticalSection(&printer_handles_cs
);
2378 printer
= get_opened_printer(hPrinter
);
2381 SetLastError(ERROR_INVALID_HANDLE
);
2387 SetLastError(ERROR_SPL_NO_STARTDOC
);
2391 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2393 LeaveCriticalSection(&printer_handles_cs
);
2397 /*****************************************************************************
2398 * AddFormA [WINSPOOL.@]
2400 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2402 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2406 /*****************************************************************************
2407 * AddFormW [WINSPOOL.@]
2409 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2411 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2415 /*****************************************************************************
2416 * AddJobA [WINSPOOL.@]
2418 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2421 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2425 SetLastError(ERROR_INVALID_LEVEL
);
2429 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2432 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2433 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2434 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2435 if(*pcbNeeded
> cbBuf
) {
2436 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2439 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2440 addjobA
->JobId
= addjobW
->JobId
;
2441 addjobA
->Path
= (char *)(addjobA
+ 1);
2442 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2448 /*****************************************************************************
2449 * AddJobW [WINSPOOL.@]
2451 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2453 opened_printer_t
*printer
;
2456 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2457 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2458 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2460 ADDJOB_INFO_1W
*addjob
;
2462 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2464 EnterCriticalSection(&printer_handles_cs
);
2466 printer
= get_opened_printer(hPrinter
);
2469 SetLastError(ERROR_INVALID_HANDLE
);
2474 SetLastError(ERROR_INVALID_LEVEL
);
2478 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2482 job
->job_id
= InterlockedIncrement(&next_job_id
);
2484 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2485 if(path
[len
- 1] != '\\')
2487 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2488 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2490 len
= strlenW(filename
);
2491 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2492 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2493 job
->document_title
= strdupW(default_doc_title
);
2494 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2496 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2497 if(*pcbNeeded
<= cbBuf
) {
2498 addjob
= (ADDJOB_INFO_1W
*)pData
;
2499 addjob
->JobId
= job
->job_id
;
2500 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2501 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2504 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2507 LeaveCriticalSection(&printer_handles_cs
);
2511 /*****************************************************************************
2512 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2514 * Return the PATH for the Print-Processors
2516 * See GetPrintProcessorDirectoryW.
2520 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2521 DWORD level
, LPBYTE Info
,
2522 DWORD cbBuf
, LPDWORD pcbNeeded
)
2524 LPWSTR serverW
= NULL
;
2529 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2530 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2534 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2535 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2536 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2540 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2541 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2542 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2545 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2546 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2548 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2551 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2552 cbBuf
, NULL
, NULL
) > 0;
2555 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2556 HeapFree(GetProcessHeap(), 0, envW
);
2557 HeapFree(GetProcessHeap(), 0, serverW
);
2561 /*****************************************************************************
2562 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2564 * Return the PATH for the Print-Processors
2567 * server [I] Servername (NT only) or NULL (local Computer)
2568 * env [I] Printing-Environment (see below) or NULL (Default)
2569 * level [I] Structure-Level (must be 1)
2570 * Info [O] PTR to Buffer that receives the Result
2571 * cbBuf [I] Size of Buffer at "Info"
2572 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2573 * required for the Buffer at "Info"
2576 * Success: TRUE and in pcbNeeded the Bytes used in Info
2577 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2578 * if cbBuf is too small
2580 * Native Values returned in Info on Success:
2581 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2582 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2583 *| win9x(Windows 4.0): "%winsysdir%"
2585 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2588 * Only NULL or "" is supported for server
2591 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2592 DWORD level
, LPBYTE Info
,
2593 DWORD cbBuf
, LPDWORD pcbNeeded
)
2596 const printenv_t
* env_t
;
2598 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
),
2599 debugstr_w(env
), level
, Info
, cbBuf
, pcbNeeded
);
2601 if(server
!= NULL
&& server
[0]) {
2602 FIXME("server not supported: %s\n", debugstr_w(server
));
2603 SetLastError(ERROR_INVALID_PARAMETER
);
2607 env_t
= validate_envW(env
);
2608 if(!env_t
) return FALSE
; /* environment invalid or unsupported */
2611 WARN("(Level: %d) is ignored in win9x\n", level
);
2612 SetLastError(ERROR_INVALID_LEVEL
);
2616 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2617 needed
= GetSystemDirectoryW(NULL
, 0);
2618 /* add the Size for the Subdirectories */
2619 needed
+= lstrlenW(spoolprtprocsW
);
2620 needed
+= lstrlenW(env_t
->subdir
);
2621 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2623 if(pcbNeeded
) *pcbNeeded
= needed
;
2624 TRACE ("required: 0x%x/%d\n", needed
, needed
);
2625 if (needed
> cbBuf
) {
2626 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2629 if(pcbNeeded
== NULL
) {
2630 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2631 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2632 SetLastError(RPC_X_NULL_REF_POINTER
);
2636 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2637 SetLastError(RPC_X_NULL_REF_POINTER
);
2641 GetSystemDirectoryW((LPWSTR
) Info
, cbBuf
/sizeof(WCHAR
));
2642 /* add the Subdirectories */
2643 lstrcatW((LPWSTR
) Info
, spoolprtprocsW
);
2644 lstrcatW((LPWSTR
) Info
, env_t
->subdir
);
2645 TRACE(" => %s\n", debugstr_w((LPWSTR
) Info
));
2649 /*****************************************************************************
2650 * WINSPOOL_OpenDriverReg [internal]
2652 * opens the registry for the printer drivers depending on the given input
2653 * variable pEnvironment
2656 * the opened hkey on success
2659 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
, BOOL unicode
)
2663 const printenv_t
* env
;
2666 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
), unicode
);
2668 if (!pEnvironment
|| unicode
) {
2669 /* pEnvironment was NULL or a Unicode-String: use it direct */
2670 env
= validate_envW(pEnvironment
);
2674 /* pEnvironment was an ANSI-String: convert to unicode first */
2676 INT len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2677 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2678 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, buffer
, len
);
2679 env
= validate_envW(buffer
);
2680 HeapFree(GetProcessHeap(), 0, buffer
);
2682 if (!env
) return NULL
;
2684 buffer
= HeapAlloc( GetProcessHeap(), 0,
2685 (strlenW(DriversW
) + strlenW(env
->envname
) +
2686 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2688 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2689 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2690 HeapFree(GetProcessHeap(), 0, buffer
);
2695 /*****************************************************************************
2696 * AddPrinterW [WINSPOOL.@]
2698 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2700 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2704 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2706 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2707 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2708 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2709 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2710 statusW
[] = {'S','t','a','t','u','s',0},
2711 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2713 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2716 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2717 SetLastError(ERROR_INVALID_PARAMETER
);
2721 ERR("Level = %d, unsupported!\n", Level
);
2722 SetLastError(ERROR_INVALID_LEVEL
);
2726 SetLastError(ERROR_INVALID_PARAMETER
);
2729 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2731 ERR("Can't create Printers key\n");
2734 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2735 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2736 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2737 RegCloseKey(hkeyPrinter
);
2738 RegCloseKey(hkeyPrinters
);
2741 RegCloseKey(hkeyPrinter
);
2743 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
2745 ERR("Can't create Drivers key\n");
2746 RegCloseKey(hkeyPrinters
);
2749 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2751 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2752 RegCloseKey(hkeyPrinters
);
2753 RegCloseKey(hkeyDrivers
);
2754 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2757 RegCloseKey(hkeyDriver
);
2758 RegCloseKey(hkeyDrivers
);
2760 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2761 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2762 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2763 RegCloseKey(hkeyPrinters
);
2767 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2769 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2770 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2771 RegCloseKey(hkeyPrinters
);
2774 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2775 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2776 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2778 /* See if we can load the driver. We may need the devmode structure anyway
2781 * Note that DocumentPropertiesW will briefly try to open the printer we
2782 * just create to find a DEVMODEA struct (it will use the WINEPS default
2783 * one in case it is not there, so we are ok).
2785 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2788 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2789 size
= sizeof(DEVMODEW
);
2795 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2797 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2799 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2800 HeapFree(GetProcessHeap(),0,dmW
);
2805 /* set devmode to printer name */
2806 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2810 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2811 and we support these drivers. NT writes DEVMODEW so somehow
2812 we'll need to distinguish between these when we support NT
2816 dmA
= DEVMODEdupWtoA(dmW
);
2817 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2818 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2819 HeapFree(GetProcessHeap(), 0, dmA
);
2821 HeapFree(GetProcessHeap(), 0, dmW
);
2823 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2824 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2825 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2826 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2828 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2829 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2830 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2831 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2832 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2833 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2834 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2835 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2836 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2837 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2838 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2839 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2840 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2842 RegCloseKey(hkeyPrinter
);
2843 RegCloseKey(hkeyPrinters
);
2844 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2845 ERR("OpenPrinter failing\n");
2851 /*****************************************************************************
2852 * AddPrinterA [WINSPOOL.@]
2854 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2856 UNICODE_STRING pNameW
;
2858 PRINTER_INFO_2W
*piW
;
2859 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2862 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
2864 ERR("Level = %d, unsupported!\n", Level
);
2865 SetLastError(ERROR_INVALID_LEVEL
);
2868 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2869 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2871 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2873 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2874 RtlFreeUnicodeString(&pNameW
);
2879 /*****************************************************************************
2880 * ClosePrinter [WINSPOOL.@]
2882 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2884 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2885 opened_printer_t
*printer
= NULL
;
2888 TRACE("(%p)\n", hPrinter
);
2890 EnterCriticalSection(&printer_handles_cs
);
2892 if ((i
> 0) && (i
<= nb_printer_handles
))
2893 printer
= printer_handles
[i
- 1];
2898 struct list
*cursor
, *cursor2
;
2900 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer
->pm
,
2901 debugstr_w(printer
->pm
? printer
->pm
->dllname
: NULL
),
2902 printer
->hXcv
, debugstr_w(printer
->name
), printer
->doc
);
2904 if (printer
->backend_printer
) {
2905 backend
->fpClosePrinter(printer
->backend_printer
);
2909 EndDocPrinter(hPrinter
);
2911 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2913 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2915 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2916 ScheduleJob(hPrinter
, job
->job_id
);
2918 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2920 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
2921 monitor_unload(printer
->pm
);
2922 HeapFree(GetProcessHeap(), 0, printer
->printername
);
2923 HeapFree(GetProcessHeap(), 0, printer
->name
);
2924 HeapFree(GetProcessHeap(), 0, printer
);
2925 printer_handles
[i
- 1] = NULL
;
2928 LeaveCriticalSection(&printer_handles_cs
);
2932 /*****************************************************************************
2933 * DeleteFormA [WINSPOOL.@]
2935 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2937 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2941 /*****************************************************************************
2942 * DeleteFormW [WINSPOOL.@]
2944 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2946 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2950 /*****************************************************************************
2951 * DeletePrinter [WINSPOOL.@]
2953 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2955 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2956 HKEY hkeyPrinters
, hkey
;
2959 SetLastError(ERROR_INVALID_HANDLE
);
2962 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
2963 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
2964 RegCloseKey(hkeyPrinters
);
2966 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
2967 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
2969 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2970 RegDeleteValueW(hkey
, lpNameW
);
2974 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
2975 RegDeleteValueW(hkey
, lpNameW
);
2981 /*****************************************************************************
2982 * SetPrinterA [WINSPOOL.@]
2984 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2987 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
2991 /*****************************************************************************
2992 * SetJobA [WINSPOOL.@]
2994 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2995 LPBYTE pJob
, DWORD Command
)
2999 UNICODE_STRING usBuffer
;
3001 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3003 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3004 are all ignored by SetJob, so we don't bother copying them */
3012 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3013 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3015 JobW
= (LPBYTE
)info1W
;
3016 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3017 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3018 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3019 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3020 info1W
->Status
= info1A
->Status
;
3021 info1W
->Priority
= info1A
->Priority
;
3022 info1W
->Position
= info1A
->Position
;
3023 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3028 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3029 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3031 JobW
= (LPBYTE
)info2W
;
3032 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3033 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3034 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3035 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3036 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3037 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3038 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3039 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3040 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3041 info2W
->Status
= info2A
->Status
;
3042 info2W
->Priority
= info2A
->Priority
;
3043 info2W
->Position
= info2A
->Position
;
3044 info2W
->StartTime
= info2A
->StartTime
;
3045 info2W
->UntilTime
= info2A
->UntilTime
;
3046 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3050 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3051 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3054 SetLastError(ERROR_INVALID_LEVEL
);
3058 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3064 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3065 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3066 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3067 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3068 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3073 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3074 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3075 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3076 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3077 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3078 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3079 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3080 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3081 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3085 HeapFree(GetProcessHeap(), 0, JobW
);
3090 /*****************************************************************************
3091 * SetJobW [WINSPOOL.@]
3093 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3094 LPBYTE pJob
, DWORD Command
)
3099 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3100 FIXME("Ignoring everything other than document title\n");
3102 EnterCriticalSection(&printer_handles_cs
);
3103 job
= get_job(hPrinter
, JobId
);
3113 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3114 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3115 job
->document_title
= strdupW(info1
->pDocument
);
3120 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3121 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3122 job
->document_title
= strdupW(info2
->pDocument
);
3128 SetLastError(ERROR_INVALID_LEVEL
);
3133 LeaveCriticalSection(&printer_handles_cs
);
3137 /*****************************************************************************
3138 * EndDocPrinter [WINSPOOL.@]
3140 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3142 opened_printer_t
*printer
;
3144 TRACE("(%p)\n", hPrinter
);
3146 EnterCriticalSection(&printer_handles_cs
);
3148 printer
= get_opened_printer(hPrinter
);
3151 SetLastError(ERROR_INVALID_HANDLE
);
3157 SetLastError(ERROR_SPL_NO_STARTDOC
);
3161 CloseHandle(printer
->doc
->hf
);
3162 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3163 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3164 printer
->doc
= NULL
;
3167 LeaveCriticalSection(&printer_handles_cs
);
3171 /*****************************************************************************
3172 * EndPagePrinter [WINSPOOL.@]
3174 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3176 FIXME("(%p): stub\n", hPrinter
);
3180 /*****************************************************************************
3181 * StartDocPrinterA [WINSPOOL.@]
3183 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3185 UNICODE_STRING usBuffer
;
3187 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3190 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3191 or one (DOC_INFO_3) extra DWORDs */
3195 doc2W
.JobId
= doc2
->JobId
;
3198 doc2W
.dwMode
= doc2
->dwMode
;
3201 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3202 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3203 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3207 SetLastError(ERROR_INVALID_LEVEL
);
3211 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3213 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3214 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3215 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3220 /*****************************************************************************
3221 * StartDocPrinterW [WINSPOOL.@]
3223 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3225 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3226 opened_printer_t
*printer
;
3227 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3228 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3229 JOB_INFO_1W job_info
;
3230 DWORD needed
, ret
= 0;
3234 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3235 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3236 debugstr_w(doc
->pDatatype
));
3238 if(Level
< 1 || Level
> 3)
3240 SetLastError(ERROR_INVALID_LEVEL
);
3244 EnterCriticalSection(&printer_handles_cs
);
3245 printer
= get_opened_printer(hPrinter
);
3248 SetLastError(ERROR_INVALID_HANDLE
);
3254 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3258 /* Even if we're printing to a file we still add a print job, we'll
3259 just ignore the spool file name */
3261 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3263 ERR("AddJob failed gle %u\n", GetLastError());
3267 if(doc
->pOutputFile
)
3268 filename
= doc
->pOutputFile
;
3270 filename
= addjob
->Path
;
3272 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3273 if(hf
== INVALID_HANDLE_VALUE
)
3276 memset(&job_info
, 0, sizeof(job_info
));
3277 job_info
.pDocument
= doc
->pDocName
;
3278 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3280 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3281 printer
->doc
->hf
= hf
;
3282 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3284 LeaveCriticalSection(&printer_handles_cs
);
3289 /*****************************************************************************
3290 * StartPagePrinter [WINSPOOL.@]
3292 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3294 FIXME("(%p): stub\n", hPrinter
);
3298 /*****************************************************************************
3299 * GetFormA [WINSPOOL.@]
3301 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3302 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3304 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3305 Level
,pForm
,cbBuf
,pcbNeeded
);
3309 /*****************************************************************************
3310 * GetFormW [WINSPOOL.@]
3312 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3313 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3315 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3316 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3320 /*****************************************************************************
3321 * SetFormA [WINSPOOL.@]
3323 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3326 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3330 /*****************************************************************************
3331 * SetFormW [WINSPOOL.@]
3333 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3336 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3340 /*****************************************************************************
3341 * ReadPrinter [WINSPOOL.@]
3343 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3344 LPDWORD pNoBytesRead
)
3346 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3350 /*****************************************************************************
3351 * ResetPrinterA [WINSPOOL.@]
3353 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3355 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3359 /*****************************************************************************
3360 * ResetPrinterW [WINSPOOL.@]
3362 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3364 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3368 /*****************************************************************************
3369 * WINSPOOL_GetDWORDFromReg
3371 * Return DWORD associated with ValueName from hkey.
3373 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3375 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3378 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3380 if(ret
!= ERROR_SUCCESS
) {
3381 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3384 if(type
!= REG_DWORD
) {
3385 ERR("Got type %d\n", type
);
3392 /*****************************************************************************
3393 * get_filename_from_reg [internal]
3395 * Get ValueName from hkey storing result in out
3396 * when the Value in the registry has only a filename, use driverdir as prefix
3397 * outlen is space left in out
3398 * String is stored either as unicode or ascii
3402 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3403 LPBYTE out
, DWORD outlen
, LPDWORD needed
, BOOL unicode
)
3405 WCHAR filename
[MAX_PATH
];
3409 LPWSTR buffer
= filename
;
3413 size
= sizeof(filename
);
3415 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3416 if (ret
== ERROR_MORE_DATA
) {
3417 TRACE("need dynamic buffer: %u\n", size
);
3418 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3420 /* No Memory is bad */
3424 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3427 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3428 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3434 /* do we have a full path ? */
3435 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3436 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3439 /* we must build the full Path */
3441 if ((out
) && (outlen
> dirlen
)) {
3443 lstrcpyW((LPWSTR
)out
, driverdir
);
3447 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3456 /* write the filename */
3458 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3459 if ((out
) && (outlen
>= size
)) {
3460 lstrcpyW((LPWSTR
)out
, ptr
);
3469 size
= WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, NULL
, 0, NULL
, NULL
);
3470 if ((out
) && (outlen
>= size
)) {
3471 WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3479 ptr
+= lstrlenW(ptr
)+1;
3480 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3483 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3485 /* write the multisz-termination */
3486 if (type
== REG_MULTI_SZ
) {
3487 size
= (unicode
) ? sizeof(WCHAR
) : 1;
3490 if (out
&& (outlen
>= size
)) {
3491 memset (out
, 0, size
);
3497 /*****************************************************************************
3498 * WINSPOOL_GetStringFromReg
3500 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3501 * String is stored either as unicode or ascii.
3502 * Bit of a hack here to get the ValueName if we want ascii.
3504 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3505 DWORD buflen
, DWORD
*needed
,
3508 DWORD sz
= buflen
, type
;
3512 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3514 LPSTR ValueNameA
= strdupWtoA(ValueName
);
3515 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
3516 HeapFree(GetProcessHeap(),0,ValueNameA
);
3518 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3519 WARN("Got ret = %d\n", ret
);
3523 /* add space for terminating '\0' */
3524 sz
+= unicode
? sizeof(WCHAR
) : 1;
3528 TRACE("%s: %s\n", debugstr_w(ValueName
), unicode
? debugstr_w((LPCWSTR
)ptr
) : debugstr_a((LPCSTR
)ptr
));
3533 /*****************************************************************************
3534 * WINSPOOL_GetDefaultDevMode
3536 * Get a default DevMode values for wineps.
3540 static void WINSPOOL_GetDefaultDevMode(
3542 DWORD buflen
, DWORD
*needed
,
3546 static const char szwps
[] = "wineps.drv";
3548 /* fill default DEVMODE - should be read from ppd... */
3549 ZeroMemory( &dm
, sizeof(dm
) );
3550 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
3551 dm
.dmSpecVersion
= DM_SPECVERSION
;
3552 dm
.dmDriverVersion
= 1;
3553 dm
.dmSize
= sizeof(DEVMODEA
);
3554 dm
.dmDriverExtra
= 0;
3556 DM_ORIENTATION
| DM_PAPERSIZE
|
3557 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3560 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3561 DM_YRESOLUTION
| DM_TTOPTION
;
3563 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3564 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3565 dm
.u1
.s1
.dmPaperLength
= 2970;
3566 dm
.u1
.s1
.dmPaperWidth
= 2100;
3568 dm
.u1
.s1
.dmScale
= 100;
3569 dm
.u1
.s1
.dmCopies
= 1;
3570 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3571 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3574 dm
.dmYResolution
= 300; /* 300dpi */
3575 dm
.dmTTOption
= DMTT_BITMAP
;
3578 /* dm.dmLogPixels */
3579 /* dm.dmBitsPerPel */
3580 /* dm.dmPelsWidth */
3581 /* dm.dmPelsHeight */
3582 /* dm.u2.dmDisplayFlags */
3583 /* dm.dmDisplayFrequency */
3584 /* dm.dmICMMethod */
3585 /* dm.dmICMIntent */
3586 /* dm.dmMediaType */
3587 /* dm.dmDitherType */
3588 /* dm.dmReserved1 */
3589 /* dm.dmReserved2 */
3590 /* dm.dmPanningWidth */
3591 /* dm.dmPanningHeight */
3594 if(buflen
>= sizeof(DEVMODEW
)) {
3595 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
3596 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
3597 HeapFree(GetProcessHeap(),0,pdmW
);
3599 *needed
= sizeof(DEVMODEW
);
3603 if(buflen
>= sizeof(DEVMODEA
)) {
3604 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
3606 *needed
= sizeof(DEVMODEA
);
3610 /*****************************************************************************
3611 * WINSPOOL_GetDevModeFromReg
3613 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3614 * DevMode is stored either as unicode or ascii.
3616 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3618 DWORD buflen
, DWORD
*needed
,
3621 DWORD sz
= buflen
, type
;
3624 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3625 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3626 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3627 if (sz
< sizeof(DEVMODEA
))
3629 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3632 /* ensures that dmSize is not erratically bogus if registry is invalid */
3633 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3634 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3636 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3638 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3639 memcpy(ptr
, dmW
, sz
);
3640 HeapFree(GetProcessHeap(),0,dmW
);
3647 /*********************************************************************
3648 * WINSPOOL_GetPrinter_1
3650 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3651 * The strings are either stored as unicode or ascii.
3653 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3654 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3657 DWORD size
, left
= cbBuf
;
3658 BOOL space
= (cbBuf
> 0);
3663 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3665 if(space
&& size
<= left
) {
3666 pi1
->pName
= (LPWSTR
)ptr
;
3674 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3675 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3677 if(space
&& size
<= left
) {
3678 pi1
->pDescription
= (LPWSTR
)ptr
;
3686 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3688 if(space
&& size
<= left
) {
3689 pi1
->pComment
= (LPWSTR
)ptr
;
3697 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3699 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3700 memset(pi1
, 0, sizeof(*pi1
));
3704 /*********************************************************************
3705 * WINSPOOL_GetPrinter_2
3707 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3708 * The strings are either stored as unicode or ascii.
3710 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3711 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3714 DWORD size
, left
= cbBuf
;
3715 BOOL space
= (cbBuf
> 0);
3720 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3722 if(space
&& size
<= left
) {
3723 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3730 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
3732 if(space
&& size
<= left
) {
3733 pi2
->pShareName
= (LPWSTR
)ptr
;
3740 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3742 if(space
&& size
<= left
) {
3743 pi2
->pPortName
= (LPWSTR
)ptr
;
3750 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
3752 if(space
&& size
<= left
) {
3753 pi2
->pDriverName
= (LPWSTR
)ptr
;
3760 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3762 if(space
&& size
<= left
) {
3763 pi2
->pComment
= (LPWSTR
)ptr
;
3770 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
3772 if(space
&& size
<= left
) {
3773 pi2
->pLocation
= (LPWSTR
)ptr
;
3780 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
3782 if(space
&& size
<= left
) {
3783 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3792 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
3793 if(space
&& size
<= left
) {
3794 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3801 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
3803 if(space
&& size
<= left
) {
3804 pi2
->pSepFile
= (LPWSTR
)ptr
;
3811 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
3813 if(space
&& size
<= left
) {
3814 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3821 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
3823 if(space
&& size
<= left
) {
3824 pi2
->pDatatype
= (LPWSTR
)ptr
;
3831 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
3833 if(space
&& size
<= left
) {
3834 pi2
->pParameters
= (LPWSTR
)ptr
;
3842 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3843 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3844 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3845 "Default Priority");
3846 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3847 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3850 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3851 memset(pi2
, 0, sizeof(*pi2
));
3856 /*********************************************************************
3857 * WINSPOOL_GetPrinter_4
3859 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3861 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3862 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3865 DWORD size
, left
= cbBuf
;
3866 BOOL space
= (cbBuf
> 0);
3871 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3873 if(space
&& size
<= left
) {
3874 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3882 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3885 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3886 memset(pi4
, 0, sizeof(*pi4
));
3891 /*********************************************************************
3892 * WINSPOOL_GetPrinter_5
3894 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3896 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3897 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3900 DWORD size
, left
= cbBuf
;
3901 BOOL space
= (cbBuf
> 0);
3906 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3908 if(space
&& size
<= left
) {
3909 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3916 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3918 if(space
&& size
<= left
) {
3919 pi5
->pPortName
= (LPWSTR
)ptr
;
3927 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3928 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3930 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3934 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3935 memset(pi5
, 0, sizeof(*pi5
));
3940 /*********************************************************************
3941 * WINSPOOL_GetPrinter_7
3943 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3945 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
3946 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
3948 DWORD size
, left
= cbBuf
;
3949 BOOL space
= (cbBuf
> 0);
3954 if (WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
, unicode
))
3956 if (space
&& size
<= left
) {
3957 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
3965 /* We do not have a Directory Service */
3966 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
3969 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
3970 memset(pi7
, 0, sizeof(*pi7
));
3975 /*********************************************************************
3976 * WINSPOOL_GetPrinter_9
3978 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
3979 * The strings are either stored as unicode or ascii.
3981 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
3982 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
3985 BOOL space
= (cbBuf
> 0);
3989 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
, unicode
)) {
3990 if(space
&& size
<= cbBuf
) {
3991 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3998 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
, unicode
);
3999 if(space
&& size
<= cbBuf
) {
4000 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
4006 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
4007 memset(pi9
, 0, sizeof(*pi9
));
4012 /*****************************************************************************
4013 * WINSPOOL_GetPrinter
4015 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4016 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4017 * just a collection of pointers to strings.
4019 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4020 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
4023 DWORD size
, needed
= 0;
4025 HKEY hkeyPrinter
, hkeyPrinters
;
4028 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4030 if (!(name
= get_opened_printer_name(hPrinter
))) {
4031 SetLastError(ERROR_INVALID_HANDLE
);
4035 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4037 ERR("Can't create Printers key\n");
4040 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
4042 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4043 RegCloseKey(hkeyPrinters
);
4044 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4051 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4053 size
= sizeof(PRINTER_INFO_2W
);
4055 ptr
= pPrinter
+ size
;
4057 memset(pPrinter
, 0, size
);
4062 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
4070 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4072 size
= sizeof(PRINTER_INFO_4W
);
4074 ptr
= pPrinter
+ size
;
4076 memset(pPrinter
, 0, size
);
4081 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
4090 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4092 size
= sizeof(PRINTER_INFO_5W
);
4094 ptr
= pPrinter
+ size
;
4096 memset(pPrinter
, 0, size
);
4102 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
4111 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
4113 size
= sizeof(PRINTER_INFO_6
);
4114 if (size
<= cbBuf
) {
4115 /* FIXME: We do not update the status yet */
4116 pi6
->dwStatus
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Status");
4128 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
4130 size
= sizeof(PRINTER_INFO_7W
);
4131 if (size
<= cbBuf
) {
4132 ptr
= pPrinter
+ size
;
4134 memset(pPrinter
, 0, size
);
4140 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
, unicode
);
4148 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
4150 size
= sizeof(PRINTER_INFO_9W
);
4152 ptr
= pPrinter
+ size
;
4154 memset(pPrinter
, 0, size
);
4160 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
, unicode
);
4167 FIXME("Unimplemented level %d\n", Level
);
4168 SetLastError(ERROR_INVALID_LEVEL
);
4169 RegCloseKey(hkeyPrinters
);
4170 RegCloseKey(hkeyPrinter
);
4174 RegCloseKey(hkeyPrinter
);
4175 RegCloseKey(hkeyPrinters
);
4177 TRACE("returning %d needed = %d\n", ret
, needed
);
4178 if(pcbNeeded
) *pcbNeeded
= needed
;
4180 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4184 /*****************************************************************************
4185 * GetPrinterW [WINSPOOL.@]
4187 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4188 DWORD cbBuf
, LPDWORD pcbNeeded
)
4190 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4194 /*****************************************************************************
4195 * GetPrinterA [WINSPOOL.@]
4197 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4198 DWORD cbBuf
, LPDWORD pcbNeeded
)
4200 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4204 /*****************************************************************************
4205 * WINSPOOL_EnumPrinters
4207 * Implementation of EnumPrintersA|W
4209 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
4210 DWORD dwLevel
, LPBYTE lpbPrinters
,
4211 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4212 LPDWORD lpdwReturned
, BOOL unicode
)
4215 HKEY hkeyPrinters
, hkeyPrinter
;
4216 WCHAR PrinterName
[255];
4217 DWORD needed
= 0, number
= 0;
4218 DWORD used
, i
, left
;
4222 memset(lpbPrinters
, 0, cbBuf
);
4228 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4229 if(dwType
== PRINTER_ENUM_DEFAULT
)
4232 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4233 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4234 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4236 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4244 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4245 FIXME("dwType = %08x\n", dwType
);
4246 SetLastError(ERROR_INVALID_FLAGS
);
4250 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4252 ERR("Can't create Printers key\n");
4256 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4257 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4258 RegCloseKey(hkeyPrinters
);
4259 ERR("Can't query Printers key\n");
4262 TRACE("Found %d printers\n", number
);
4266 used
= number
* sizeof(PRINTER_INFO_1W
);
4269 used
= number
* sizeof(PRINTER_INFO_2W
);
4272 used
= number
* sizeof(PRINTER_INFO_4W
);
4275 used
= number
* sizeof(PRINTER_INFO_5W
);
4279 SetLastError(ERROR_INVALID_LEVEL
);
4280 RegCloseKey(hkeyPrinters
);
4283 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4285 for(i
= 0; i
< number
; i
++) {
4286 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4288 ERR("Can't enum key number %d\n", i
);
4289 RegCloseKey(hkeyPrinters
);
4292 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4293 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4295 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4296 RegCloseKey(hkeyPrinters
);
4301 buf
= lpbPrinters
+ used
;
4302 left
= cbBuf
- used
;
4310 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4311 left
, &needed
, unicode
);
4313 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4316 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4317 left
, &needed
, unicode
);
4319 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4322 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4323 left
, &needed
, unicode
);
4325 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4328 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4329 left
, &needed
, unicode
);
4331 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4334 ERR("Shouldn't be here!\n");
4335 RegCloseKey(hkeyPrinter
);
4336 RegCloseKey(hkeyPrinters
);
4339 RegCloseKey(hkeyPrinter
);
4341 RegCloseKey(hkeyPrinters
);
4348 memset(lpbPrinters
, 0, cbBuf
);
4349 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4353 *lpdwReturned
= number
;
4354 SetLastError(ERROR_SUCCESS
);
4359 /******************************************************************
4360 * EnumPrintersW [WINSPOOL.@]
4362 * Enumerates the available printers, print servers and print
4363 * providers, depending on the specified flags, name and level.
4367 * If level is set to 1:
4368 * Returns an array of PRINTER_INFO_1 data structures in the
4369 * lpbPrinters buffer.
4371 * If level is set to 2:
4372 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4373 * Returns an array of PRINTER_INFO_2 data structures in the
4374 * lpbPrinters buffer. Note that according to MSDN also an
4375 * OpenPrinter should be performed on every remote printer.
4377 * If level is set to 4 (officially WinNT only):
4378 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4379 * Fast: Only the registry is queried to retrieve printer names,
4380 * no connection to the driver is made.
4381 * Returns an array of PRINTER_INFO_4 data structures in the
4382 * lpbPrinters buffer.
4384 * If level is set to 5 (officially WinNT4/Win9x only):
4385 * Fast: Only the registry is queried to retrieve printer names,
4386 * no connection to the driver is made.
4387 * Returns an array of PRINTER_INFO_5 data structures in the
4388 * lpbPrinters buffer.
4390 * If level set to 3 or 6+:
4391 * returns zero (failure!)
4393 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4397 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4398 * - Only levels 2, 4 and 5 are implemented at the moment.
4399 * - 16-bit printer drivers are not enumerated.
4400 * - Returned amount of bytes used/needed does not match the real Windoze
4401 * implementation (as in this implementation, all strings are part
4402 * of the buffer, whereas Win32 keeps them somewhere else)
4403 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4406 * - In a regular Wine installation, no registry settings for printers
4407 * exist, which makes this function return an empty list.
4409 BOOL WINAPI
EnumPrintersW(
4410 DWORD dwType
, /* [in] Types of print objects to enumerate */
4411 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4412 DWORD dwLevel
, /* [in] type of printer info structure */
4413 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4414 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4415 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4416 LPDWORD lpdwReturned
/* [out] number of entries returned */
4419 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4420 lpdwNeeded
, lpdwReturned
, TRUE
);
4423 /******************************************************************
4424 * EnumPrintersA [WINSPOOL.@]
4429 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4430 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4433 UNICODE_STRING pNameU
;
4437 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4438 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4440 pNameW
= asciitounicode(&pNameU
, pName
);
4442 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4443 MS Office need this */
4444 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4446 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4448 RtlFreeUnicodeString(&pNameU
);
4450 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4452 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4456 /*****************************************************************************
4457 * WINSPOOL_GetDriverInfoFromReg [internal]
4459 * Enters the information from the registry into the DRIVER_INFO struct
4462 * zero if the printer driver does not exist in the registry
4463 * (only if Level > 1) otherwise nonzero
4465 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4468 const printenv_t
* env
,
4470 LPBYTE ptr
, /* DRIVER_INFO */
4471 LPBYTE pDriverStrings
, /* strings buffer */
4472 DWORD cbBuf
, /* size of string buffer */
4473 LPDWORD pcbNeeded
, /* space needed for str. */
4474 BOOL unicode
) /* type of strings */
4478 WCHAR driverdir
[MAX_PATH
];
4480 LPBYTE strPtr
= pDriverStrings
;
4481 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4483 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers
,
4484 debugstr_w(DriverName
), env
,
4485 Level
, di
, pDriverStrings
, cbBuf
, unicode
);
4487 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4490 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4491 if (*pcbNeeded
<= cbBuf
)
4492 strcpyW((LPWSTR
)strPtr
, DriverName
);
4496 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0, NULL
, NULL
);
4497 if (*pcbNeeded
<= cbBuf
)
4498 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
4501 /* pName for level 1 has a different offset! */
4503 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4507 /* .cVersion and .pName for level > 1 */
4509 di
->cVersion
= env
->driverversion
;
4510 di
->pName
= (LPWSTR
) strPtr
;
4511 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4514 /* Reserve Space for the largest subdir and a Backslash*/
4515 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4516 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4517 /* Should never Fail */
4520 lstrcatW(driverdir
, env
->versionsubdir
);
4521 lstrcatW(driverdir
, backslashW
);
4523 /* dirlen must not include the terminating zero */
4524 dirlen
= (unicode
) ? lstrlenW(driverdir
) * sizeof(WCHAR
) :
4525 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, NULL
, 0, NULL
, NULL
) -1;
4527 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4528 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4529 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4535 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4537 size
= WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, NULL
, 0, NULL
, NULL
);
4540 if (*pcbNeeded
<= cbBuf
) {
4542 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4546 WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, (LPSTR
)strPtr
, size
, NULL
, NULL
);
4548 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4549 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4552 /* .pDriverPath is the Graphics rendering engine.
4553 The full Path is required to avoid a crash in some apps */
4554 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
, unicode
)) {
4556 if (*pcbNeeded
<= cbBuf
)
4557 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
, unicode
);
4559 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4560 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4563 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4564 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
, unicode
)) {
4566 if (*pcbNeeded
<= cbBuf
)
4567 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
, unicode
);
4569 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4570 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4573 /* .pConfigFile is the Driver user Interface */
4574 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
, unicode
)) {
4576 if (*pcbNeeded
<= cbBuf
)
4577 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
, unicode
);
4579 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4580 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4584 RegCloseKey(hkeyDriver
);
4585 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4590 RegCloseKey(hkeyDriver
);
4591 FIXME("level 5: incomplete\n");
4596 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
, unicode
)) {
4598 if (*pcbNeeded
<= cbBuf
)
4599 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
, unicode
);
4601 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4602 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4605 /* .pDependentFiles */
4606 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
, unicode
)) {
4608 if (*pcbNeeded
<= cbBuf
)
4609 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
, unicode
);
4611 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4612 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4614 else if (GetVersion() & 0x80000000) {
4615 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4616 size
= 2 * ((unicode
) ? sizeof(WCHAR
) : 1);
4618 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4620 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4621 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4624 /* .pMonitorName is the optional Language Monitor */
4625 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
, unicode
)) {
4627 if (*pcbNeeded
<= cbBuf
)
4628 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
, unicode
);
4630 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4631 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4634 /* .pDefaultDataType */
4635 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
, unicode
)) {
4637 if(*pcbNeeded
<= cbBuf
)
4638 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
, unicode
);
4640 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4641 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4645 RegCloseKey(hkeyDriver
);
4646 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4650 /* .pszzPreviousNames */
4651 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
, unicode
)) {
4653 if(*pcbNeeded
<= cbBuf
)
4654 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
, unicode
);
4656 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4657 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4661 RegCloseKey(hkeyDriver
);
4662 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4666 /* support is missing, but not important enough for a FIXME */
4667 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4670 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
, unicode
)) {
4672 if(*pcbNeeded
<= cbBuf
)
4673 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
, unicode
);
4675 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4676 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4680 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
, unicode
)) {
4682 if(*pcbNeeded
<= cbBuf
)
4683 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
, unicode
);
4685 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4686 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4689 /* .pszHardwareID */
4690 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
, unicode
)) {
4692 if(*pcbNeeded
<= cbBuf
)
4693 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
, unicode
);
4695 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4696 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4700 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
, unicode
)) {
4702 if(*pcbNeeded
<= cbBuf
)
4703 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
, unicode
);
4705 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4706 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4710 RegCloseKey(hkeyDriver
);
4714 /* support is missing, but not important enough for a FIXME */
4715 TRACE("level 8: incomplete\n");
4717 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4718 RegCloseKey(hkeyDriver
);
4722 /*****************************************************************************
4723 * WINSPOOL_GetPrinterDriver
4725 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPCWSTR pEnvironment
,
4726 DWORD Level
, LPBYTE pDriverInfo
,
4727 DWORD cbBuf
, LPDWORD pcbNeeded
,
4731 WCHAR DriverName
[100];
4732 DWORD ret
, type
, size
, needed
= 0;
4734 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4735 const printenv_t
* env
;
4737 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4738 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4741 if (!(name
= get_opened_printer_name(hPrinter
))) {
4742 SetLastError(ERROR_INVALID_HANDLE
);
4746 if (Level
< 1 || Level
== 7 || Level
> 8) {
4747 SetLastError(ERROR_INVALID_LEVEL
);
4751 env
= validate_envW(pEnvironment
);
4752 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4754 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4756 ERR("Can't create Printers key\n");
4759 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4761 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4762 RegCloseKey(hkeyPrinters
);
4763 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4766 size
= sizeof(DriverName
);
4768 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4769 (LPBYTE
)DriverName
, &size
);
4770 RegCloseKey(hkeyPrinter
);
4771 RegCloseKey(hkeyPrinters
);
4772 if(ret
!= ERROR_SUCCESS
) {
4773 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4777 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
4779 ERR("Can't create Drivers key\n");
4783 size
= di_sizeof
[Level
];
4784 if ((size
<= cbBuf
) && pDriverInfo
)
4785 ptr
= pDriverInfo
+ size
;
4787 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4788 env
, Level
, pDriverInfo
, ptr
,
4789 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4790 &needed
, unicode
)) {
4791 RegCloseKey(hkeyDrivers
);
4795 RegCloseKey(hkeyDrivers
);
4797 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4798 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4799 if(cbBuf
>= needed
) return TRUE
;
4800 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4804 /*****************************************************************************
4805 * GetPrinterDriverA [WINSPOOL.@]
4807 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4808 DWORD Level
, LPBYTE pDriverInfo
,
4809 DWORD cbBuf
, LPDWORD pcbNeeded
)
4812 UNICODE_STRING pEnvW
;
4815 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4816 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
4817 cbBuf
, pcbNeeded
, FALSE
);
4818 RtlFreeUnicodeString(&pEnvW
);
4821 /*****************************************************************************
4822 * GetPrinterDriverW [WINSPOOL.@]
4824 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4825 DWORD Level
, LPBYTE pDriverInfo
,
4826 DWORD cbBuf
, LPDWORD pcbNeeded
)
4828 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
4829 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
4832 /*****************************************************************************
4833 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4835 * Return the PATH for the Printer-Drivers (UNICODE)
4838 * pName [I] Servername (NT only) or NULL (local Computer)
4839 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4840 * Level [I] Structure-Level (must be 1)
4841 * pDriverDirectory [O] PTR to Buffer that receives the Result
4842 * cbBuf [I] Size of Buffer at pDriverDirectory
4843 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4844 * required for pDriverDirectory
4847 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4848 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4849 * if cbBuf is too small
4851 * Native Values returned in pDriverDirectory on Success:
4852 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4853 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4854 *| win9x(Windows 4.0): "%winsysdir%"
4856 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4859 *- Only NULL or "" is supported for pName
4862 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4863 DWORD Level
, LPBYTE pDriverDirectory
,
4864 DWORD cbBuf
, LPDWORD pcbNeeded
)
4866 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4867 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4869 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4872 /* (Level != 1) is ignored in win9x */
4873 SetLastError(ERROR_INVALID_LEVEL
);
4876 if (pcbNeeded
== NULL
) {
4877 /* (pcbNeeded == NULL) is ignored in win9x */
4878 SetLastError(RPC_X_NULL_REF_POINTER
);
4882 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
4883 pDriverDirectory
, cbBuf
, pcbNeeded
);
4888 /*****************************************************************************
4889 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4891 * Return the PATH for the Printer-Drivers (ANSI)
4893 * See GetPrinterDriverDirectoryW.
4896 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4899 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4900 DWORD Level
, LPBYTE pDriverDirectory
,
4901 DWORD cbBuf
, LPDWORD pcbNeeded
)
4903 UNICODE_STRING nameW
, environmentW
;
4906 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4907 WCHAR
*driverDirectoryW
= NULL
;
4909 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4910 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4912 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4914 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4915 else nameW
.Buffer
= NULL
;
4916 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4917 else environmentW
.Buffer
= NULL
;
4919 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4920 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4923 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4924 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4926 *pcbNeeded
= needed
;
4927 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4929 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4931 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4933 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4934 RtlFreeUnicodeString(&environmentW
);
4935 RtlFreeUnicodeString(&nameW
);
4940 /*****************************************************************************
4941 * AddPrinterDriverA [WINSPOOL.@]
4943 * See AddPrinterDriverW.
4946 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4948 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4949 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4952 /******************************************************************************
4953 * AddPrinterDriverW (WINSPOOL.@)
4955 * Install a Printer Driver
4958 * pName [I] Servername or NULL (local Computer)
4959 * level [I] Level for the supplied DRIVER_INFO_*W struct
4960 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4967 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4969 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
4970 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4973 /*****************************************************************************
4974 * AddPrintProcessorA [WINSPOOL.@]
4976 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4977 LPSTR pPrintProcessorName
)
4979 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4980 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4984 /*****************************************************************************
4985 * AddPrintProcessorW [WINSPOOL.@]
4987 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4988 LPWSTR pPrintProcessorName
)
4990 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4991 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4995 /*****************************************************************************
4996 * AddPrintProvidorA [WINSPOOL.@]
4998 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5000 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5004 /*****************************************************************************
5005 * AddPrintProvidorW [WINSPOOL.@]
5007 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5009 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5013 /*****************************************************************************
5014 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5016 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5017 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5019 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5020 pDevModeOutput
, pDevModeInput
);
5024 /*****************************************************************************
5025 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5027 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5028 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5030 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5031 pDevModeOutput
, pDevModeInput
);
5035 /*****************************************************************************
5036 * PrinterProperties [WINSPOOL.@]
5038 * Displays a dialog to set the properties of the printer.
5041 * nonzero on success or zero on failure
5044 * implemented as stub only
5046 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5047 HANDLE hPrinter
/* [in] handle to printer object */
5049 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5050 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5054 /*****************************************************************************
5055 * EnumJobsA [WINSPOOL.@]
5058 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5059 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5062 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5063 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5065 if(pcbNeeded
) *pcbNeeded
= 0;
5066 if(pcReturned
) *pcReturned
= 0;
5071 /*****************************************************************************
5072 * EnumJobsW [WINSPOOL.@]
5075 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5076 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5079 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5080 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5082 if(pcbNeeded
) *pcbNeeded
= 0;
5083 if(pcReturned
) *pcReturned
= 0;
5087 /*****************************************************************************
5088 * WINSPOOL_EnumPrinterDrivers [internal]
5090 * Delivers information about all printer drivers installed on the
5091 * localhost or a given server
5094 * nonzero on success or zero on failure. If the buffer for the returned
5095 * information is too small the function will return an error
5098 * - only implemented for localhost, foreign hosts will return an error
5100 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5101 DWORD Level
, LPBYTE pDriverInfo
,
5102 DWORD cbBuf
, LPDWORD pcbNeeded
,
5103 LPDWORD pcReturned
, BOOL unicode
)
5106 DWORD i
, needed
, number
= 0, size
= 0;
5107 WCHAR DriverNameW
[255];
5109 const printenv_t
* env
;
5111 TRACE("%s,%s,%d,%p,%d,%d\n",
5112 debugstr_w(pName
), debugstr_w(pEnvironment
),
5113 Level
, pDriverInfo
, cbBuf
, unicode
);
5115 /* check for local drivers */
5116 if((pName
) && (pName
[0])) {
5117 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5118 SetLastError(ERROR_ACCESS_DENIED
);
5122 env
= validate_envW(pEnvironment
);
5123 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5125 /* check input parameter */
5126 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5127 SetLastError(ERROR_INVALID_LEVEL
);
5131 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
)) {
5132 SetLastError(RPC_X_NULL_REF_POINTER
);
5136 /* initialize return values */
5138 memset( pDriverInfo
, 0, cbBuf
);
5142 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
5144 ERR("Can't open Drivers key\n");
5148 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
5149 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5150 RegCloseKey(hkeyDrivers
);
5151 ERR("Can't query Drivers key\n");
5154 TRACE("Found %d Drivers\n", number
);
5156 /* get size of single struct
5157 * unicode and ascii structure have the same size
5159 size
= di_sizeof
[Level
];
5161 /* calculate required buffer size */
5162 *pcbNeeded
= size
* number
;
5164 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
5166 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
5167 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
5169 ERR("Can't enum key number %d\n", i
);
5170 RegCloseKey(hkeyDrivers
);
5173 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5175 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
5176 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5177 &needed
, unicode
)) {
5178 RegCloseKey(hkeyDrivers
);
5181 *pcbNeeded
+= needed
;
5184 RegCloseKey(hkeyDrivers
);
5186 if(cbBuf
< *pcbNeeded
){
5187 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5191 *pcReturned
= number
;
5195 /*****************************************************************************
5196 * EnumPrinterDriversW [WINSPOOL.@]
5198 * see function EnumPrinterDrivers for RETURNS, BUGS
5200 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5201 LPBYTE pDriverInfo
, DWORD cbBuf
,
5202 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5204 static const WCHAR allW
[] = {'a','l','l',0};
5206 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
5209 DWORD i
, needed
, returned
, bufsize
= cbBuf
;
5211 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5213 needed
= returned
= 0;
5214 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
5215 pDriverInfo
, bufsize
, &needed
, &returned
, TRUE
);
5216 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5220 if (pDriverInfo
) pDriverInfo
+= needed
;
5221 if (pcReturned
) *pcReturned
+= returned
;
5223 if (pcbNeeded
) *pcbNeeded
+= needed
;
5227 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5228 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
5231 /*****************************************************************************
5232 * EnumPrinterDriversA [WINSPOOL.@]
5234 * see function EnumPrinterDrivers for RETURNS, BUGS
5236 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5237 LPBYTE pDriverInfo
, DWORD cbBuf
,
5238 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5241 UNICODE_STRING pNameW
, pEnvironmentW
;
5242 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5244 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5245 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5247 if (pEnvironment
&& !strcmp(pEnvironment
, "all"))
5249 DWORD i
, needed
, returned
, bufsize
= cbBuf
;
5251 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5253 needed
= returned
= 0;
5254 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, all_printenv
[i
]->envname
, Level
,
5255 pDriverInfo
, bufsize
, &needed
, &returned
, FALSE
);
5256 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) break;
5260 if (pDriverInfo
) pDriverInfo
+= needed
;
5261 if (pcReturned
) *pcReturned
+= returned
;
5263 if (pcbNeeded
) *pcbNeeded
+= needed
;
5266 else ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
5267 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
5269 RtlFreeUnicodeString(&pNameW
);
5270 RtlFreeUnicodeString(&pEnvironmentW
);
5275 /******************************************************************************
5276 * EnumPortsA (WINSPOOL.@)
5281 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5282 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5285 LPBYTE bufferW
= NULL
;
5286 LPWSTR nameW
= NULL
;
5288 DWORD numentries
= 0;
5291 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5292 cbBuf
, pcbNeeded
, pcReturned
);
5294 /* convert servername to unicode */
5296 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5297 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5298 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5300 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5301 needed
= cbBuf
* sizeof(WCHAR
);
5302 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5303 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5305 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5306 if (pcbNeeded
) needed
= *pcbNeeded
;
5307 /* HeapReAlloc return NULL, when bufferW was NULL */
5308 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5309 HeapAlloc(GetProcessHeap(), 0, needed
);
5311 /* Try again with the large Buffer */
5312 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5314 needed
= pcbNeeded
? *pcbNeeded
: 0;
5315 numentries
= pcReturned
? *pcReturned
: 0;
5318 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5319 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5322 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5323 DWORD entrysize
= 0;
5326 LPPORT_INFO_2W pi2w
;
5327 LPPORT_INFO_2A pi2a
;
5330 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5332 /* First pass: calculate the size for all Entries */
5333 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5334 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5336 while (index
< numentries
) {
5338 needed
+= entrysize
; /* PORT_INFO_?A */
5339 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5341 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5342 NULL
, 0, NULL
, NULL
);
5344 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5345 NULL
, 0, NULL
, NULL
);
5346 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5347 NULL
, 0, NULL
, NULL
);
5349 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5350 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5351 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5354 /* check for errors and quit on failure */
5355 if (cbBuf
< needed
) {
5356 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5360 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5361 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5362 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5363 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5364 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5366 /* Second Pass: Fill the User Buffer (if we have one) */
5367 while ((index
< numentries
) && pPorts
) {
5369 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5370 pi2a
->pPortName
= ptr
;
5371 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5372 ptr
, cbBuf
, NULL
, NULL
);
5376 pi2a
->pMonitorName
= ptr
;
5377 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5378 ptr
, cbBuf
, NULL
, NULL
);
5382 pi2a
->pDescription
= ptr
;
5383 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5384 ptr
, cbBuf
, NULL
, NULL
);
5388 pi2a
->fPortType
= pi2w
->fPortType
;
5389 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5392 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5393 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5394 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5399 if (pcbNeeded
) *pcbNeeded
= needed
;
5400 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5402 HeapFree(GetProcessHeap(), 0, nameW
);
5403 HeapFree(GetProcessHeap(), 0, bufferW
);
5405 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5406 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5412 /******************************************************************************
5413 * EnumPortsW (WINSPOOL.@)
5415 * Enumerate available Ports
5418 * pName [I] Servername or NULL (local Computer)
5419 * Level [I] Structure-Level (1 or 2)
5420 * pPorts [O] PTR to Buffer that receives the Result
5421 * cbBuf [I] Size of Buffer at pPorts
5422 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5423 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5427 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5430 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5433 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5434 cbBuf
, pcbNeeded
, pcReturned
);
5436 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5438 /* Level is not checked in win9x */
5439 if (!Level
|| (Level
> 2)) {
5440 WARN("level (%d) is ignored in win9x\n", Level
);
5441 SetLastError(ERROR_INVALID_LEVEL
);
5444 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5445 SetLastError(RPC_X_NULL_REF_POINTER
);
5449 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5452 /******************************************************************************
5453 * GetDefaultPrinterW (WINSPOOL.@)
5456 * This function must read the value from data 'device' of key
5457 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5459 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5463 WCHAR
*buffer
, *ptr
;
5467 SetLastError(ERROR_INVALID_PARAMETER
);
5471 /* make the buffer big enough for the stuff from the profile/registry,
5472 * the content must fit into the local buffer to compute the correct
5473 * size even if the extern buffer is too small or not given.
5474 * (20 for ,driver,port) */
5476 len
= max(100, (insize
+ 20));
5477 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5479 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5481 SetLastError (ERROR_FILE_NOT_FOUND
);
5485 TRACE("%s\n", debugstr_w(buffer
));
5487 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5489 SetLastError(ERROR_INVALID_NAME
);
5495 *namesize
= strlenW(buffer
) + 1;
5496 if(!name
|| (*namesize
> insize
))
5498 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5502 strcpyW(name
, buffer
);
5505 HeapFree( GetProcessHeap(), 0, buffer
);
5510 /******************************************************************************
5511 * GetDefaultPrinterA (WINSPOOL.@)
5513 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5517 WCHAR
*bufferW
= NULL
;
5521 SetLastError(ERROR_INVALID_PARAMETER
);
5525 if(name
&& *namesize
) {
5527 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5530 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5535 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5539 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5542 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5545 HeapFree( GetProcessHeap(), 0, bufferW
);
5550 /******************************************************************************
5551 * SetDefaultPrinterW (WINSPOOL.204)
5553 * Set the Name of the Default Printer
5556 * pszPrinter [I] Name of the Printer or NULL
5563 * When the Parameter is NULL or points to an Empty String and
5564 * a Default Printer was already present, then this Function changes nothing.
5565 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5566 * the First enumerated local Printer is used.
5569 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5572 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5574 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5578 /******************************************************************************
5579 * SetDefaultPrinterA (WINSPOOL.202)
5581 * See SetDefaultPrinterW.
5584 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5587 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5589 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5594 /******************************************************************************
5595 * SetPrinterDataExA (WINSPOOL.@)
5597 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5598 LPCSTR pValueName
, DWORD Type
,
5599 LPBYTE pData
, DWORD cbData
)
5601 HKEY hkeyPrinter
, hkeySubkey
;
5604 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5605 debugstr_a(pValueName
), Type
, pData
, cbData
);
5607 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5611 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5613 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5614 RegCloseKey(hkeyPrinter
);
5617 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5618 RegCloseKey(hkeySubkey
);
5619 RegCloseKey(hkeyPrinter
);
5623 /******************************************************************************
5624 * SetPrinterDataExW (WINSPOOL.@)
5626 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5627 LPCWSTR pValueName
, DWORD Type
,
5628 LPBYTE pData
, DWORD cbData
)
5630 HKEY hkeyPrinter
, hkeySubkey
;
5633 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5634 debugstr_w(pValueName
), Type
, pData
, cbData
);
5636 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5640 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5642 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5643 RegCloseKey(hkeyPrinter
);
5646 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5647 RegCloseKey(hkeySubkey
);
5648 RegCloseKey(hkeyPrinter
);
5652 /******************************************************************************
5653 * SetPrinterDataA (WINSPOOL.@)
5655 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5656 LPBYTE pData
, DWORD cbData
)
5658 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5662 /******************************************************************************
5663 * SetPrinterDataW (WINSPOOL.@)
5665 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5666 LPBYTE pData
, DWORD cbData
)
5668 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5672 /******************************************************************************
5673 * GetPrinterDataExA (WINSPOOL.@)
5675 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5676 LPCSTR pValueName
, LPDWORD pType
,
5677 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5679 HKEY hkeyPrinter
, hkeySubkey
;
5682 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5683 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
5686 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5690 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5692 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
5693 RegCloseKey(hkeyPrinter
);
5697 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5698 RegCloseKey(hkeySubkey
);
5699 RegCloseKey(hkeyPrinter
);
5703 /******************************************************************************
5704 * GetPrinterDataExW (WINSPOOL.@)
5706 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5707 LPCWSTR pValueName
, LPDWORD pType
,
5708 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5710 HKEY hkeyPrinter
, hkeySubkey
;
5713 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5714 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
5717 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5721 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5723 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
5724 RegCloseKey(hkeyPrinter
);
5728 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5729 RegCloseKey(hkeySubkey
);
5730 RegCloseKey(hkeyPrinter
);
5734 /******************************************************************************
5735 * GetPrinterDataA (WINSPOOL.@)
5737 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5738 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5740 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5741 pData
, nSize
, pcbNeeded
);
5744 /******************************************************************************
5745 * GetPrinterDataW (WINSPOOL.@)
5747 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5748 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5750 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5751 pData
, nSize
, pcbNeeded
);
5754 /*******************************************************************************
5755 * EnumPrinterDataExW [WINSPOOL.@]
5757 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5758 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5759 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5761 HKEY hkPrinter
, hkSubKey
;
5762 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5763 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5768 PPRINTER_ENUM_VALUESW ppev
;
5770 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5772 if (pKeyName
== NULL
|| *pKeyName
== 0)
5773 return ERROR_INVALID_PARAMETER
;
5775 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5776 if (ret
!= ERROR_SUCCESS
)
5778 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5783 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5784 if (ret
!= ERROR_SUCCESS
)
5786 r
= RegCloseKey (hkPrinter
);
5787 if (r
!= ERROR_SUCCESS
)
5788 WARN ("RegCloseKey returned %i\n", r
);
5789 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5790 debugstr_w (pKeyName
), ret
);
5794 ret
= RegCloseKey (hkPrinter
);
5795 if (ret
!= ERROR_SUCCESS
)
5797 ERR ("RegCloseKey returned %i\n", ret
);
5798 r
= RegCloseKey (hkSubKey
);
5799 if (r
!= ERROR_SUCCESS
)
5800 WARN ("RegCloseKey returned %i\n", r
);
5804 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5805 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5806 if (ret
!= ERROR_SUCCESS
)
5808 r
= RegCloseKey (hkSubKey
);
5809 if (r
!= ERROR_SUCCESS
)
5810 WARN ("RegCloseKey returned %i\n", r
);
5811 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5815 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5816 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5818 if (cValues
== 0) /* empty key */
5820 r
= RegCloseKey (hkSubKey
);
5821 if (r
!= ERROR_SUCCESS
)
5822 WARN ("RegCloseKey returned %i\n", r
);
5823 *pcbEnumValues
= *pnEnumValues
= 0;
5824 return ERROR_SUCCESS
;
5827 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5829 hHeap
= GetProcessHeap ();
5832 ERR ("GetProcessHeap failed\n");
5833 r
= RegCloseKey (hkSubKey
);
5834 if (r
!= ERROR_SUCCESS
)
5835 WARN ("RegCloseKey returned %i\n", r
);
5836 return ERROR_OUTOFMEMORY
;
5839 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5840 if (lpValueName
== NULL
)
5842 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5843 r
= RegCloseKey (hkSubKey
);
5844 if (r
!= ERROR_SUCCESS
)
5845 WARN ("RegCloseKey returned %i\n", r
);
5846 return ERROR_OUTOFMEMORY
;
5849 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5850 if (lpValue
== NULL
)
5852 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5853 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5854 WARN ("HeapFree failed with code %i\n", GetLastError ());
5855 r
= RegCloseKey (hkSubKey
);
5856 if (r
!= ERROR_SUCCESS
)
5857 WARN ("RegCloseKey returned %i\n", r
);
5858 return ERROR_OUTOFMEMORY
;
5861 TRACE ("pass 1: calculating buffer required for all names and values\n");
5863 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5865 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5867 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5869 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5870 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5871 NULL
, NULL
, lpValue
, &cbValueLen
);
5872 if (ret
!= ERROR_SUCCESS
)
5874 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5875 WARN ("HeapFree failed with code %i\n", GetLastError ());
5876 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5877 WARN ("HeapFree failed with code %i\n", GetLastError ());
5878 r
= RegCloseKey (hkSubKey
);
5879 if (r
!= ERROR_SUCCESS
)
5880 WARN ("RegCloseKey returned %i\n", r
);
5881 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5885 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5886 debugstr_w (lpValueName
), dwIndex
,
5887 cbValueNameLen
+ 1, cbValueLen
);
5889 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5890 cbBufSize
+= cbValueLen
;
5893 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5895 *pcbEnumValues
= cbBufSize
;
5896 *pnEnumValues
= cValues
;
5898 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5900 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5901 WARN ("HeapFree failed with code %i\n", GetLastError ());
5902 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5903 WARN ("HeapFree failed with code %i\n", GetLastError ());
5904 r
= RegCloseKey (hkSubKey
);
5905 if (r
!= ERROR_SUCCESS
)
5906 WARN ("RegCloseKey returned %i\n", r
);
5907 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5908 return ERROR_MORE_DATA
;
5911 TRACE ("pass 2: copying all names and values to buffer\n");
5913 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5914 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5916 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5918 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5919 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5920 NULL
, &dwType
, lpValue
, &cbValueLen
);
5921 if (ret
!= ERROR_SUCCESS
)
5923 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5924 WARN ("HeapFree failed with code %i\n", GetLastError ());
5925 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5926 WARN ("HeapFree failed with code %i\n", GetLastError ());
5927 r
= RegCloseKey (hkSubKey
);
5928 if (r
!= ERROR_SUCCESS
)
5929 WARN ("RegCloseKey returned %i\n", r
);
5930 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5934 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5935 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5936 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5937 pEnumValues
+= cbValueNameLen
;
5939 /* return # of *bytes* (including trailing \0), not # of chars */
5940 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5942 ppev
[dwIndex
].dwType
= dwType
;
5944 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5945 ppev
[dwIndex
].pData
= pEnumValues
;
5946 pEnumValues
+= cbValueLen
;
5948 ppev
[dwIndex
].cbData
= cbValueLen
;
5950 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5951 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5954 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5956 ret
= GetLastError ();
5957 ERR ("HeapFree failed with code %i\n", ret
);
5958 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5959 WARN ("HeapFree failed with code %i\n", GetLastError ());
5960 r
= RegCloseKey (hkSubKey
);
5961 if (r
!= ERROR_SUCCESS
)
5962 WARN ("RegCloseKey returned %i\n", r
);
5966 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5968 ret
= GetLastError ();
5969 ERR ("HeapFree failed with code %i\n", ret
);
5970 r
= RegCloseKey (hkSubKey
);
5971 if (r
!= ERROR_SUCCESS
)
5972 WARN ("RegCloseKey returned %i\n", r
);
5976 ret
= RegCloseKey (hkSubKey
);
5977 if (ret
!= ERROR_SUCCESS
)
5979 ERR ("RegCloseKey returned %i\n", ret
);
5983 return ERROR_SUCCESS
;
5986 /*******************************************************************************
5987 * EnumPrinterDataExA [WINSPOOL.@]
5989 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5990 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5991 * what Windows 2000 SP1 does.
5994 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5995 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5996 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6000 DWORD ret
, dwIndex
, dwBufSize
;
6004 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6006 if (pKeyName
== NULL
|| *pKeyName
== 0)
6007 return ERROR_INVALID_PARAMETER
;
6009 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6012 ret
= GetLastError ();
6013 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6017 hHeap
= GetProcessHeap ();
6020 ERR ("GetProcessHeap failed\n");
6021 return ERROR_OUTOFMEMORY
;
6024 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6025 if (pKeyNameW
== NULL
)
6027 ERR ("Failed to allocate %i bytes from process heap\n",
6028 (LONG
)(len
* sizeof (WCHAR
)));
6029 return ERROR_OUTOFMEMORY
;
6032 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6034 ret
= GetLastError ();
6035 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6036 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6037 WARN ("HeapFree failed with code %i\n", GetLastError ());
6041 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6042 pcbEnumValues
, pnEnumValues
);
6043 if (ret
!= ERROR_SUCCESS
)
6045 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6046 WARN ("HeapFree failed with code %i\n", GetLastError ());
6047 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6051 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6053 ret
= GetLastError ();
6054 ERR ("HeapFree failed with code %i\n", ret
);
6058 if (*pnEnumValues
== 0) /* empty key */
6059 return ERROR_SUCCESS
;
6062 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6064 PPRINTER_ENUM_VALUESW ppev
=
6065 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6067 if (dwBufSize
< ppev
->cbValueName
)
6068 dwBufSize
= ppev
->cbValueName
;
6070 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6071 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6072 dwBufSize
= ppev
->cbData
;
6075 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6077 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6078 if (pBuffer
== NULL
)
6080 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6081 return ERROR_OUTOFMEMORY
;
6084 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6086 PPRINTER_ENUM_VALUESW ppev
=
6087 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6089 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6090 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6094 ret
= GetLastError ();
6095 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6096 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6097 WARN ("HeapFree failed with code %i\n", GetLastError ());
6101 memcpy (ppev
->pValueName
, pBuffer
, len
);
6103 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6105 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6106 ppev
->dwType
!= REG_MULTI_SZ
)
6109 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6110 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6113 ret
= GetLastError ();
6114 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6115 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6116 WARN ("HeapFree failed with code %i\n", GetLastError ());
6120 memcpy (ppev
->pData
, pBuffer
, len
);
6122 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6123 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6126 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6128 ret
= GetLastError ();
6129 ERR ("HeapFree failed with code %i\n", ret
);
6133 return ERROR_SUCCESS
;
6136 /******************************************************************************
6137 * AbortPrinter (WINSPOOL.@)
6139 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6141 FIXME("(%p), stub!\n", hPrinter
);
6145 /******************************************************************************
6146 * AddPortA (WINSPOOL.@)
6151 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6153 LPWSTR nameW
= NULL
;
6154 LPWSTR monitorW
= NULL
;
6158 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6161 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6162 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6163 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6167 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6168 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6169 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6171 res
= AddPortW(nameW
, hWnd
, monitorW
);
6172 HeapFree(GetProcessHeap(), 0, nameW
);
6173 HeapFree(GetProcessHeap(), 0, monitorW
);
6177 /******************************************************************************
6178 * AddPortW (WINSPOOL.@)
6180 * Add a Port for a specific Monitor
6183 * pName [I] Servername or NULL (local Computer)
6184 * hWnd [I] Handle to parent Window for the Dialog-Box
6185 * pMonitorName [I] Name of the Monitor that manage the Port
6192 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6198 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6200 if (pName
&& pName
[0]) {
6201 SetLastError(ERROR_INVALID_PARAMETER
);
6205 if (!pMonitorName
) {
6206 SetLastError(RPC_X_NULL_REF_POINTER
);
6210 /* an empty Monitorname is Invalid */
6211 if (!pMonitorName
[0]) {
6212 SetLastError(ERROR_NOT_SUPPORTED
);
6216 pm
= monitor_load(pMonitorName
, NULL
);
6217 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
6218 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
6219 TRACE("got %d with %u\n", res
, GetLastError());
6224 pui
= monitor_loadui(pm
);
6225 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
6226 TRACE("use %p: %s\n", pui
, debugstr_w(pui
->dllname
));
6227 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
6228 TRACE("got %d with %u\n", res
, GetLastError());
6233 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName
),
6234 pm
, debugstr_w(pm
? pm
->dllname
: NULL
), pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
6236 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6237 SetLastError(ERROR_NOT_SUPPORTED
);
6240 monitor_unload(pui
);
6243 TRACE("returning %d with %u\n", res
, GetLastError());
6247 /******************************************************************************
6248 * AddPortExA (WINSPOOL.@)
6253 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6256 PORT_INFO_2A
* pi2A
;
6257 LPWSTR nameW
= NULL
;
6258 LPWSTR monitorW
= NULL
;
6262 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6264 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6265 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6267 if ((level
< 1) || (level
> 2)) {
6268 SetLastError(ERROR_INVALID_LEVEL
);
6273 SetLastError(ERROR_INVALID_PARAMETER
);
6278 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6279 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6280 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6284 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6285 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6286 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6289 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6291 if (pi2A
->pPortName
) {
6292 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6293 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6294 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6298 if (pi2A
->pMonitorName
) {
6299 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6300 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6301 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6304 if (pi2A
->pDescription
) {
6305 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6306 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6307 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6309 pi2W
.fPortType
= pi2A
->fPortType
;
6310 pi2W
.Reserved
= pi2A
->Reserved
;
6313 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6315 HeapFree(GetProcessHeap(), 0, nameW
);
6316 HeapFree(GetProcessHeap(), 0, monitorW
);
6317 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6318 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6319 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6324 /******************************************************************************
6325 * AddPortExW (WINSPOOL.@)
6327 * Add a Port for a specific Monitor, without presenting a user interface
6330 * pName [I] Servername or NULL (local Computer)
6331 * level [I] Structure-Level (1 or 2) for pBuffer
6332 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6333 * pMonitorName [I] Name of the Monitor that manage the Port
6340 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6346 pi2
= (PORT_INFO_2W
*) pBuffer
;
6348 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6349 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6350 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6351 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6354 if ((level
< 1) || (level
> 2)) {
6355 SetLastError(ERROR_INVALID_LEVEL
);
6359 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6360 SetLastError(ERROR_INVALID_PARAMETER
);
6364 /* load the Monitor */
6365 pm
= monitor_load(pMonitorName
, NULL
);
6367 SetLastError(ERROR_INVALID_PARAMETER
);
6371 if (pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
6372 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6373 TRACE("got %u with %u\n", res
, GetLastError());
6377 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName
), pm
->monitor
);
6383 /******************************************************************************
6384 * AddPrinterConnectionA (WINSPOOL.@)
6386 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6388 FIXME("%s\n", debugstr_a(pName
));
6392 /******************************************************************************
6393 * AddPrinterConnectionW (WINSPOOL.@)
6395 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6397 FIXME("%s\n", debugstr_w(pName
));
6401 /******************************************************************************
6402 * AddPrinterDriverExW (WINSPOOL.@)
6404 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6407 * pName [I] Servername or NULL (local Computer)
6408 * level [I] Level for the supplied DRIVER_INFO_*W struct
6409 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6410 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6417 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6419 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6421 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6423 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6424 SetLastError(ERROR_INVALID_LEVEL
);
6429 SetLastError(ERROR_INVALID_PARAMETER
);
6433 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6436 /******************************************************************************
6437 * AddPrinterDriverExA (WINSPOOL.@)
6439 * See AddPrinterDriverExW.
6442 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6444 DRIVER_INFO_8A
*diA
;
6446 LPWSTR nameW
= NULL
;
6451 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6453 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6454 ZeroMemory(&diW
, sizeof(diW
));
6456 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6457 SetLastError(ERROR_INVALID_LEVEL
);
6462 SetLastError(ERROR_INVALID_PARAMETER
);
6466 /* convert servername to unicode */
6468 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6469 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6470 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6474 diW
.cVersion
= diA
->cVersion
;
6477 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6478 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6479 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6482 if (diA
->pEnvironment
) {
6483 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6484 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6485 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6488 if (diA
->pDriverPath
) {
6489 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6490 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6491 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6494 if (diA
->pDataFile
) {
6495 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6496 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6497 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6500 if (diA
->pConfigFile
) {
6501 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6502 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6503 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6506 if ((Level
> 2) && diA
->pDependentFiles
) {
6507 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6508 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6509 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6510 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6513 if ((Level
> 2) && diA
->pMonitorName
) {
6514 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6515 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6516 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6519 if ((Level
> 3) && diA
->pDefaultDataType
) {
6520 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6521 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6522 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6525 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6526 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6527 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6528 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6529 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6532 if ((Level
> 5) && diA
->pszMfgName
) {
6533 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6534 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6535 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6538 if ((Level
> 5) && diA
->pszOEMUrl
) {
6539 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6540 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6541 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6544 if ((Level
> 5) && diA
->pszHardwareID
) {
6545 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6546 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6547 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6550 if ((Level
> 5) && diA
->pszProvider
) {
6551 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6552 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6553 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6557 FIXME("level %u is incomplete\n", Level
);
6560 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6561 TRACE("got %u with %u\n", res
, GetLastError());
6562 HeapFree(GetProcessHeap(), 0, nameW
);
6563 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6564 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6565 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6566 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6567 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6568 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6569 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6570 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6571 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6572 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6573 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6574 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6575 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6577 TRACE("=> %u with %u\n", res
, GetLastError());
6581 /******************************************************************************
6582 * ConfigurePortA (WINSPOOL.@)
6584 * See ConfigurePortW.
6587 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6589 LPWSTR nameW
= NULL
;
6590 LPWSTR portW
= NULL
;
6594 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6596 /* convert servername to unicode */
6598 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6599 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6600 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6603 /* convert portname to unicode */
6605 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6606 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6607 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6610 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6611 HeapFree(GetProcessHeap(), 0, nameW
);
6612 HeapFree(GetProcessHeap(), 0, portW
);
6616 /******************************************************************************
6617 * ConfigurePortW (WINSPOOL.@)
6619 * Display the Configuration-Dialog for a specific Port
6622 * pName [I] Servername or NULL (local Computer)
6623 * hWnd [I] Handle to parent Window for the Dialog-Box
6624 * pPortName [I] Name of the Port, that should be configured
6631 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6637 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6639 if (pName
&& pName
[0]) {
6640 SetLastError(ERROR_INVALID_PARAMETER
);
6645 SetLastError(RPC_X_NULL_REF_POINTER
);
6649 /* an empty Portname is Invalid, but can popup a Dialog */
6650 if (!pPortName
[0]) {
6651 SetLastError(ERROR_NOT_SUPPORTED
);
6655 pm
= monitor_load_by_port(pPortName
);
6656 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
6657 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
6658 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
6659 TRACE("got %d with %u\n", res
, GetLastError());
6663 pui
= monitor_loadui(pm
);
6664 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
6665 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
6666 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
6667 TRACE("got %d with %u\n", res
, GetLastError());
6671 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
6672 pm
, debugstr_w(pm
? pm
->dllname
: NULL
), pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
6674 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6675 SetLastError(ERROR_NOT_SUPPORTED
);
6678 monitor_unload(pui
);
6682 TRACE("returning %d with %u\n", res
, GetLastError());
6686 /******************************************************************************
6687 * ConnectToPrinterDlg (WINSPOOL.@)
6689 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6691 FIXME("%p %x\n", hWnd
, Flags
);
6695 /******************************************************************************
6696 * DeletePrinterConnectionA (WINSPOOL.@)
6698 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6700 FIXME("%s\n", debugstr_a(pName
));
6704 /******************************************************************************
6705 * DeletePrinterConnectionW (WINSPOOL.@)
6707 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6709 FIXME("%s\n", debugstr_w(pName
));
6713 /******************************************************************************
6714 * DeletePrinterDriverExW (WINSPOOL.@)
6716 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6717 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6722 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6723 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6725 if(pName
&& pName
[0])
6727 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6728 SetLastError(ERROR_INVALID_PARAMETER
);
6734 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6735 SetLastError(ERROR_INVALID_PARAMETER
);
6739 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
6743 ERR("Can't open drivers key\n");
6747 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6750 RegCloseKey(hkey_drivers
);
6755 /******************************************************************************
6756 * DeletePrinterDriverExA (WINSPOOL.@)
6758 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6759 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6761 UNICODE_STRING NameW
, EnvW
, DriverW
;
6764 asciitounicode(&NameW
, pName
);
6765 asciitounicode(&EnvW
, pEnvironment
);
6766 asciitounicode(&DriverW
, pDriverName
);
6768 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6770 RtlFreeUnicodeString(&DriverW
);
6771 RtlFreeUnicodeString(&EnvW
);
6772 RtlFreeUnicodeString(&NameW
);
6777 /******************************************************************************
6778 * DeletePrinterDataExW (WINSPOOL.@)
6780 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6783 FIXME("%p %s %s\n", hPrinter
,
6784 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6785 return ERROR_INVALID_PARAMETER
;
6788 /******************************************************************************
6789 * DeletePrinterDataExA (WINSPOOL.@)
6791 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6794 FIXME("%p %s %s\n", hPrinter
,
6795 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6796 return ERROR_INVALID_PARAMETER
;
6799 /******************************************************************************
6800 * DeletePrintProcessorA (WINSPOOL.@)
6802 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6804 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6805 debugstr_a(pPrintProcessorName
));
6809 /******************************************************************************
6810 * DeletePrintProcessorW (WINSPOOL.@)
6812 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6814 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6815 debugstr_w(pPrintProcessorName
));
6819 /******************************************************************************
6820 * DeletePrintProvidorA (WINSPOOL.@)
6822 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6824 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6825 debugstr_a(pPrintProviderName
));
6829 /******************************************************************************
6830 * DeletePrintProvidorW (WINSPOOL.@)
6832 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6834 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6835 debugstr_w(pPrintProviderName
));
6839 /******************************************************************************
6840 * EnumFormsA (WINSPOOL.@)
6842 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6843 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6845 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6846 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6850 /******************************************************************************
6851 * EnumFormsW (WINSPOOL.@)
6853 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6854 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6856 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6857 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6861 /*****************************************************************************
6862 * EnumMonitorsA [WINSPOOL.@]
6864 * See EnumMonitorsW.
6867 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6868 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6871 LPBYTE bufferW
= NULL
;
6872 LPWSTR nameW
= NULL
;
6874 DWORD numentries
= 0;
6877 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6878 cbBuf
, pcbNeeded
, pcReturned
);
6880 /* convert servername to unicode */
6882 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6883 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6884 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6886 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6887 needed
= cbBuf
* sizeof(WCHAR
);
6888 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6889 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6891 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6892 if (pcbNeeded
) needed
= *pcbNeeded
;
6893 /* HeapReAlloc return NULL, when bufferW was NULL */
6894 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6895 HeapAlloc(GetProcessHeap(), 0, needed
);
6897 /* Try again with the large Buffer */
6898 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6900 numentries
= pcReturned
? *pcReturned
: 0;
6903 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6904 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6907 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6908 DWORD entrysize
= 0;
6911 LPMONITOR_INFO_2W mi2w
;
6912 LPMONITOR_INFO_2A mi2a
;
6914 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6915 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6917 /* First pass: calculate the size for all Entries */
6918 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6919 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6921 while (index
< numentries
) {
6923 needed
+= entrysize
; /* MONITOR_INFO_?A */
6924 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6926 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6927 NULL
, 0, NULL
, NULL
);
6929 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6930 NULL
, 0, NULL
, NULL
);
6931 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6932 NULL
, 0, NULL
, NULL
);
6934 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6935 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6936 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6939 /* check for errors and quit on failure */
6940 if (cbBuf
< needed
) {
6941 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6945 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6946 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6947 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6948 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6949 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6951 /* Second Pass: Fill the User Buffer (if we have one) */
6952 while ((index
< numentries
) && pMonitors
) {
6954 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6956 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6957 ptr
, cbBuf
, NULL
, NULL
);
6961 mi2a
->pEnvironment
= ptr
;
6962 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6963 ptr
, cbBuf
, NULL
, NULL
);
6967 mi2a
->pDLLName
= ptr
;
6968 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6969 ptr
, cbBuf
, NULL
, NULL
);
6973 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6974 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6975 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6979 if (pcbNeeded
) *pcbNeeded
= needed
;
6980 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6982 HeapFree(GetProcessHeap(), 0, nameW
);
6983 HeapFree(GetProcessHeap(), 0, bufferW
);
6985 TRACE("returning %d with %d (%d byte for %d entries)\n",
6986 (res
), GetLastError(), needed
, numentries
);
6992 /*****************************************************************************
6993 * EnumMonitorsW [WINSPOOL.@]
6995 * Enumerate available Port-Monitors
6998 * pName [I] Servername or NULL (local Computer)
6999 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7000 * pMonitors [O] PTR to Buffer that receives the Result
7001 * cbBuf [I] Size of Buffer at pMonitors
7002 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7003 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7007 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7010 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7011 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7014 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7015 cbBuf
, pcbNeeded
, pcReturned
);
7017 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7019 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
7020 SetLastError(RPC_X_NULL_REF_POINTER
);
7024 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
7027 /******************************************************************************
7028 * SpoolerInit (WINSPOOL.@)
7030 * Initialize the Spooler
7037 * The function fails on windows, when the spooler service is not running
7040 BOOL WINAPI
SpoolerInit(void)
7043 if ((backend
== NULL
) && !load_backend()) return FALSE
;
7047 /******************************************************************************
7048 * XcvDataW (WINSPOOL.@)
7050 * Execute commands in the Printmonitor DLL
7053 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7054 * pszDataName [i] Name of the command to execute
7055 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7056 * cbInputData [i] Size in Bytes of Buffer at pInputData
7057 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7058 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7059 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7060 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7067 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7068 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7070 * Minimal List of commands, that a Printmonitor DLL should support:
7072 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7073 *| "AddPort" : Add a Port
7074 *| "DeletePort": Delete a Port
7076 * Many Printmonitors support additional commands. Examples for localspl.dll:
7077 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7078 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7081 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7082 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7083 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7085 opened_printer_t
*printer
;
7087 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7088 pInputData
, cbInputData
, pOutputData
,
7089 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7091 printer
= get_opened_printer(hXcv
);
7092 if (!printer
|| (!printer
->hXcv
)) {
7093 SetLastError(ERROR_INVALID_HANDLE
);
7097 if (!pcbOutputNeeded
) {
7098 SetLastError(ERROR_INVALID_PARAMETER
);
7102 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7103 SetLastError(RPC_X_NULL_REF_POINTER
);
7107 *pcbOutputNeeded
= 0;
7109 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
7110 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
7115 /*****************************************************************************
7116 * EnumPrinterDataA [WINSPOOL.@]
7119 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7120 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7121 DWORD cbData
, LPDWORD pcbData
)
7123 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7124 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7125 return ERROR_NO_MORE_ITEMS
;
7128 /*****************************************************************************
7129 * EnumPrinterDataW [WINSPOOL.@]
7132 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7133 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7134 DWORD cbData
, LPDWORD pcbData
)
7136 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7137 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7138 return ERROR_NO_MORE_ITEMS
;
7141 /*****************************************************************************
7142 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7145 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7146 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7147 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7149 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7150 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7151 pcbNeeded
, pcReturned
);
7155 /*****************************************************************************
7156 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7159 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7160 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7161 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7163 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7164 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7165 pcbNeeded
, pcReturned
);
7169 /*****************************************************************************
7170 * EnumPrintProcessorsA [WINSPOOL.@]
7173 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7174 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7176 FIXME("Stub: %s %s %d %p %d %p %p\n", pName
, pEnvironment
, Level
,
7177 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
7181 /*****************************************************************************
7182 * EnumPrintProcessorsW [WINSPOOL.@]
7185 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7186 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7188 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7189 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
7190 cbBuf
, pcbNeeded
, pcbReturned
);
7194 /*****************************************************************************
7195 * ExtDeviceMode [WINSPOOL.@]
7198 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7199 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7202 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7203 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7204 debugstr_a(pProfile
), fMode
);
7208 /*****************************************************************************
7209 * FindClosePrinterChangeNotification [WINSPOOL.@]
7212 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7214 FIXME("Stub: %p\n", hChange
);
7218 /*****************************************************************************
7219 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7222 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7223 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7225 FIXME("Stub: %p %x %x %p\n",
7226 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7227 return INVALID_HANDLE_VALUE
;
7230 /*****************************************************************************
7231 * FindNextPrinterChangeNotification [WINSPOOL.@]
7234 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7235 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7237 FIXME("Stub: %p %p %p %p\n",
7238 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7242 /*****************************************************************************
7243 * FreePrinterNotifyInfo [WINSPOOL.@]
7246 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7248 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7252 /*****************************************************************************
7255 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7256 * ansi depending on the unicode parameter.
7258 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7268 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7271 memcpy(ptr
, str
, *size
);
7278 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7281 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7288 /*****************************************************************************
7291 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7292 LPDWORD pcbNeeded
, BOOL unicode
)
7294 DWORD size
, left
= cbBuf
;
7295 BOOL space
= (cbBuf
> 0);
7302 ji1
->JobId
= job
->job_id
;
7305 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7306 if(space
&& size
<= left
)
7308 ji1
->pDocument
= (LPWSTR
)ptr
;
7319 /*****************************************************************************
7322 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7323 LPDWORD pcbNeeded
, BOOL unicode
)
7325 DWORD size
, left
= cbBuf
;
7326 BOOL space
= (cbBuf
> 0);
7333 ji2
->JobId
= job
->job_id
;
7336 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7337 if(space
&& size
<= left
)
7339 ji2
->pDocument
= (LPWSTR
)ptr
;
7350 /*****************************************************************************
7353 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7354 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7357 DWORD needed
= 0, size
;
7361 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7363 EnterCriticalSection(&printer_handles_cs
);
7364 job
= get_job(hPrinter
, JobId
);
7371 size
= sizeof(JOB_INFO_1W
);
7376 memset(pJob
, 0, size
);
7380 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7385 size
= sizeof(JOB_INFO_2W
);
7390 memset(pJob
, 0, size
);
7394 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7399 size
= sizeof(JOB_INFO_3
);
7403 memset(pJob
, 0, size
);
7412 SetLastError(ERROR_INVALID_LEVEL
);
7416 *pcbNeeded
= needed
;
7418 LeaveCriticalSection(&printer_handles_cs
);
7422 /*****************************************************************************
7423 * GetJobA [WINSPOOL.@]
7426 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7427 DWORD cbBuf
, LPDWORD pcbNeeded
)
7429 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7432 /*****************************************************************************
7433 * GetJobW [WINSPOOL.@]
7436 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7437 DWORD cbBuf
, LPDWORD pcbNeeded
)
7439 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7442 /*****************************************************************************
7445 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7447 char *unixname
, *queue
, *cmd
;
7448 char fmt
[] = "lpr -P%s %s";
7452 if(!(unixname
= wine_get_unix_file_name(filename
)))
7455 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7456 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7457 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7459 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7460 sprintf(cmd
, fmt
, queue
, unixname
);
7462 TRACE("printing with: %s\n", cmd
);
7465 HeapFree(GetProcessHeap(), 0, cmd
);
7466 HeapFree(GetProcessHeap(), 0, queue
);
7467 HeapFree(GetProcessHeap(), 0, unixname
);
7471 /*****************************************************************************
7474 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7476 #ifdef SONAME_LIBCUPS
7479 char *unixname
, *queue
, *unix_doc_title
;
7483 if(!(unixname
= wine_get_unix_file_name(filename
)))
7486 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7487 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7488 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7490 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7491 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
7492 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
7494 TRACE("printing via cups\n");
7495 ret
= pcupsPrintFile(queue
, unixname
, unix_doc_title
, 0, NULL
);
7496 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
7497 HeapFree(GetProcessHeap(), 0, queue
);
7498 HeapFree(GetProcessHeap(), 0, unixname
);
7504 return schedule_lpr(printer_name
, filename
);
7508 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7515 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7519 if(HIWORD(wparam
) == BN_CLICKED
)
7521 if(LOWORD(wparam
) == IDOK
)
7524 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7527 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7528 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7530 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7532 WCHAR caption
[200], message
[200];
7535 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7536 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7537 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7538 if(mb_ret
== IDCANCEL
)
7540 HeapFree(GetProcessHeap(), 0, filename
);
7544 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7545 if(hf
== INVALID_HANDLE_VALUE
)
7547 WCHAR caption
[200], message
[200];
7549 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7550 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7551 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7552 HeapFree(GetProcessHeap(), 0, filename
);
7556 DeleteFileW(filename
);
7557 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7559 EndDialog(hwnd
, IDOK
);
7562 if(LOWORD(wparam
) == IDCANCEL
)
7564 EndDialog(hwnd
, IDCANCEL
);
7573 /*****************************************************************************
7576 static BOOL
get_filename(LPWSTR
*filename
)
7578 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7579 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7582 /*****************************************************************************
7585 static BOOL
schedule_file(LPCWSTR filename
)
7587 LPWSTR output
= NULL
;
7589 if(get_filename(&output
))
7592 TRACE("copy to %s\n", debugstr_w(output
));
7593 r
= CopyFileW(filename
, output
, FALSE
);
7594 HeapFree(GetProcessHeap(), 0, output
);
7600 /*****************************************************************************
7603 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7606 char *unixname
, *cmdA
;
7608 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7612 if(!(unixname
= wine_get_unix_file_name(filename
)))
7615 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7616 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7617 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7619 TRACE("printing with: %s\n", cmdA
);
7621 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7626 ERR("pipe() failed!\n");
7636 /* reset signals that we previously set to SIG_IGN */
7637 signal(SIGPIPE
, SIG_DFL
);
7638 signal(SIGCHLD
, SIG_DFL
);
7640 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
7644 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7645 write(fds
[1], buf
, no_read
);
7650 if(file_fd
!= -1) close(file_fd
);
7651 if(fds
[0] != -1) close(fds
[0]);
7652 if(fds
[1] != -1) close(fds
[1]);
7654 HeapFree(GetProcessHeap(), 0, cmdA
);
7655 HeapFree(GetProcessHeap(), 0, unixname
);
7662 /*****************************************************************************
7665 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7667 int in_fd
, out_fd
, no_read
;
7670 char *unixname
, *outputA
;
7673 if(!(unixname
= wine_get_unix_file_name(filename
)))
7676 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7677 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7678 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7680 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7681 in_fd
= open(unixname
, O_RDONLY
);
7682 if(out_fd
== -1 || in_fd
== -1)
7685 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7686 write(out_fd
, buf
, no_read
);
7690 if(in_fd
!= -1) close(in_fd
);
7691 if(out_fd
!= -1) close(out_fd
);
7692 HeapFree(GetProcessHeap(), 0, outputA
);
7693 HeapFree(GetProcessHeap(), 0, unixname
);
7697 /*****************************************************************************
7698 * ScheduleJob [WINSPOOL.@]
7701 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7703 opened_printer_t
*printer
;
7705 struct list
*cursor
, *cursor2
;
7707 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7708 EnterCriticalSection(&printer_handles_cs
);
7709 printer
= get_opened_printer(hPrinter
);
7713 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7715 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7718 if(job
->job_id
!= dwJobID
) continue;
7720 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7721 if(hf
!= INVALID_HANDLE_VALUE
)
7723 PRINTER_INFO_5W
*pi5
;
7727 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7728 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7730 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7731 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7732 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7733 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7734 debugstr_w(pi5
->pPortName
));
7738 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7739 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7741 DWORD type
, count
= sizeof(output
);
7742 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
7745 if(output
[0] == '|')
7747 ret
= schedule_pipe(output
+ 1, job
->filename
);
7751 ret
= schedule_unixfile(output
, job
->filename
);
7753 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
7755 ret
= schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
7757 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
7759 ret
= schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7761 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
7763 ret
= schedule_file(job
->filename
);
7767 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
7769 HeapFree(GetProcessHeap(), 0, pi5
);
7771 DeleteFileW(job
->filename
);
7773 list_remove(cursor
);
7774 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7775 HeapFree(GetProcessHeap(), 0, job
->filename
);
7776 HeapFree(GetProcessHeap(), 0, job
);
7780 LeaveCriticalSection(&printer_handles_cs
);
7784 /*****************************************************************************
7785 * StartDocDlgA [WINSPOOL.@]
7787 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7789 UNICODE_STRING usBuffer
;
7792 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7795 docW
.cbSize
= sizeof(docW
);
7796 if (doc
->lpszDocName
)
7798 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7799 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7801 if (doc
->lpszOutput
)
7803 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7804 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7806 if (doc
->lpszDatatype
)
7808 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7809 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7811 docW
.fwType
= doc
->fwType
;
7813 retW
= StartDocDlgW(hPrinter
, &docW
);
7817 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7818 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7819 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7820 HeapFree(GetProcessHeap(), 0, retW
);
7823 HeapFree(GetProcessHeap(), 0, datatypeW
);
7824 HeapFree(GetProcessHeap(), 0, outputW
);
7825 HeapFree(GetProcessHeap(), 0, docnameW
);
7830 /*****************************************************************************
7831 * StartDocDlgW [WINSPOOL.@]
7833 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7834 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7835 * port is "FILE:". Also returns the full path if passed a relative path.
7837 * The caller should free the returned string from the process heap.
7839 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7844 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7846 PRINTER_INFO_5W
*pi5
;
7847 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7848 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7850 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7851 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7852 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7854 HeapFree(GetProcessHeap(), 0, pi5
);
7857 HeapFree(GetProcessHeap(), 0, pi5
);
7860 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7864 if (get_filename(&name
))
7866 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7868 HeapFree(GetProcessHeap(), 0, name
);
7871 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7872 GetFullPathNameW(name
, len
, ret
, NULL
);
7873 HeapFree(GetProcessHeap(), 0, name
);
7878 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7881 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7882 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7884 attr
= GetFileAttributesW(ret
);
7885 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7887 HeapFree(GetProcessHeap(), 0, ret
);