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, 2006, 2007 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
60 #include "ddk/winsplp.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
65 /* ############################### */
67 static CRITICAL_SECTION monitor_handles_cs
;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug
=
70 0, 0, &monitor_handles_cs
,
71 { &monitor_handles_cs_debug
.ProcessLocksList
, &monitor_handles_cs_debug
.ProcessLocksList
},
72 0, 0, { (DWORD_PTR
)(__FILE__
": monitor_handles_cs") }
74 static CRITICAL_SECTION monitor_handles_cs
= { &monitor_handles_cs_debug
, -1, 0, 0, 0, 0 };
77 static CRITICAL_SECTION printer_handles_cs
;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
80 0, 0, &printer_handles_cs
,
81 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
82 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
84 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
86 /* ############################### */
122 WCHAR
*document_title
;
130 LPCWSTR versionregpath
;
131 LPCWSTR versionsubdir
;
134 /* ############################### */
136 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
137 static monitor_t
* pm_localport
;
139 static opened_printer_t
**printer_handles
;
140 static int nb_printer_handles
;
141 static LONG next_job_id
= 1;
143 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
144 WORD fwCapability
, LPSTR lpszOutput
,
146 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
147 LPSTR lpszDevice
, LPSTR lpszPort
,
148 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
151 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
152 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
153 'c','o','n','t','r','o','l','\\',
154 'P','r','i','n','t','\\',
155 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
156 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
158 static const WCHAR MonitorsW
[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'C','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'M','o','n','i','t','o','r','s','\\',0};
164 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
165 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
166 'C','o','n','t','r','o','l','\\',
167 'P','r','i','n','t','\\',
168 'P','r','i','n','t','e','r','s',0};
170 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
172 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s',' ','N','T','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'W','i','n','d','o','w','s',0};
178 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'D','e','v','i','c','e','s',0};
184 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
185 'M','i','c','r','o','s','o','f','t','\\',
186 'W','i','n','d','o','w','s',' ','N','T','\\',
187 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
188 'P','o','r','t','s',0};
190 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
191 static const WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
192 static const WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
193 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
194 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
195 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
196 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
198 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
199 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
201 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
202 'i','o','n',' ','F','i','l','e',0};
203 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
204 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
205 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v',
207 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F',
209 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
210 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
211 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
212 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
213 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
214 static const WCHAR MonitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
215 static const WCHAR NameW
[] = {'N','a','m','e',0};
216 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
217 static const WCHAR PortW
[] = {'P','o','r','t',0};
218 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
219 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e',
221 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i',
223 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i',
224 'v','e','r','D','a','t','a',0};
225 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F',
227 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
228 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
229 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
230 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
231 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
232 static const WCHAR emptyStringW
[] = {0};
233 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
234 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
236 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
238 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
239 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
240 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
242 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
243 'D','o','c','u','m','e','n','t',0};
246 /******************************************************************
247 * validate the user-supplied printing-environment [internal]
250 * env [I] PTR to Environment-String or NULL
254 * Success: PTR to printenv_t
257 * An empty string is handled the same way as NULL.
258 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
262 static const printenv_t
* validate_envW(LPCWSTR env
)
264 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
,
265 3, Version3_RegPathW
, Version3_SubdirW
};
266 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
,
267 0, emptyStringW
, emptyStringW
};
268 static const printenv_t
* const all_printenv
[]={&env_x86
, &env_win40
};
270 const printenv_t
*result
= NULL
;
273 TRACE("testing %s\n", debugstr_w(env
));
276 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
278 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
280 result
= all_printenv
[i
];
285 if (result
== NULL
) {
286 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
287 SetLastError(ERROR_INVALID_ENVIRONMENT
);
289 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
293 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
295 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
301 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
302 if passed a NULL string. This returns NULLs to the result.
304 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
308 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
309 return usBufferPtr
->Buffer
;
311 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
315 static LPWSTR
strdupW(LPCWSTR p
)
321 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
322 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
327 static LPSTR
strdupWtoA( LPCWSTR str
)
332 if (!str
) return NULL
;
333 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
334 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
335 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
339 /* Returns the number of bytes in an ansi \0\0 terminated string (multi_sz).
340 The result includes all \0s (specifically the last two). */
341 static int multi_sz_lenA(const char *str
)
343 const char *ptr
= str
;
347 ptr
+= lstrlenA(ptr
) + 1;
350 return ptr
- str
+ 1;
354 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
357 /* If forcing, or no profile string entry for device yet, set the entry
359 * The always change entry if not WINEPS yet is discussable.
362 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
364 !strstr(qbuf
,"WINEPS.DRV")
366 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
369 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
370 WriteProfileStringA("windows","device",buf
);
371 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
372 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
375 HeapFree(GetProcessHeap(),0,buf
);
379 static BOOL
add_printer_driver(const char *name
)
383 static char driver_path
[] = "wineps16",
384 data_file
[] = "<datafile?>",
385 config_file
[] = "wineps16",
386 help_file
[] = "<helpfile?>",
387 dep_file
[] = "<dependent files?>\0",
388 monitor_name
[] = "<monitor name?>",
389 default_data_type
[] = "RAW";
391 di3a
.cVersion
= (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
392 di3a
.pName
= (char *)name
;
393 di3a
.pEnvironment
= NULL
; /* NULL means auto */
394 di3a
.pDriverPath
= driver_path
;
395 di3a
.pDataFile
= data_file
;
396 di3a
.pConfigFile
= config_file
;
397 di3a
.pHelpFile
= help_file
;
398 di3a
.pDependentFiles
= dep_file
;
399 di3a
.pMonitorName
= monitor_name
;
400 di3a
.pDefaultDataType
= default_data_type
;
402 if (!AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
))
404 ERR("Failed adding driver (%d)\n", GetLastError());
410 #ifdef SONAME_LIBCUPS
411 static typeof(cupsGetDests
) *pcupsGetDests
;
412 static typeof(cupsGetPPD
) *pcupsGetPPD
;
413 static typeof(cupsPrintFile
) *pcupsPrintFile
;
414 static void *cupshandle
;
416 static BOOL
CUPS_LoadPrinters(void)
419 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
421 PRINTER_INFO_2A pinfo2a
;
423 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
425 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, NULL
, 0);
428 TRACE("loaded %s\n", SONAME_LIBCUPS
);
431 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
432 if (!p##x) return FALSE;
435 DYNCUPS(cupsGetDests
);
436 DYNCUPS(cupsPrintFile
);
439 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
441 ERR("Can't create Printers key\n");
445 nrofdests
= pcupsGetDests(&dests
);
446 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
447 for (i
=0;i
<nrofdests
;i
++) {
448 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests
[i
].name
)+1);
449 sprintf(port
,"LPR:%s",dests
[i
].name
);
450 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
451 sprintf(devline
,"WINEPS.DRV,%s",port
);
452 WriteProfileStringA("devices",dests
[i
].name
,devline
);
453 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
454 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
457 HeapFree(GetProcessHeap(),0,devline
);
459 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
460 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
461 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
463 TRACE("Printer already exists\n");
464 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
465 RegCloseKey(hkeyPrinter
);
467 static CHAR data_type
[] = "RAW",
468 print_proc
[] = "WinPrint",
469 comment
[] = "WINEPS Printer using CUPS",
470 location
[] = "<physical location of printer>",
471 params
[] = "<parameters?>",
472 share_name
[] = "<share name?>",
473 sep_file
[] = "<sep file?>";
475 add_printer_driver(dests
[i
].name
);
477 memset(&pinfo2a
,0,sizeof(pinfo2a
));
478 pinfo2a
.pPrinterName
= dests
[i
].name
;
479 pinfo2a
.pDatatype
= data_type
;
480 pinfo2a
.pPrintProcessor
= print_proc
;
481 pinfo2a
.pDriverName
= dests
[i
].name
;
482 pinfo2a
.pComment
= comment
;
483 pinfo2a
.pLocation
= location
;
484 pinfo2a
.pPortName
= port
;
485 pinfo2a
.pParameters
= params
;
486 pinfo2a
.pShareName
= share_name
;
487 pinfo2a
.pSepFile
= sep_file
;
489 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
490 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
491 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
494 HeapFree(GetProcessHeap(),0,port
);
497 if (dests
[i
].is_default
) {
498 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
502 if (hadprinter
& !haddefault
)
503 WINSPOOL_SetDefaultPrinter(dests
[0].name
, dests
[0].name
, TRUE
);
504 RegCloseKey(hkeyPrinters
);
510 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
511 PRINTER_INFO_2A pinfo2a
;
512 char *e
,*s
,*name
,*prettyname
,*devname
;
513 BOOL ret
= FALSE
, set_default
= FALSE
;
514 char *port
,*devline
,*env_default
;
515 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
517 while (isspace(*pent
)) pent
++;
518 s
= strchr(pent
,':');
520 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
528 TRACE("name=%s entry=%s\n",name
, pent
);
530 if(ispunct(*name
)) { /* a tc entry, not a real printer */
531 TRACE("skipping tc entry\n");
535 if(strstr(pent
,":server")) { /* server only version so skip */
536 TRACE("skipping server entry\n");
540 /* Determine whether this is a postscript printer. */
543 env_default
= getenv("PRINTER");
545 /* Get longest name, usually the one at the right for later display. */
546 while((s
=strchr(prettyname
,'|'))) {
549 while(isspace(*--e
)) *e
= '\0';
550 TRACE("\t%s\n", debugstr_a(prettyname
));
551 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
552 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
555 e
= prettyname
+ strlen(prettyname
);
556 while(isspace(*--e
)) *e
= '\0';
557 TRACE("\t%s\n", debugstr_a(prettyname
));
558 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
560 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
561 * if it is too long, we use it as comment below. */
562 devname
= prettyname
;
563 if (strlen(devname
)>=CCHDEVICENAME
-1)
565 if (strlen(devname
)>=CCHDEVICENAME
-1) {
570 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
571 sprintf(port
,"LPR:%s",name
);
573 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
574 sprintf(devline
,"WINEPS.DRV,%s",port
);
575 WriteProfileStringA("devices",devname
,devline
);
576 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
577 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
580 HeapFree(GetProcessHeap(),0,devline
);
582 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
584 ERR("Can't create Printers key\n");
588 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
589 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
591 TRACE("Printer already exists\n");
592 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
593 RegCloseKey(hkeyPrinter
);
595 static CHAR data_type
[] = "RAW",
596 print_proc
[] = "WinPrint",
597 comment
[] = "WINEPS Printer using LPR",
598 params
[] = "<parameters?>",
599 share_name
[] = "<share name?>",
600 sep_file
[] = "<sep file?>";
602 add_printer_driver(devname
);
604 memset(&pinfo2a
,0,sizeof(pinfo2a
));
605 pinfo2a
.pPrinterName
= devname
;
606 pinfo2a
.pDatatype
= data_type
;
607 pinfo2a
.pPrintProcessor
= print_proc
;
608 pinfo2a
.pDriverName
= devname
;
609 pinfo2a
.pComment
= comment
;
610 pinfo2a
.pLocation
= prettyname
;
611 pinfo2a
.pPortName
= port
;
612 pinfo2a
.pParameters
= params
;
613 pinfo2a
.pShareName
= share_name
;
614 pinfo2a
.pSepFile
= sep_file
;
616 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
617 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
618 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
621 RegCloseKey(hkeyPrinters
);
623 if (isfirst
|| set_default
)
624 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
626 HeapFree(GetProcessHeap(), 0, port
);
628 HeapFree(GetProcessHeap(), 0, name
);
633 PRINTCAP_LoadPrinters(void) {
634 BOOL hadprinter
= FALSE
;
638 BOOL had_bash
= FALSE
;
640 f
= fopen("/etc/printcap","r");
644 while(fgets(buf
,sizeof(buf
),f
)) {
647 end
=strchr(buf
,'\n');
651 while(isspace(*start
)) start
++;
652 if(*start
== '#' || *start
== '\0')
655 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
656 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
657 HeapFree(GetProcessHeap(),0,pent
);
661 if (end
&& *--end
== '\\') {
668 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
671 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
677 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
678 HeapFree(GetProcessHeap(),0,pent
);
684 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
687 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
688 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
690 return ERROR_FILE_NOT_FOUND
;
693 /*****************************************************************************
694 * enumerate the local monitors (INTERNAL)
696 * returns the needed size (in bytes) for pMonitors
697 * and *lpreturned is set to number of entries returned in pMonitors
700 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
705 LPMONITOR_INFO_2W mi
;
706 WCHAR buffer
[MAX_PATH
];
707 WCHAR dllname
[MAX_PATH
];
715 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
717 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
718 len
= entrysize
* numentries
;
719 ptr
= (LPWSTR
) &pMonitors
[len
];
722 len
= sizeof(buffer
);
725 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
726 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
727 /* Scan all Monitor-Registry-Keys */
728 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
729 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
730 dllsize
= sizeof(dllname
);
733 /* The Monitor must have a Driver-DLL */
734 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
735 if (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
736 /* We found a valid DLL for this Monitor. */
737 TRACE("using Driver: %s\n", debugstr_w(dllname
));
742 /* Windows returns only Port-Monitors here, but to simplify our code,
743 we do no filtering for Language-Monitors */
747 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
749 /* we install and return only monitors for "Windows NT x86" */
750 needed
+= (lstrlenW(envname_x86W
) +1) * sizeof(WCHAR
);
754 /* required size is calculated. Now fill the user-buffer */
755 if (pMonitors
&& (cbBuf
>= needed
)){
756 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
757 pMonitors
+= entrysize
;
759 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
761 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
762 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
764 mi
->pEnvironment
= ptr
;
765 lstrcpyW(ptr
, envname_x86W
); /* fixed to "Windows NT x86" */
766 ptr
+= (lstrlenW(envname_x86W
)+1);
769 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
770 ptr
+= (dllsize
/ sizeof(WCHAR
));
775 len
= sizeof(buffer
);
780 *lpreturned
= numentries
;
781 TRACE("need %d byte for %d entries\n", needed
, numentries
);
785 /******************************************************************
786 * monitor_unload [internal]
788 * release a printmonitor and unload it from memory, when needed
791 static void monitor_unload(monitor_t
* pm
)
793 if (pm
== NULL
) return;
794 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
796 EnterCriticalSection(&monitor_handles_cs
);
798 if (pm
->refcount
) pm
->refcount
--;
800 if (pm
->refcount
== 0) {
801 list_remove(&pm
->entry
);
802 FreeLibrary(pm
->hdll
);
803 HeapFree(GetProcessHeap(), 0, pm
->name
);
804 HeapFree(GetProcessHeap(), 0, pm
->dllname
);
805 HeapFree(GetProcessHeap(), 0, pm
);
807 LeaveCriticalSection(&monitor_handles_cs
);
810 /******************************************************************
811 * monitor_unloadall [internal]
813 * release all printmonitors and unload them from memory, when needed
816 static void monitor_unloadall(void)
821 EnterCriticalSection(&monitor_handles_cs
);
822 /* iterate through the list, with safety against removal */
823 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
827 LeaveCriticalSection(&monitor_handles_cs
);
830 /******************************************************************
831 * monitor_load [internal]
833 * load a printmonitor, get the dllname from the registry, when needed
834 * initialize the monitor and dump found function-pointers
836 * On failure, SetLastError() is called and NULL is returned
839 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
841 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
842 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
843 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
844 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
845 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
847 monitor_t
* pm
= NULL
;
849 LPWSTR regroot
= NULL
;
850 LPWSTR driver
= dllname
;
852 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
853 /* Is the Monitor already loaded? */
854 EnterCriticalSection(&monitor_handles_cs
);
857 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
859 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
867 pm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(monitor_t
));
868 if (pm
== NULL
) goto cleanup
;
869 list_add_tail(&monitor_handles
, &pm
->entry
);
873 if (pm
->name
== NULL
) {
874 /* Load the monitor */
875 LPMONITOREX pmonitorEx
;
879 len
= lstrlenW(MonitorsW
) + lstrlenW(name
) + 2;
880 regroot
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
884 lstrcpyW(regroot
, MonitorsW
);
885 lstrcatW(regroot
, name
);
886 /* Get the Driver from the Registry */
887 if (driver
== NULL
) {
890 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
891 if (RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, NULL
,
892 &namesize
) == ERROR_SUCCESS
) {
893 driver
= HeapAlloc(GetProcessHeap(), 0, namesize
);
894 RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
901 pm
->name
= strdupW(name
);
902 pm
->dllname
= strdupW(driver
);
904 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
906 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
911 pm
->hdll
= LoadLibraryW(driver
);
912 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
914 if (pm
->hdll
== NULL
) {
916 SetLastError(ERROR_MOD_NOT_FOUND
);
921 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
922 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
923 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
924 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
925 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
928 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
929 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
930 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
931 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
932 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
934 if (pInitializePrintMonitorUI
!= NULL
) {
935 pm
->monitorUI
= pInitializePrintMonitorUI();
936 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
938 TRACE( "0x%08x: dwMonitorSize (%d)\n",
939 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
944 if (pInitializePrintMonitor
&& regroot
) {
945 pmonitorEx
= pInitializePrintMonitor(regroot
);
946 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
947 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
950 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
951 pm
->monitor
= &(pmonitorEx
->Monitor
);
956 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
960 if (!pm
->monitor
&& regroot
) {
961 if (pInitializePrintMonitor2
!= NULL
) {
962 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
964 if (pInitializeMonitorEx
!= NULL
) {
965 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
967 if (pInitializeMonitor
!= NULL
) {
968 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
971 if (!pm
->monitor
&& !pm
->monitorUI
) {
973 SetLastError(ERROR_PROC_NOT_FOUND
);
978 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, LocalPortW
) == 0)) {
982 LeaveCriticalSection(&monitor_handles_cs
);
983 if (driver
!= dllname
) HeapFree(GetProcessHeap(), 0, driver
);
984 HeapFree(GetProcessHeap(), 0, regroot
);
985 TRACE("=> %p\n", pm
);
989 /******************************************************************
990 * monitor_loadall [internal]
992 * Load all registered monitors
995 static DWORD
monitor_loadall(void)
998 DWORD registered
= 0;
1001 WCHAR buffer
[MAX_PATH
];
1004 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
1005 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
1006 NULL
, NULL
, NULL
, NULL
, NULL
);
1008 TRACE("%d monitors registered\n", registered
);
1010 EnterCriticalSection(&monitor_handles_cs
);
1011 while (id
< registered
) {
1013 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
1014 pm
= monitor_load(buffer
, NULL
);
1018 LeaveCriticalSection(&monitor_handles_cs
);
1019 RegCloseKey(hmonitors
);
1021 TRACE("%d monitors loaded\n", loaded
);
1025 /******************************************************************
1026 * monitor_loadui [internal]
1028 * load the userinterface-dll for a given portmonitor
1030 * On failure, NULL is returned
1033 static monitor_t
* monitor_loadui(monitor_t
* pm
)
1035 monitor_t
* pui
= NULL
;
1036 LPWSTR buffer
[MAX_PATH
];
1041 if (pm
== NULL
) return NULL
;
1042 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
1044 /* Try the Portmonitor first; works for many monitors */
1045 if (pm
->monitorUI
) {
1046 EnterCriticalSection(&monitor_handles_cs
);
1048 LeaveCriticalSection(&monitor_handles_cs
);
1052 /* query the userinterface-dllname from the Portmonitor */
1053 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
1054 /* building (",XcvMonitor %s",pm->name) not needed yet */
1055 res
= pm
->monitor
->pfnXcvOpenPort(emptyStringW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
1056 TRACE("got %u with %p\n", res
, hXcv
);
1058 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, MonitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
1059 TRACE("got %u with %s\n", res
, debugstr_w((LPWSTR
) buffer
));
1060 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, (LPWSTR
) buffer
);
1061 pm
->monitor
->pfnXcvClosePort(hXcv
);
1068 /******************************************************************
1069 * monitor_load_by_port [internal]
1071 * load a printmonitor for a given port
1073 * On failure, NULL is returned
1076 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
1081 monitor_t
* pm
= NULL
;
1082 DWORD registered
= 0;
1086 TRACE("(%s)\n", debugstr_w(portname
));
1088 /* Try the Local Monitor first */
1089 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
) == ERROR_SUCCESS
) {
1090 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
1091 /* found the portname */
1093 return monitor_load(LocalPortW
, NULL
);
1098 len
= MAX_PATH
+ lstrlenW(bs_Ports_bsW
) + lstrlenW(portname
) + 1;
1099 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1100 if (buffer
== NULL
) return NULL
;
1102 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
1103 EnterCriticalSection(&monitor_handles_cs
);
1104 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1106 while ((pm
== NULL
) && (id
< registered
)) {
1108 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
1109 TRACE("testing %s\n", debugstr_w(buffer
));
1110 len
= lstrlenW(buffer
);
1111 lstrcatW(buffer
, bs_Ports_bsW
);
1112 lstrcatW(buffer
, portname
);
1113 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
1115 buffer
[len
] = '\0'; /* use only the Monitor-Name */
1116 pm
= monitor_load(buffer
, NULL
);
1120 LeaveCriticalSection(&monitor_handles_cs
);
1123 HeapFree(GetProcessHeap(), 0, buffer
);
1127 /******************************************************************
1128 * enumerate the local Ports from all loaded monitors (internal)
1130 * returns the needed size (in bytes) for pPorts
1131 * and *lpreturned is set to number of entries returned in pPorts
1134 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
1138 LPPORT_INFO_2W cache
;
1140 LPBYTE pi_buffer
= NULL
;
1141 DWORD pi_allocated
= 0;
1152 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
1153 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
1155 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1156 needed
= entrysize
* numentries
;
1157 ptr
= (LPWSTR
) &pPorts
[needed
];
1162 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
1164 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
1167 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1168 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
1169 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1170 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1171 pi_buffer
= HeapAlloc(GetProcessHeap(), 0, pi_needed
);
1172 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
1173 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1175 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1176 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
1178 numentries
+= pi_returned
;
1179 needed
+= pi_needed
;
1181 /* fill the output-buffer (pPorts), if we have one */
1182 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
1184 while (pi_returned
> pi_index
) {
1185 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
1186 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
1187 out
->pPortName
= ptr
;
1188 lstrcpyW(ptr
, cache
->pPortName
);
1189 ptr
+= (lstrlenW(ptr
)+1);
1191 out
->pMonitorName
= ptr
;
1192 lstrcpyW(ptr
, cache
->pMonitorName
);
1193 ptr
+= (lstrlenW(ptr
)+1);
1195 out
->pDescription
= ptr
;
1196 lstrcpyW(ptr
, cache
->pDescription
);
1197 ptr
+= (lstrlenW(ptr
)+1);
1198 out
->fPortType
= cache
->fPortType
;
1199 out
->Reserved
= cache
->Reserved
;
1207 /* the temporary portinfo-buffer is no longer needed */
1208 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1210 *lpreturned
= numentries
;
1211 TRACE("need %d byte for %d entries\n", needed
, numentries
);
1215 /******************************************************************
1216 * get_servername_from_name (internal)
1218 * for an external server, a copy of the serverpart from the full name is returned
1221 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1225 WCHAR buffer
[MAX_PATH
];
1228 if (name
== NULL
) return NULL
;
1229 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1231 server
= strdupW(&name
[2]); /* skip over both backslash */
1232 if (server
== NULL
) return NULL
;
1234 /* strip '\' and the printername */
1235 ptr
= strchrW(server
, '\\');
1236 if (ptr
) ptr
[0] = '\0';
1238 TRACE("found %s\n", debugstr_w(server
));
1240 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1241 if (GetComputerNameW(buffer
, &len
)) {
1242 if (lstrcmpW(buffer
, server
) == 0) {
1243 /* The requested Servername is our computername */
1244 HeapFree(GetProcessHeap(), 0, server
);
1251 /******************************************************************
1252 * get_basename_from_name (internal)
1254 * skip over the serverpart from the full name
1257 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1259 if (name
== NULL
) return NULL
;
1260 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1261 /* skip over the servername and search for the following '\' */
1262 name
= strchrW(&name
[2], '\\');
1263 if ((name
) && (name
[1])) {
1264 /* found a separator ('\') followed by a name:
1265 skip over the separator and return the rest */
1270 /* no basename present (we found only a servername) */
1277 /******************************************************************
1278 * get_opened_printer_entry
1279 * Get the first place empty in the opened printer table
1282 * - pDefault is ignored
1284 static HANDLE
get_opened_printer_entry(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1286 UINT_PTR handle
= nb_printer_handles
, i
;
1287 jobqueue_t
*queue
= NULL
;
1288 opened_printer_t
*printer
= NULL
;
1290 LPCWSTR printername
;
1295 servername
= get_servername_from_name(name
);
1297 FIXME("server %s not supported\n", debugstr_w(servername
));
1298 HeapFree(GetProcessHeap(), 0, servername
);
1299 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1303 printername
= get_basename_from_name(name
);
1304 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1306 /* an empty printername is invalid */
1307 if (printername
&& (!printername
[0])) {
1308 SetLastError(ERROR_INVALID_PARAMETER
);
1312 EnterCriticalSection(&printer_handles_cs
);
1314 for (i
= 0; i
< nb_printer_handles
; i
++)
1316 if (!printer_handles
[i
])
1318 if(handle
== nb_printer_handles
)
1323 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1324 queue
= printer_handles
[i
]->queue
;
1328 if (handle
>= nb_printer_handles
)
1330 opened_printer_t
**new_array
;
1331 if (printer_handles
)
1332 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1333 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1335 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1336 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1343 printer_handles
= new_array
;
1344 nb_printer_handles
+= 16;
1347 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1354 /* clone the base name. This is NULL for the printserver */
1355 printer
->printername
= strdupW(printername
);
1357 /* clone the full name */
1358 printer
->name
= strdupW(name
);
1359 if (name
&& (!printer
->name
)) {
1365 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1366 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1367 /* OpenPrinter(",XcvMonitor " detected */
1368 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1369 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1370 if (printer
->pm
== NULL
) {
1371 SetLastError(ERROR_UNKNOWN_PORT
);
1378 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1379 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1380 /* OpenPrinter(",XcvPort " detected */
1381 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1382 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1383 if (printer
->pm
== NULL
) {
1384 SetLastError(ERROR_UNKNOWN_PORT
);
1392 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1393 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1394 pDefault
? pDefault
->DesiredAccess
: 0,
1397 if (printer
->hXcv
== NULL
) {
1398 SetLastError(ERROR_INVALID_PARAMETER
);
1405 /* Does the Printer exist? */
1406 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1407 ERR("Can't create Printers key\n");
1411 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1412 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1413 RegCloseKey(hkeyPrinters
);
1414 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1418 RegCloseKey(hkeyPrinter
);
1419 RegCloseKey(hkeyPrinters
);
1424 TRACE("using the local printserver\n");
1428 printer
->queue
= queue
;
1431 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1432 if (!printer
->queue
) {
1436 list_init(&printer
->queue
->jobs
);
1437 printer
->queue
->ref
= 0;
1439 InterlockedIncrement(&printer
->queue
->ref
);
1441 printer_handles
[handle
] = printer
;
1444 LeaveCriticalSection(&printer_handles_cs
);
1445 if (!handle
&& printer
) {
1446 /* Something failed: Free all resources */
1447 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1448 monitor_unload(printer
->pm
);
1449 HeapFree(GetProcessHeap(), 0, printer
->printername
);
1450 HeapFree(GetProcessHeap(), 0, printer
->name
);
1451 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1452 HeapFree(GetProcessHeap(), 0, printer
);
1455 return (HANDLE
)handle
;
1458 /******************************************************************
1459 * get_opened_printer
1460 * Get the pointer to the opened printer referred by the handle
1462 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
1464 UINT_PTR idx
= (UINT_PTR
)hprn
;
1465 opened_printer_t
*ret
= NULL
;
1467 EnterCriticalSection(&printer_handles_cs
);
1469 if ((idx
<= 0) || (idx
> nb_printer_handles
))
1472 ret
= printer_handles
[idx
- 1];
1474 LeaveCriticalSection(&printer_handles_cs
);
1478 /******************************************************************
1479 * get_opened_printer_name
1480 * Get the pointer to the opened printer name referred by the handle
1482 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
1484 opened_printer_t
*printer
= get_opened_printer(hprn
);
1485 if(!printer
) return NULL
;
1486 return printer
->name
;
1489 /******************************************************************
1490 * WINSPOOL_GetOpenedPrinterRegKey
1493 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
1495 LPCWSTR name
= get_opened_printer_name(hPrinter
);
1499 if(!name
) return ERROR_INVALID_HANDLE
;
1501 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
1505 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
1507 ERR("Can't find opened printer %s in registry\n",
1509 RegCloseKey(hkeyPrinters
);
1510 return ERROR_INVALID_PRINTER_NAME
; /* ? */
1512 RegCloseKey(hkeyPrinters
);
1513 return ERROR_SUCCESS
;
1516 void WINSPOOL_LoadSystemPrinters(void)
1518 HKEY hkey
, hkeyPrinters
;
1520 DWORD needed
, num
, i
;
1521 WCHAR PrinterName
[256];
1524 /* This ensures that all printer entries have a valid Name value. If causes
1525 problems later if they don't. If one is found to be missed we create one
1526 and set it equal to the name of the key */
1527 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1528 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1529 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1530 for(i
= 0; i
< num
; i
++) {
1531 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) == ERROR_SUCCESS
) {
1532 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1533 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1534 set_reg_szW(hkey
, NameW
, PrinterName
);
1541 RegCloseKey(hkeyPrinters
);
1544 /* We want to avoid calling AddPrinter on printers as much as
1545 possible, because on cups printers this will (eventually) lead
1546 to a call to cupsGetPPD which takes forever, even with non-cups
1547 printers AddPrinter takes a while. So we'll tag all printers that
1548 were automatically added last time around, if they still exist
1549 we'll leave them be otherwise we'll delete them. */
1550 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1552 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1553 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1554 for(i
= 0; i
< num
; i
++) {
1555 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1556 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1557 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1559 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1567 HeapFree(GetProcessHeap(), 0, pi
);
1571 #ifdef SONAME_LIBCUPS
1572 done
= CUPS_LoadPrinters();
1575 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1576 PRINTCAP_LoadPrinters();
1578 /* Now enumerate the list again and delete any printers that a still tagged */
1579 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1581 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1582 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1583 for(i
= 0; i
< num
; i
++) {
1584 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1585 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1586 BOOL delete_driver
= FALSE
;
1587 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1588 DWORD dw
, type
, size
= sizeof(dw
);
1589 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1590 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1591 DeletePrinter(hprn
);
1592 delete_driver
= TRUE
;
1598 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1603 HeapFree(GetProcessHeap(), 0, pi
);
1610 /******************************************************************
1613 * Get the pointer to the specified job.
1614 * Should hold the printer_handles_cs before calling.
1616 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1618 opened_printer_t
*printer
= get_opened_printer(hprn
);
1621 if(!printer
) return NULL
;
1622 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1624 if(job
->job_id
== JobId
)
1630 /***********************************************************
1633 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1636 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1639 Formname
= (dmA
->dmSize
> off_formname
);
1640 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1641 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1642 dmW
->dmDeviceName
, CCHDEVICENAME
);
1644 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1645 dmA
->dmSize
- CCHDEVICENAME
);
1647 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1648 off_formname
- CCHDEVICENAME
);
1649 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1650 dmW
->dmFormName
, CCHFORMNAME
);
1651 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1652 (off_formname
+ CCHFORMNAME
));
1655 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1656 dmA
->dmDriverExtra
);
1660 /***********************************************************
1662 * Creates an ascii copy of supplied devmode on heap
1664 static LPDEVMODEA
DEVMODEdupWtoA(HANDLE heap
, const DEVMODEW
*dmW
)
1669 ptrdiff_t off_formname
= (const char *)dmW
->dmFormName
- (const char *)dmW
;
1671 if(!dmW
) return NULL
;
1672 Formname
= (dmW
->dmSize
> off_formname
);
1673 size
= dmW
->dmSize
- CCHDEVICENAME
- (Formname
? CCHFORMNAME
: 0);
1674 dmA
= HeapAlloc(heap
, HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1675 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1676 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1678 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1679 dmW
->dmSize
- CCHDEVICENAME
* sizeof(WCHAR
));
1681 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1682 off_formname
- CCHDEVICENAME
* sizeof(WCHAR
));
1683 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1684 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1685 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
-
1686 (off_formname
+ CCHFORMNAME
* sizeof(WCHAR
)));
1689 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
,
1690 dmW
->dmDriverExtra
);
1694 /***********************************************************
1695 * PRINTER_INFO_2AtoW
1696 * Creates a unicode copy of PRINTER_INFO_2A on heap
1698 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1700 LPPRINTER_INFO_2W piW
;
1701 UNICODE_STRING usBuffer
;
1703 if(!piA
) return NULL
;
1704 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1705 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1707 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1708 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1709 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1710 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1711 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1712 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1713 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1714 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1715 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1716 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1717 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1718 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1722 /***********************************************************
1723 * FREE_PRINTER_INFO_2W
1724 * Free PRINTER_INFO_2W and all strings
1726 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1730 HeapFree(heap
,0,piW
->pServerName
);
1731 HeapFree(heap
,0,piW
->pPrinterName
);
1732 HeapFree(heap
,0,piW
->pShareName
);
1733 HeapFree(heap
,0,piW
->pPortName
);
1734 HeapFree(heap
,0,piW
->pDriverName
);
1735 HeapFree(heap
,0,piW
->pComment
);
1736 HeapFree(heap
,0,piW
->pLocation
);
1737 HeapFree(heap
,0,piW
->pDevMode
);
1738 HeapFree(heap
,0,piW
->pSepFile
);
1739 HeapFree(heap
,0,piW
->pPrintProcessor
);
1740 HeapFree(heap
,0,piW
->pDatatype
);
1741 HeapFree(heap
,0,piW
->pParameters
);
1742 HeapFree(heap
,0,piW
);
1746 /******************************************************************
1747 * DeviceCapabilities [WINSPOOL.@]
1748 * DeviceCapabilitiesA [WINSPOOL.@]
1751 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1752 LPSTR pOutput
, LPDEVMODEA lpdm
)
1756 if (!GDI_CallDeviceCapabilities16
)
1758 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1760 if (!GDI_CallDeviceCapabilities16
) return -1;
1762 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1764 /* If DC_PAPERSIZE map POINT16s to POINTs */
1765 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1766 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1767 POINT
*pt
= (POINT
*)pOutput
;
1769 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1770 for(i
= 0; i
< ret
; i
++, pt
++)
1775 HeapFree( GetProcessHeap(), 0, tmp
);
1781 /*****************************************************************************
1782 * DeviceCapabilitiesW [WINSPOOL.@]
1784 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1787 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1788 WORD fwCapability
, LPWSTR pOutput
,
1789 const DEVMODEW
*pDevMode
)
1791 LPDEVMODEA dmA
= DEVMODEdupWtoA(GetProcessHeap(), pDevMode
);
1792 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1793 LPSTR pPortA
= strdupWtoA(pPort
);
1796 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1797 fwCapability
== DC_FILEDEPENDENCIES
||
1798 fwCapability
== DC_PAPERNAMES
)) {
1799 /* These need A -> W translation */
1802 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1806 switch(fwCapability
) {
1811 case DC_FILEDEPENDENCIES
:
1815 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1816 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1818 for(i
= 0; i
< ret
; i
++)
1819 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1820 pOutput
+ (i
* size
), size
);
1821 HeapFree(GetProcessHeap(), 0, pOutputA
);
1823 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1824 (LPSTR
)pOutput
, dmA
);
1826 HeapFree(GetProcessHeap(),0,pPortA
);
1827 HeapFree(GetProcessHeap(),0,pDeviceA
);
1828 HeapFree(GetProcessHeap(),0,dmA
);
1832 /******************************************************************
1833 * DocumentPropertiesA [WINSPOOL.@]
1835 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1837 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1838 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1839 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1841 LPSTR lpName
= pDeviceName
;
1842 static CHAR port
[] = "LPT1:";
1845 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1846 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1850 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1852 ERR("no name from hPrinter?\n");
1853 SetLastError(ERROR_INVALID_HANDLE
);
1856 lpName
= strdupWtoA(lpNameW
);
1859 if (!GDI_CallExtDeviceMode16
)
1861 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1863 if (!GDI_CallExtDeviceMode16
) {
1864 ERR("No CallExtDeviceMode16?\n");
1868 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1869 pDevModeInput
, NULL
, fMode
);
1872 HeapFree(GetProcessHeap(),0,lpName
);
1877 /*****************************************************************************
1878 * DocumentPropertiesW (WINSPOOL.@)
1880 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1882 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1884 LPDEVMODEW pDevModeOutput
,
1885 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1888 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1889 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput
);
1890 LPDEVMODEA pDevModeOutputA
= NULL
;
1893 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1894 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1896 if(pDevModeOutput
) {
1897 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1898 if(ret
< 0) return ret
;
1899 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1901 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1902 pDevModeInputA
, fMode
);
1903 if(pDevModeOutput
) {
1904 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1905 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1907 if(fMode
== 0 && ret
> 0)
1908 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1909 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1910 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1914 /******************************************************************
1915 * OpenPrinterA [WINSPOOL.@]
1920 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1921 LPPRINTER_DEFAULTSA pDefault
)
1923 UNICODE_STRING lpPrinterNameW
;
1924 UNICODE_STRING usBuffer
;
1925 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1926 PWSTR pwstrPrinterNameW
;
1929 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1932 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1933 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1934 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1935 pDefaultW
= &DefaultW
;
1937 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1939 RtlFreeUnicodeString(&usBuffer
);
1940 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1942 RtlFreeUnicodeString(&lpPrinterNameW
);
1946 /******************************************************************
1947 * OpenPrinterW [WINSPOOL.@]
1949 * Open a Printer / Printserver or a Printer-Object
1952 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1953 * phPrinter [O] The resulting Handle is stored here
1954 * pDefault [I] PTR to Default Printer Settings or NULL
1961 * lpPrinterName is one of:
1962 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1963 *| Printer: "PrinterName"
1964 *| Printer-Object: "PrinterName,Job xxx"
1965 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1966 *| XcvPort: "Servername,XcvPort PortName"
1969 *| Printer-Object not supported
1970 *| pDefaults is ignored
1973 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1976 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
1978 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1979 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
1983 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1984 SetLastError(ERROR_INVALID_PARAMETER
);
1988 /* Get the unique handle of the printer or Printserver */
1989 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
1990 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
1991 return (*phPrinter
!= 0);
1994 /******************************************************************
1995 * AddMonitorA [WINSPOOL.@]
2000 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2002 LPWSTR nameW
= NULL
;
2005 LPMONITOR_INFO_2A mi2a
;
2006 MONITOR_INFO_2W mi2w
;
2008 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2009 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2010 mi2a
? debugstr_a(mi2a
->pName
) : NULL
,
2011 mi2a
? debugstr_a(mi2a
->pEnvironment
) : NULL
,
2012 mi2a
? debugstr_a(mi2a
->pDLLName
) : NULL
);
2015 SetLastError(ERROR_INVALID_LEVEL
);
2019 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2025 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2026 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2027 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2030 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2032 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2033 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2034 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2036 if (mi2a
->pEnvironment
) {
2037 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2038 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2039 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2041 if (mi2a
->pDLLName
) {
2042 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2043 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2044 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2047 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2049 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2050 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2051 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2053 HeapFree(GetProcessHeap(), 0, nameW
);
2057 /******************************************************************************
2058 * AddMonitorW [WINSPOOL.@]
2060 * Install a Printmonitor
2063 * pName [I] Servername or NULL (local Computer)
2064 * Level [I] Structure-Level (Must be 2)
2065 * pMonitors [I] PTR to MONITOR_INFO_2
2072 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2075 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2077 monitor_t
* pm
= NULL
;
2078 LPMONITOR_INFO_2W mi2w
;
2084 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2085 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2086 mi2w
? debugstr_w(mi2w
->pName
) : NULL
,
2087 mi2w
? debugstr_w(mi2w
->pEnvironment
) : NULL
,
2088 mi2w
? debugstr_w(mi2w
->pDLLName
) : NULL
);
2091 SetLastError(ERROR_INVALID_LEVEL
);
2095 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2100 if (pName
&& (pName
[0])) {
2101 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2102 SetLastError(ERROR_ACCESS_DENIED
);
2107 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
2108 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
2109 SetLastError(ERROR_INVALID_PARAMETER
);
2112 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, envname_x86W
)) {
2113 WARN("Environment %s requested (we support only %s)\n",
2114 debugstr_w(mi2w
->pEnvironment
), debugstr_w(envname_x86W
));
2115 SetLastError(ERROR_INVALID_ENVIRONMENT
);
2119 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
2120 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
2121 SetLastError(ERROR_INVALID_PARAMETER
);
2125 /* Load and initialize the monitor. SetLastError() is called on failure */
2126 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
2131 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2132 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2136 if(RegCreateKeyExW( hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2137 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
2138 &disposition
) == ERROR_SUCCESS
) {
2140 /* Some installers set options for the port before calling AddMonitor.
2141 We query the "Driver" entry to verify that the monitor is installed,
2142 before we return an error.
2143 When a user installs two print monitors at the same time with the
2144 same name but with a different driver DLL and a task switch comes
2145 between RegQueryValueExW and RegSetValueExW, a race condition
2146 is possible but silently ignored. */
2150 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
2151 (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, NULL
,
2152 &namesize
) == ERROR_SUCCESS
)) {
2153 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
2154 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2155 9x: ERROR_ALREADY_EXISTS (183) */
2156 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
2161 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
2162 res
= (RegSetValueExW(hentry
, DriverW
, 0,
2163 REG_SZ
, (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
2165 RegCloseKey(hentry
);
2172 /******************************************************************
2173 * DeletePrinterDriverA [WINSPOOL.@]
2176 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2178 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2181 /******************************************************************
2182 * DeletePrinterDriverW [WINSPOOL.@]
2185 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2187 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2190 /******************************************************************
2191 * DeleteMonitorA [WINSPOOL.@]
2193 * See DeleteMonitorW.
2196 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2198 LPWSTR nameW
= NULL
;
2199 LPWSTR EnvironmentW
= NULL
;
2200 LPWSTR MonitorNameW
= NULL
;
2205 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2206 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2207 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2211 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2212 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2213 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2216 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2217 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2218 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2221 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2223 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2224 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2225 HeapFree(GetProcessHeap(), 0, nameW
);
2229 /******************************************************************
2230 * DeleteMonitorW [WINSPOOL.@]
2232 * Delete a specific Printmonitor from a Printing-Environment
2235 * pName [I] Servername or NULL (local Computer)
2236 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2237 * pMonitorName [I] Name of the Monitor, that should be deleted
2244 * pEnvironment is ignored in Windows for the local Computer.
2248 BOOL WINAPI
DeleteMonitorW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2252 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2253 debugstr_w(pMonitorName
));
2255 if (pName
&& (pName
[0])) {
2256 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2257 SetLastError(ERROR_ACCESS_DENIED
);
2261 /* pEnvironment is ignored in Windows for the local Computer */
2263 if (!pMonitorName
|| !pMonitorName
[0]) {
2264 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
2265 SetLastError(ERROR_INVALID_PARAMETER
);
2269 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2270 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2274 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
2275 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName
));
2280 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName
));
2283 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2284 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
2288 /******************************************************************
2289 * DeletePortA [WINSPOOL.@]
2294 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2296 LPWSTR nameW
= NULL
;
2297 LPWSTR portW
= NULL
;
2301 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2303 /* convert servername to unicode */
2305 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2306 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2307 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2310 /* convert portname to unicode */
2312 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2313 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2314 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2317 res
= DeletePortW(nameW
, hWnd
, portW
);
2318 HeapFree(GetProcessHeap(), 0, nameW
);
2319 HeapFree(GetProcessHeap(), 0, portW
);
2323 /******************************************************************
2324 * DeletePortW [WINSPOOL.@]
2326 * Delete a specific Port
2329 * pName [I] Servername or NULL (local Computer)
2330 * hWnd [I] Handle to parent Window for the Dialog-Box
2331 * pPortName [I] Name of the Port, that should be deleted
2338 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2344 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2346 if (pName
&& pName
[0]) {
2347 SetLastError(ERROR_INVALID_PARAMETER
);
2352 SetLastError(RPC_X_NULL_REF_POINTER
);
2356 /* an empty Portname is Invalid */
2357 if (!pPortName
[0]) {
2358 SetLastError(ERROR_NOT_SUPPORTED
);
2362 pm
= monitor_load_by_port(pPortName
);
2363 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
2364 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2365 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
2366 TRACE("got %d with %u\n", res
, GetLastError());
2370 pui
= monitor_loadui(pm
);
2371 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2372 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2373 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2374 TRACE("got %d with %u\n", res
, GetLastError());
2378 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
2379 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
2381 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2382 SetLastError(ERROR_NOT_SUPPORTED
);
2385 monitor_unload(pui
);
2389 TRACE("returning %d with %u\n", res
, GetLastError());
2393 /******************************************************************************
2394 * SetPrinterW [WINSPOOL.@]
2396 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2398 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2399 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2403 /******************************************************************************
2404 * WritePrinter [WINSPOOL.@]
2406 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2408 opened_printer_t
*printer
;
2411 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2413 EnterCriticalSection(&printer_handles_cs
);
2414 printer
= get_opened_printer(hPrinter
);
2417 SetLastError(ERROR_INVALID_HANDLE
);
2423 SetLastError(ERROR_SPL_NO_STARTDOC
);
2427 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2429 LeaveCriticalSection(&printer_handles_cs
);
2433 /*****************************************************************************
2434 * AddFormA [WINSPOOL.@]
2436 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2438 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2442 /*****************************************************************************
2443 * AddFormW [WINSPOOL.@]
2445 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2447 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2451 /*****************************************************************************
2452 * AddJobA [WINSPOOL.@]
2454 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2457 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2461 SetLastError(ERROR_INVALID_LEVEL
);
2465 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2468 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2469 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2470 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2471 if(*pcbNeeded
> cbBuf
) {
2472 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2475 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2476 addjobA
->JobId
= addjobW
->JobId
;
2477 addjobA
->Path
= (char *)(addjobA
+ 1);
2478 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2484 /*****************************************************************************
2485 * AddJobW [WINSPOOL.@]
2487 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2489 opened_printer_t
*printer
;
2492 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2493 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2494 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2496 ADDJOB_INFO_1W
*addjob
;
2498 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2500 EnterCriticalSection(&printer_handles_cs
);
2502 printer
= get_opened_printer(hPrinter
);
2505 SetLastError(ERROR_INVALID_HANDLE
);
2510 SetLastError(ERROR_INVALID_LEVEL
);
2514 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2518 job
->job_id
= InterlockedIncrement(&next_job_id
);
2520 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2521 if(path
[len
- 1] != '\\')
2523 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2524 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2526 len
= strlenW(filename
);
2527 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2528 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2529 job
->document_title
= strdupW(default_doc_title
);
2530 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2532 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2533 if(*pcbNeeded
<= cbBuf
) {
2534 addjob
= (ADDJOB_INFO_1W
*)pData
;
2535 addjob
->JobId
= job
->job_id
;
2536 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2537 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2540 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2543 LeaveCriticalSection(&printer_handles_cs
);
2547 /*****************************************************************************
2548 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2550 * Return the PATH for the Print-Processors
2552 * See GetPrintProcessorDirectoryW.
2556 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2557 DWORD level
, LPBYTE Info
,
2558 DWORD cbBuf
, LPDWORD pcbNeeded
)
2560 LPWSTR serverW
= NULL
;
2565 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2566 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2570 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2571 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2572 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2576 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2577 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2578 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2581 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2582 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2584 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2587 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2588 cbBuf
, NULL
, NULL
) > 0;
2591 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2592 HeapFree(GetProcessHeap(), 0, envW
);
2593 HeapFree(GetProcessHeap(), 0, serverW
);
2597 /*****************************************************************************
2598 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2600 * Return the PATH for the Print-Processors
2603 * server [I] Servername (NT only) or NULL (local Computer)
2604 * env [I] Printing-Environment (see below) or NULL (Default)
2605 * level [I] Structure-Level (must be 1)
2606 * Info [O] PTR to Buffer that receives the Result
2607 * cbBuf [I] Size of Buffer at "Info"
2608 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2609 * required for the Buffer at "Info"
2612 * Success: TRUE and in pcbNeeded the Bytes used in Info
2613 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2614 * if cbBuf is too small
2616 * Native Values returned in Info on Success:
2617 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2618 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2619 *| win9x(Windows 4.0): "%winsysdir%"
2621 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2624 * Only NULL or "" is supported for server
2627 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2628 DWORD level
, LPBYTE Info
,
2629 DWORD cbBuf
, LPDWORD pcbNeeded
)
2632 const printenv_t
* env_t
;
2634 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
),
2635 debugstr_w(env
), level
, Info
, cbBuf
, pcbNeeded
);
2637 if(server
!= NULL
&& server
[0]) {
2638 FIXME("server not supported: %s\n", debugstr_w(server
));
2639 SetLastError(ERROR_INVALID_PARAMETER
);
2643 env_t
= validate_envW(env
);
2644 if(!env_t
) return FALSE
; /* environment invalid or unsupported */
2647 WARN("(Level: %d) is ignored in win9x\n", level
);
2648 SetLastError(ERROR_INVALID_LEVEL
);
2652 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2653 needed
= GetSystemDirectoryW(NULL
, 0);
2654 /* add the Size for the Subdirectories */
2655 needed
+= lstrlenW(spoolprtprocsW
);
2656 needed
+= lstrlenW(env_t
->subdir
);
2657 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2659 if(pcbNeeded
) *pcbNeeded
= needed
;
2660 TRACE ("required: 0x%x/%d\n", needed
, needed
);
2661 if (needed
> cbBuf
) {
2662 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2665 if(pcbNeeded
== NULL
) {
2666 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2667 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2668 SetLastError(RPC_X_NULL_REF_POINTER
);
2672 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2673 SetLastError(RPC_X_NULL_REF_POINTER
);
2677 GetSystemDirectoryW((LPWSTR
) Info
, cbBuf
/sizeof(WCHAR
));
2678 /* add the Subdirectories */
2679 lstrcatW((LPWSTR
) Info
, spoolprtprocsW
);
2680 lstrcatW((LPWSTR
) Info
, env_t
->subdir
);
2681 TRACE(" => %s\n", debugstr_w((LPWSTR
) Info
));
2685 /*****************************************************************************
2686 * WINSPOOL_OpenDriverReg [internal]
2688 * opens the registry for the printer drivers depending on the given input
2689 * variable pEnvironment
2692 * the opened hkey on success
2695 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
, BOOL unicode
)
2699 const printenv_t
* env
;
2702 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
), unicode
);
2704 if (!pEnvironment
|| unicode
) {
2705 /* pEnvironment was NULL or an Unicode-String: use it direct */
2706 env
= validate_envW(pEnvironment
);
2710 /* pEnvironment was an ANSI-String: convert to unicode first */
2712 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
2713 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2714 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
2715 env
= validate_envW(buffer
);
2716 HeapFree(GetProcessHeap(), 0, buffer
);
2718 if (!env
) return NULL
;
2720 buffer
= HeapAlloc( GetProcessHeap(), 0,
2721 (strlenW(DriversW
) + strlenW(env
->envname
) +
2722 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2724 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2725 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2726 HeapFree(GetProcessHeap(), 0, buffer
);
2731 /*****************************************************************************
2732 * AddPrinterW [WINSPOOL.@]
2734 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2736 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2740 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2742 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2743 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2744 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2745 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2746 statusW
[] = {'S','t','a','t','u','s',0},
2747 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2749 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2752 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2753 SetLastError(ERROR_INVALID_PARAMETER
);
2757 ERR("Level = %d, unsupported!\n", Level
);
2758 SetLastError(ERROR_INVALID_LEVEL
);
2762 SetLastError(ERROR_INVALID_PARAMETER
);
2765 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2767 ERR("Can't create Printers key\n");
2770 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2771 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2772 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2773 RegCloseKey(hkeyPrinter
);
2774 RegCloseKey(hkeyPrinters
);
2777 RegCloseKey(hkeyPrinter
);
2779 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
2781 ERR("Can't create Drivers key\n");
2782 RegCloseKey(hkeyPrinters
);
2785 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2787 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2788 RegCloseKey(hkeyPrinters
);
2789 RegCloseKey(hkeyDrivers
);
2790 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2793 RegCloseKey(hkeyDriver
);
2794 RegCloseKey(hkeyDrivers
);
2796 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2797 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2798 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2799 RegCloseKey(hkeyPrinters
);
2803 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2805 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2806 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2807 RegCloseKey(hkeyPrinters
);
2810 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2811 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2812 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2814 /* See if we can load the driver. We may need the devmode structure anyway
2817 * Note that DocumentPropertiesW will briefly try to open the printer we
2818 * just create to find a DEVMODEA struct (it will use the WINEPS default
2819 * one in case it is not there, so we are ok).
2821 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2824 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2825 size
= sizeof(DEVMODEW
);
2831 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2833 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2835 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2836 HeapFree(GetProcessHeap(),0,dmW
);
2841 /* set devmode to printer name */
2842 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2846 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2847 and we support these drivers. NT writes DEVMODEW so somehow
2848 we'll need to distinguish between these when we support NT
2852 dmA
= DEVMODEdupWtoA(GetProcessHeap(), dmW
);
2853 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2854 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2855 HeapFree(GetProcessHeap(), 0, dmA
);
2857 HeapFree(GetProcessHeap(), 0, dmW
);
2859 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2860 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2861 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2862 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2864 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2865 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2866 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2867 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2868 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2869 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2870 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2871 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2872 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2873 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2874 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2875 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2876 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2878 RegCloseKey(hkeyPrinter
);
2879 RegCloseKey(hkeyPrinters
);
2880 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2881 ERR("OpenPrinter failing\n");
2887 /*****************************************************************************
2888 * AddPrinterA [WINSPOOL.@]
2890 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2892 UNICODE_STRING pNameW
;
2894 PRINTER_INFO_2W
*piW
;
2895 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2898 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
2900 ERR("Level = %d, unsupported!\n", Level
);
2901 SetLastError(ERROR_INVALID_LEVEL
);
2904 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2905 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2907 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2909 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2910 RtlFreeUnicodeString(&pNameW
);
2915 /*****************************************************************************
2916 * ClosePrinter [WINSPOOL.@]
2918 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2920 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2921 opened_printer_t
*printer
= NULL
;
2924 TRACE("(%p)\n", hPrinter
);
2926 EnterCriticalSection(&printer_handles_cs
);
2928 if ((i
> 0) && (i
<= nb_printer_handles
))
2929 printer
= printer_handles
[i
- 1];
2934 struct list
*cursor
, *cursor2
;
2936 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer
->pm
,
2937 debugstr_w(printer
->pm
? printer
->pm
->dllname
: NULL
),
2938 printer
->hXcv
, debugstr_w(printer
->name
), printer
->doc
);
2941 EndDocPrinter(hPrinter
);
2943 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2945 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2947 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2948 ScheduleJob(hPrinter
, job
->job_id
);
2950 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2952 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
2953 monitor_unload(printer
->pm
);
2954 HeapFree(GetProcessHeap(), 0, printer
->printername
);
2955 HeapFree(GetProcessHeap(), 0, printer
->name
);
2956 HeapFree(GetProcessHeap(), 0, printer
);
2957 printer_handles
[i
- 1] = NULL
;
2960 LeaveCriticalSection(&printer_handles_cs
);
2964 /*****************************************************************************
2965 * DeleteFormA [WINSPOOL.@]
2967 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2969 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2973 /*****************************************************************************
2974 * DeleteFormW [WINSPOOL.@]
2976 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2978 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2982 /*****************************************************************************
2983 * DeletePrinter [WINSPOOL.@]
2985 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2987 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2988 HKEY hkeyPrinters
, hkey
;
2991 SetLastError(ERROR_INVALID_HANDLE
);
2994 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
2995 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
2996 RegCloseKey(hkeyPrinters
);
2998 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
2999 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3000 RegDeleteValueW(hkey
, lpNameW
);
3006 /*****************************************************************************
3007 * SetPrinterA [WINSPOOL.@]
3009 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3012 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
3016 /*****************************************************************************
3017 * SetJobA [WINSPOOL.@]
3019 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3020 LPBYTE pJob
, DWORD Command
)
3024 UNICODE_STRING usBuffer
;
3026 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3028 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3029 are all ignored by SetJob, so we don't bother copying them */
3037 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3038 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3040 JobW
= (LPBYTE
)info1W
;
3041 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3042 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3043 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3044 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3045 info1W
->Status
= info1A
->Status
;
3046 info1W
->Priority
= info1A
->Priority
;
3047 info1W
->Position
= info1A
->Position
;
3048 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3053 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3054 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3056 JobW
= (LPBYTE
)info2W
;
3057 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3058 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3059 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3060 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3061 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3062 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3063 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3064 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3065 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3066 info2W
->Status
= info2A
->Status
;
3067 info2W
->Priority
= info2A
->Priority
;
3068 info2W
->Position
= info2A
->Position
;
3069 info2W
->StartTime
= info2A
->StartTime
;
3070 info2W
->UntilTime
= info2A
->UntilTime
;
3071 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3075 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3076 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3079 SetLastError(ERROR_INVALID_LEVEL
);
3083 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3089 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3090 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3091 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3092 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3093 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3098 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3099 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3100 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3101 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3102 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3103 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3104 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3105 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3106 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3110 HeapFree(GetProcessHeap(), 0, JobW
);
3115 /*****************************************************************************
3116 * SetJobW [WINSPOOL.@]
3118 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3119 LPBYTE pJob
, DWORD Command
)
3124 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3125 FIXME("Ignoring everything other than document title\n");
3127 EnterCriticalSection(&printer_handles_cs
);
3128 job
= get_job(hPrinter
, JobId
);
3138 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3139 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3140 job
->document_title
= strdupW(info1
->pDocument
);
3145 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3146 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3147 job
->document_title
= strdupW(info2
->pDocument
);
3153 SetLastError(ERROR_INVALID_LEVEL
);
3158 LeaveCriticalSection(&printer_handles_cs
);
3162 /*****************************************************************************
3163 * EndDocPrinter [WINSPOOL.@]
3165 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3167 opened_printer_t
*printer
;
3169 TRACE("(%p)\n", hPrinter
);
3171 EnterCriticalSection(&printer_handles_cs
);
3173 printer
= get_opened_printer(hPrinter
);
3176 SetLastError(ERROR_INVALID_HANDLE
);
3182 SetLastError(ERROR_SPL_NO_STARTDOC
);
3186 CloseHandle(printer
->doc
->hf
);
3187 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3188 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3189 printer
->doc
= NULL
;
3192 LeaveCriticalSection(&printer_handles_cs
);
3196 /*****************************************************************************
3197 * EndPagePrinter [WINSPOOL.@]
3199 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3201 FIXME("(%p): stub\n", hPrinter
);
3205 /*****************************************************************************
3206 * StartDocPrinterA [WINSPOOL.@]
3208 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3210 UNICODE_STRING usBuffer
;
3212 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3215 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3216 or one (DOC_INFO_3) extra DWORDs */
3220 doc2W
.JobId
= doc2
->JobId
;
3223 doc2W
.dwMode
= doc2
->dwMode
;
3226 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3227 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3228 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3232 SetLastError(ERROR_INVALID_LEVEL
);
3236 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3238 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3239 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3240 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3245 /*****************************************************************************
3246 * StartDocPrinterW [WINSPOOL.@]
3248 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3250 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3251 opened_printer_t
*printer
;
3252 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3253 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3254 JOB_INFO_1W job_info
;
3255 DWORD needed
, ret
= 0;
3259 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3260 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3261 debugstr_w(doc
->pDatatype
));
3263 if(Level
< 1 || Level
> 3)
3265 SetLastError(ERROR_INVALID_LEVEL
);
3269 EnterCriticalSection(&printer_handles_cs
);
3270 printer
= get_opened_printer(hPrinter
);
3273 SetLastError(ERROR_INVALID_HANDLE
);
3279 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3283 /* Even if we're printing to a file we still add a print job, we'll
3284 just ignore the spool file name */
3286 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3288 ERR("AddJob failed gle %u\n", GetLastError());
3292 if(doc
->pOutputFile
)
3293 filename
= doc
->pOutputFile
;
3295 filename
= addjob
->Path
;
3297 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3298 if(hf
== INVALID_HANDLE_VALUE
)
3301 memset(&job_info
, 0, sizeof(job_info
));
3302 job_info
.pDocument
= doc
->pDocName
;
3303 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3305 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3306 printer
->doc
->hf
= hf
;
3307 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3309 LeaveCriticalSection(&printer_handles_cs
);
3314 /*****************************************************************************
3315 * StartPagePrinter [WINSPOOL.@]
3317 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3319 FIXME("(%p): stub\n", hPrinter
);
3323 /*****************************************************************************
3324 * GetFormA [WINSPOOL.@]
3326 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3327 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3329 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3330 Level
,pForm
,cbBuf
,pcbNeeded
);
3334 /*****************************************************************************
3335 * GetFormW [WINSPOOL.@]
3337 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3338 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3340 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3341 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3345 /*****************************************************************************
3346 * SetFormA [WINSPOOL.@]
3348 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3351 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3355 /*****************************************************************************
3356 * SetFormW [WINSPOOL.@]
3358 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3361 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3365 /*****************************************************************************
3366 * ReadPrinter [WINSPOOL.@]
3368 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3369 LPDWORD pNoBytesRead
)
3371 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3375 /*****************************************************************************
3376 * ResetPrinterA [WINSPOOL.@]
3378 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3380 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3384 /*****************************************************************************
3385 * ResetPrinterW [WINSPOOL.@]
3387 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3389 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3393 /*****************************************************************************
3394 * WINSPOOL_GetDWORDFromReg
3396 * Return DWORD associated with ValueName from hkey.
3398 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3400 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3403 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3405 if(ret
!= ERROR_SUCCESS
) {
3406 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3409 if(type
!= REG_DWORD
) {
3410 ERR("Got type %d\n", type
);
3416 /*****************************************************************************
3417 * WINSPOOL_GetStringFromReg
3419 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3420 * String is stored either as unicode or ascii.
3421 * Bit of a hack here to get the ValueName if we want ascii.
3423 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3424 DWORD buflen
, DWORD
*needed
,
3427 DWORD sz
= buflen
, type
;
3431 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3433 LPSTR ValueNameA
= strdupWtoA(ValueName
);
3434 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
3435 HeapFree(GetProcessHeap(),0,ValueNameA
);
3437 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3438 WARN("Got ret = %d\n", ret
);
3442 /* add space for terminating '\0' */
3443 sz
+= unicode
? sizeof(WCHAR
) : 1;
3447 TRACE("%s: %s\n", debugstr_w(ValueName
), unicode
? debugstr_w((LPCWSTR
)ptr
) : debugstr_a((LPCSTR
)ptr
));
3452 /*****************************************************************************
3453 * WINSPOOL_GetDefaultDevMode
3455 * Get a default DevMode values for wineps.
3459 static void WINSPOOL_GetDefaultDevMode(
3461 DWORD buflen
, DWORD
*needed
,
3465 static const char szwps
[] = "wineps.drv";
3467 /* fill default DEVMODE - should be read from ppd... */
3468 ZeroMemory( &dm
, sizeof(dm
) );
3469 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
3470 dm
.dmSpecVersion
= DM_SPECVERSION
;
3471 dm
.dmDriverVersion
= 1;
3472 dm
.dmSize
= sizeof(DEVMODEA
);
3473 dm
.dmDriverExtra
= 0;
3475 DM_ORIENTATION
| DM_PAPERSIZE
|
3476 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3479 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3480 DM_YRESOLUTION
| DM_TTOPTION
;
3482 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3483 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3484 dm
.u1
.s1
.dmPaperLength
= 2970;
3485 dm
.u1
.s1
.dmPaperWidth
= 2100;
3489 dm
.dmDefaultSource
= DMBIN_AUTO
;
3490 dm
.dmPrintQuality
= DMRES_MEDIUM
;
3493 dm
.dmYResolution
= 300; /* 300dpi */
3494 dm
.dmTTOption
= DMTT_BITMAP
;
3497 /* dm.dmLogPixels */
3498 /* dm.dmBitsPerPel */
3499 /* dm.dmPelsWidth */
3500 /* dm.dmPelsHeight */
3501 /* dm.dmDisplayFlags */
3502 /* dm.dmDisplayFrequency */
3503 /* dm.dmICMMethod */
3504 /* dm.dmICMIntent */
3505 /* dm.dmMediaType */
3506 /* dm.dmDitherType */
3507 /* dm.dmReserved1 */
3508 /* dm.dmReserved2 */
3509 /* dm.dmPanningWidth */
3510 /* dm.dmPanningHeight */
3513 if(buflen
>= sizeof(DEVMODEW
)) {
3514 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
3515 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
3516 HeapFree(GetProcessHeap(),0,pdmW
);
3518 *needed
= sizeof(DEVMODEW
);
3522 if(buflen
>= sizeof(DEVMODEA
)) {
3523 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
3525 *needed
= sizeof(DEVMODEA
);
3529 /*****************************************************************************
3530 * WINSPOOL_GetDevModeFromReg
3532 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3533 * DevMode is stored either as unicode or ascii.
3535 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3537 DWORD buflen
, DWORD
*needed
,
3540 DWORD sz
= buflen
, type
;
3543 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3544 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3545 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3546 if (sz
< sizeof(DEVMODEA
))
3548 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3551 /* ensures that dmSize is not erratically bogus if registry is invalid */
3552 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3553 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3555 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3557 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3558 memcpy(ptr
, dmW
, sz
);
3559 HeapFree(GetProcessHeap(),0,dmW
);
3566 /*********************************************************************
3567 * WINSPOOL_GetPrinter_1
3569 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3570 * The strings are either stored as unicode or ascii.
3572 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3573 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3576 DWORD size
, left
= cbBuf
;
3577 BOOL space
= (cbBuf
> 0);
3582 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3584 if(space
&& size
<= left
) {
3585 pi1
->pName
= (LPWSTR
)ptr
;
3593 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3594 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3596 if(space
&& size
<= left
) {
3597 pi1
->pDescription
= (LPWSTR
)ptr
;
3605 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3607 if(space
&& size
<= left
) {
3608 pi1
->pComment
= (LPWSTR
)ptr
;
3616 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3618 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3619 memset(pi1
, 0, sizeof(*pi1
));
3623 /*********************************************************************
3624 * WINSPOOL_GetPrinter_2
3626 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3627 * The strings are either stored as unicode or ascii.
3629 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3630 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3633 DWORD size
, left
= cbBuf
;
3634 BOOL space
= (cbBuf
> 0);
3639 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3641 if(space
&& size
<= left
) {
3642 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3649 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
3651 if(space
&& size
<= left
) {
3652 pi2
->pShareName
= (LPWSTR
)ptr
;
3659 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3661 if(space
&& size
<= left
) {
3662 pi2
->pPortName
= (LPWSTR
)ptr
;
3669 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
3671 if(space
&& size
<= left
) {
3672 pi2
->pDriverName
= (LPWSTR
)ptr
;
3679 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3681 if(space
&& size
<= left
) {
3682 pi2
->pComment
= (LPWSTR
)ptr
;
3689 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
3691 if(space
&& size
<= left
) {
3692 pi2
->pLocation
= (LPWSTR
)ptr
;
3699 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
3701 if(space
&& size
<= left
) {
3702 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3711 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
3712 if(space
&& size
<= left
) {
3713 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3720 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
3722 if(space
&& size
<= left
) {
3723 pi2
->pSepFile
= (LPWSTR
)ptr
;
3730 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
3732 if(space
&& size
<= left
) {
3733 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3740 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
3742 if(space
&& size
<= left
) {
3743 pi2
->pDatatype
= (LPWSTR
)ptr
;
3750 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
3752 if(space
&& size
<= left
) {
3753 pi2
->pParameters
= (LPWSTR
)ptr
;
3761 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3762 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3763 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3764 "Default Priority");
3765 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3766 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3769 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3770 memset(pi2
, 0, sizeof(*pi2
));
3775 /*********************************************************************
3776 * WINSPOOL_GetPrinter_4
3778 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3780 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3781 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3784 DWORD size
, left
= cbBuf
;
3785 BOOL space
= (cbBuf
> 0);
3790 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3792 if(space
&& size
<= left
) {
3793 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3801 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3804 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3805 memset(pi4
, 0, sizeof(*pi4
));
3810 /*********************************************************************
3811 * WINSPOOL_GetPrinter_5
3813 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3815 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3816 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3819 DWORD size
, left
= cbBuf
;
3820 BOOL space
= (cbBuf
> 0);
3825 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3827 if(space
&& size
<= left
) {
3828 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3835 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3837 if(space
&& size
<= left
) {
3838 pi5
->pPortName
= (LPWSTR
)ptr
;
3846 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3847 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3849 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3853 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3854 memset(pi5
, 0, sizeof(*pi5
));
3859 /*****************************************************************************
3860 * WINSPOOL_GetPrinter
3862 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3863 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3864 * just a collection of pointers to strings.
3866 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3867 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
3870 DWORD size
, needed
= 0;
3872 HKEY hkeyPrinter
, hkeyPrinters
;
3875 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3877 if (!(name
= get_opened_printer_name(hPrinter
))) {
3878 SetLastError(ERROR_INVALID_HANDLE
);
3882 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3884 ERR("Can't create Printers key\n");
3887 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
3889 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3890 RegCloseKey(hkeyPrinters
);
3891 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3898 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3900 size
= sizeof(PRINTER_INFO_2W
);
3902 ptr
= pPrinter
+ size
;
3904 memset(pPrinter
, 0, size
);
3909 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
3917 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3919 size
= sizeof(PRINTER_INFO_4W
);
3921 ptr
= pPrinter
+ size
;
3923 memset(pPrinter
, 0, size
);
3928 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
3937 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3939 size
= sizeof(PRINTER_INFO_5W
);
3941 ptr
= pPrinter
+ size
;
3943 memset(pPrinter
, 0, size
);
3949 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
3956 FIXME("Unimplemented level %d\n", Level
);
3957 SetLastError(ERROR_INVALID_LEVEL
);
3958 RegCloseKey(hkeyPrinters
);
3959 RegCloseKey(hkeyPrinter
);
3963 RegCloseKey(hkeyPrinter
);
3964 RegCloseKey(hkeyPrinters
);
3966 TRACE("returning %d needed = %d\n", ret
, needed
);
3967 if(pcbNeeded
) *pcbNeeded
= needed
;
3969 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3973 /*****************************************************************************
3974 * GetPrinterW [WINSPOOL.@]
3976 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3977 DWORD cbBuf
, LPDWORD pcbNeeded
)
3979 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
3983 /*****************************************************************************
3984 * GetPrinterA [WINSPOOL.@]
3986 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3987 DWORD cbBuf
, LPDWORD pcbNeeded
)
3989 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
3993 /*****************************************************************************
3994 * WINSPOOL_EnumPrinters
3996 * Implementation of EnumPrintersA|W
3998 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
3999 DWORD dwLevel
, LPBYTE lpbPrinters
,
4000 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4001 LPDWORD lpdwReturned
, BOOL unicode
)
4004 HKEY hkeyPrinters
, hkeyPrinter
;
4005 WCHAR PrinterName
[255];
4006 DWORD needed
= 0, number
= 0;
4007 DWORD used
, i
, left
;
4011 memset(lpbPrinters
, 0, cbBuf
);
4017 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4018 if(dwType
== PRINTER_ENUM_DEFAULT
)
4021 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4022 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4023 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4025 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4033 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4034 FIXME("dwType = %08x\n", dwType
);
4035 SetLastError(ERROR_INVALID_FLAGS
);
4039 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4041 ERR("Can't create Printers key\n");
4045 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4046 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4047 RegCloseKey(hkeyPrinters
);
4048 ERR("Can't query Printers key\n");
4051 TRACE("Found %d printers\n", number
);
4055 used
= number
* sizeof(PRINTER_INFO_1W
);
4058 used
= number
* sizeof(PRINTER_INFO_2W
);
4061 used
= number
* sizeof(PRINTER_INFO_4W
);
4064 used
= number
* sizeof(PRINTER_INFO_5W
);
4068 SetLastError(ERROR_INVALID_LEVEL
);
4069 RegCloseKey(hkeyPrinters
);
4072 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4074 for(i
= 0; i
< number
; i
++) {
4075 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) !=
4077 ERR("Can't enum key number %d\n", i
);
4078 RegCloseKey(hkeyPrinters
);
4081 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4082 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4084 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4085 RegCloseKey(hkeyPrinters
);
4090 buf
= lpbPrinters
+ used
;
4091 left
= cbBuf
- used
;
4099 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4100 left
, &needed
, unicode
);
4102 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4105 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4106 left
, &needed
, unicode
);
4108 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4111 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4112 left
, &needed
, unicode
);
4114 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4117 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4118 left
, &needed
, unicode
);
4120 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4123 ERR("Shouldn't be here!\n");
4124 RegCloseKey(hkeyPrinter
);
4125 RegCloseKey(hkeyPrinters
);
4128 RegCloseKey(hkeyPrinter
);
4130 RegCloseKey(hkeyPrinters
);
4137 memset(lpbPrinters
, 0, cbBuf
);
4138 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4142 *lpdwReturned
= number
;
4143 SetLastError(ERROR_SUCCESS
);
4148 /******************************************************************
4149 * EnumPrintersW [WINSPOOL.@]
4151 * Enumerates the available printers, print servers and print
4152 * providers, depending on the specified flags, name and level.
4156 * If level is set to 1:
4157 * Returns an array of PRINTER_INFO_1 data structures in the
4158 * lpbPrinters buffer.
4160 * If level is set to 2:
4161 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4162 * Returns an array of PRINTER_INFO_2 data structures in the
4163 * lpbPrinters buffer. Note that according to MSDN also an
4164 * OpenPrinter should be performed on every remote printer.
4166 * If level is set to 4 (officially WinNT only):
4167 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4168 * Fast: Only the registry is queried to retrieve printer names,
4169 * no connection to the driver is made.
4170 * Returns an array of PRINTER_INFO_4 data structures in the
4171 * lpbPrinters buffer.
4173 * If level is set to 5 (officially WinNT4/Win9x only):
4174 * Fast: Only the registry is queried to retrieve printer names,
4175 * no connection to the driver is made.
4176 * Returns an array of PRINTER_INFO_5 data structures in the
4177 * lpbPrinters buffer.
4179 * If level set to 3 or 6+:
4180 * returns zero (failure!)
4182 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4186 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4187 * - Only levels 2, 4 and 5 are implemented at the moment.
4188 * - 16-bit printer drivers are not enumerated.
4189 * - Returned amount of bytes used/needed does not match the real Windoze
4190 * implementation (as in this implementation, all strings are part
4191 * of the buffer, whereas Win32 keeps them somewhere else)
4192 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4195 * - In a regular Wine installation, no registry settings for printers
4196 * exist, which makes this function return an empty list.
4198 BOOL WINAPI
EnumPrintersW(
4199 DWORD dwType
, /* [in] Types of print objects to enumerate */
4200 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4201 DWORD dwLevel
, /* [in] type of printer info structure */
4202 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4203 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4204 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4205 LPDWORD lpdwReturned
/* [out] number of entries returned */
4208 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4209 lpdwNeeded
, lpdwReturned
, TRUE
);
4212 /******************************************************************
4213 * EnumPrintersA [WINSPOOL.@]
4216 BOOL WINAPI
EnumPrintersA(DWORD dwType
, LPSTR lpszName
,
4217 DWORD dwLevel
, LPBYTE lpbPrinters
,
4218 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4219 LPDWORD lpdwReturned
)
4221 BOOL ret
, unicode
= FALSE
;
4222 UNICODE_STRING lpszNameW
;
4225 pwstrNameW
= asciitounicode(&lpszNameW
,lpszName
);
4226 if(!cbBuf
) unicode
= TRUE
; /* return a buffer that's big enough for the unicode version */
4227 ret
= WINSPOOL_EnumPrinters(dwType
, pwstrNameW
, dwLevel
, lpbPrinters
, cbBuf
,
4228 lpdwNeeded
, lpdwReturned
, unicode
);
4229 RtlFreeUnicodeString(&lpszNameW
);
4233 /*****************************************************************************
4234 * WINSPOOL_GetDriverInfoFromReg [internal]
4236 * Enters the information from the registry into the DRIVER_INFO struct
4239 * zero if the printer driver does not exist in the registry
4240 * (only if Level > 1) otherwise nonzero
4242 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4245 const printenv_t
* env
,
4247 LPBYTE ptr
, /* DRIVER_INFO */
4248 LPBYTE pDriverStrings
, /* strings buffer */
4249 DWORD cbBuf
, /* size of string buffer */
4250 LPDWORD pcbNeeded
, /* space needed for str. */
4251 BOOL unicode
) /* type of strings */
4255 LPBYTE strPtr
= pDriverStrings
;
4256 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4258 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers
,
4259 debugstr_w(DriverName
), env
,
4260 Level
, di
, pDriverStrings
, cbBuf
, unicode
);
4263 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4264 if (*pcbNeeded
<= cbBuf
)
4265 strcpyW((LPWSTR
)strPtr
, DriverName
);
4269 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0, NULL
, NULL
);
4270 if (*pcbNeeded
<= cbBuf
)
4271 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
4274 /* pName for level 1 has a different offset! */
4276 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4280 /* .cVersion and .pName for level > 1 */
4282 di
->cVersion
= env
->driverversion
;
4283 di
->pName
= (LPWSTR
) strPtr
;
4284 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4287 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4288 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4289 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4295 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4297 size
= WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, NULL
, 0, NULL
, NULL
);
4300 if (*pcbNeeded
<= cbBuf
) {
4302 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4306 WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, (LPSTR
)strPtr
, size
, NULL
, NULL
);
4308 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4309 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4313 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, 0, &size
,
4316 if(*pcbNeeded
<= cbBuf
)
4317 WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, size
, &tmp
,
4320 ((PDRIVER_INFO_2W
) ptr
)->pDriverPath
= (LPWSTR
)strPtr
;
4321 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4324 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, 0, &size
,
4327 if(*pcbNeeded
<= cbBuf
)
4328 WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, size
,
4331 ((PDRIVER_INFO_2W
) ptr
)->pDataFile
= (LPWSTR
)strPtr
;
4332 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4335 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
4336 0, &size
, unicode
)) {
4338 if(*pcbNeeded
<= cbBuf
)
4339 WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
4340 size
, &tmp
, unicode
);
4342 ((PDRIVER_INFO_2W
) ptr
)->pConfigFile
= (LPWSTR
)strPtr
;
4343 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4347 RegCloseKey(hkeyDriver
);
4348 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4352 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
, 0, &size
,
4355 if(*pcbNeeded
<= cbBuf
)
4356 WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
,
4357 size
, &tmp
, unicode
);
4359 ((PDRIVER_INFO_3W
) ptr
)->pHelpFile
= (LPWSTR
)strPtr
;
4360 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4363 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
, 0,
4366 if(*pcbNeeded
<= cbBuf
)
4367 WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
,
4368 size
, &tmp
, unicode
);
4370 ((PDRIVER_INFO_3W
) ptr
)->pDependentFiles
= (LPWSTR
)strPtr
;
4371 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4374 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
,
4377 if(*pcbNeeded
<= cbBuf
)
4378 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
,
4379 size
, &tmp
, unicode
);
4381 ((PDRIVER_INFO_3W
) ptr
)->pMonitorName
= (LPWSTR
)strPtr
;
4382 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4385 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
,
4388 if(*pcbNeeded
<= cbBuf
)
4389 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
,
4390 size
, &tmp
, unicode
);
4392 ((PDRIVER_INFO_3W
) ptr
)->pDefaultDataType
= (LPWSTR
)strPtr
;
4393 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4396 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4397 RegCloseKey(hkeyDriver
);
4401 /*****************************************************************************
4402 * WINSPOOL_GetPrinterDriver
4404 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPCWSTR pEnvironment
,
4405 DWORD Level
, LPBYTE pDriverInfo
,
4406 DWORD cbBuf
, LPDWORD pcbNeeded
,
4410 WCHAR DriverName
[100];
4411 DWORD ret
, type
, size
, needed
= 0;
4413 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4414 const printenv_t
* env
;
4416 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4417 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4419 ZeroMemory(pDriverInfo
, cbBuf
);
4421 if (!(name
= get_opened_printer_name(hPrinter
))) {
4422 SetLastError(ERROR_INVALID_HANDLE
);
4426 if(Level
< 1 || Level
> 6) {
4427 SetLastError(ERROR_INVALID_LEVEL
);
4431 env
= validate_envW(pEnvironment
);
4432 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4434 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4436 ERR("Can't create Printers key\n");
4439 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4441 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4442 RegCloseKey(hkeyPrinters
);
4443 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4446 size
= sizeof(DriverName
);
4448 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4449 (LPBYTE
)DriverName
, &size
);
4450 RegCloseKey(hkeyPrinter
);
4451 RegCloseKey(hkeyPrinters
);
4452 if(ret
!= ERROR_SUCCESS
) {
4453 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4457 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
4459 ERR("Can't create Drivers key\n");
4465 size
= sizeof(DRIVER_INFO_1W
);
4468 size
= sizeof(DRIVER_INFO_2W
);
4471 size
= sizeof(DRIVER_INFO_3W
);
4474 size
= sizeof(DRIVER_INFO_4W
);
4477 size
= sizeof(DRIVER_INFO_5W
);
4480 size
= sizeof(DRIVER_INFO_6W
);
4483 ERR("Invalid level\n");
4488 ptr
= pDriverInfo
+ size
;
4490 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4491 env
, Level
, pDriverInfo
,
4492 (cbBuf
< size
) ? NULL
: ptr
,
4493 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4494 &needed
, unicode
)) {
4495 RegCloseKey(hkeyDrivers
);
4499 RegCloseKey(hkeyDrivers
);
4501 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4502 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4503 if(cbBuf
>= needed
) return TRUE
;
4504 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4508 /*****************************************************************************
4509 * GetPrinterDriverA [WINSPOOL.@]
4511 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4512 DWORD Level
, LPBYTE pDriverInfo
,
4513 DWORD cbBuf
, LPDWORD pcbNeeded
)
4516 UNICODE_STRING pEnvW
;
4519 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4520 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
4521 cbBuf
, pcbNeeded
, FALSE
);
4522 RtlFreeUnicodeString(&pEnvW
);
4525 /*****************************************************************************
4526 * GetPrinterDriverW [WINSPOOL.@]
4528 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4529 DWORD Level
, LPBYTE pDriverInfo
,
4530 DWORD cbBuf
, LPDWORD pcbNeeded
)
4532 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
4533 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
4536 /*****************************************************************************
4537 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4539 * Return the PATH for the Printer-Drivers (UNICODE)
4542 * pName [I] Servername (NT only) or NULL (local Computer)
4543 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4544 * Level [I] Structure-Level (must be 1)
4545 * pDriverDirectory [O] PTR to Buffer that receives the Result
4546 * cbBuf [I] Size of Buffer at pDriverDirectory
4547 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4548 * required for pDriverDirectory
4551 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4552 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4553 * if cbBuf is too small
4555 * Native Values returned in pDriverDirectory on Success:
4556 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4557 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4558 *| win9x(Windows 4.0): "%winsysdir%"
4560 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4563 *- Only NULL or "" is supported for pName
4566 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4567 DWORD Level
, LPBYTE pDriverDirectory
,
4568 DWORD cbBuf
, LPDWORD pcbNeeded
)
4571 const printenv_t
* env
;
4573 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4574 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4575 if(pName
!= NULL
&& pName
[0]) {
4576 FIXME("pName unsupported: %s\n", debugstr_w(pName
));
4577 SetLastError(ERROR_INVALID_PARAMETER
);
4581 env
= validate_envW(pEnvironment
);
4582 if(!env
) return FALSE
; /* pEnvironment invalid or unsupported */
4585 WARN("(Level: %d) is ignored in win9x\n", Level
);
4586 SetLastError(ERROR_INVALID_LEVEL
);
4590 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4591 needed
= GetSystemDirectoryW(NULL
, 0);
4592 /* add the Size for the Subdirectories */
4593 needed
+= lstrlenW(spooldriversW
);
4594 needed
+= lstrlenW(env
->subdir
);
4595 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
4598 *pcbNeeded
= needed
;
4599 TRACE("required: 0x%x/%d\n", needed
, needed
);
4600 if(needed
> cbBuf
) {
4601 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4604 if(pcbNeeded
== NULL
) {
4605 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4606 SetLastError(RPC_X_NULL_REF_POINTER
);
4609 if(pDriverDirectory
== NULL
) {
4610 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4611 SetLastError(ERROR_INVALID_USER_BUFFER
);
4615 GetSystemDirectoryW((LPWSTR
) pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
4616 /* add the Subdirectories */
4617 lstrcatW((LPWSTR
) pDriverDirectory
, spooldriversW
);
4618 lstrcatW((LPWSTR
) pDriverDirectory
, env
->subdir
);
4619 TRACE(" => %s\n", debugstr_w((LPWSTR
) pDriverDirectory
));
4624 /*****************************************************************************
4625 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4627 * Return the PATH for the Printer-Drivers (ANSI)
4629 * See GetPrinterDriverDirectoryW.
4632 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4635 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4636 DWORD Level
, LPBYTE pDriverDirectory
,
4637 DWORD cbBuf
, LPDWORD pcbNeeded
)
4639 UNICODE_STRING nameW
, environmentW
;
4642 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4643 WCHAR
*driverDirectoryW
= NULL
;
4645 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4646 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4648 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4650 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4651 else nameW
.Buffer
= NULL
;
4652 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4653 else environmentW
.Buffer
= NULL
;
4655 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4656 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4659 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4660 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4662 *pcbNeeded
= needed
;
4663 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4665 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4667 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4669 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4670 RtlFreeUnicodeString(&environmentW
);
4671 RtlFreeUnicodeString(&nameW
);
4676 /*****************************************************************************
4677 * AddPrinterDriverA [WINSPOOL.@]
4679 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4682 HKEY hkeyDrivers
, hkeyName
;
4683 static CHAR empty
[] = "",
4686 TRACE("(%s,%d,%p)\n",debugstr_a(pName
),level
,pDriverInfo
);
4688 if(level
!= 2 && level
!= 3) {
4689 SetLastError(ERROR_INVALID_LEVEL
);
4692 if ((pName
) && (pName
[0])) {
4693 FIXME("pName= %s - unsupported\n", debugstr_a(pName
));
4694 SetLastError(ERROR_INVALID_PARAMETER
);
4698 WARN("pDriverInfo == NULL\n");
4699 SetLastError(ERROR_INVALID_PARAMETER
);
4704 di3
= *(DRIVER_INFO_3A
*)pDriverInfo
;
4706 memset(&di3
, 0, sizeof(di3
));
4707 memcpy(&di3
, pDriverInfo
, sizeof(DRIVER_INFO_2A
));
4710 if(!di3
.pName
|| !di3
.pDriverPath
|| !di3
.pConfigFile
||
4712 SetLastError(ERROR_INVALID_PARAMETER
);
4716 if(!di3
.pDefaultDataType
) di3
.pDefaultDataType
= empty
;
4717 if(!di3
.pDependentFiles
) di3
.pDependentFiles
= nullnull
;
4718 if(!di3
.pHelpFile
) di3
.pHelpFile
= empty
;
4719 if(!di3
.pMonitorName
) di3
.pMonitorName
= empty
;
4721 hkeyDrivers
= WINSPOOL_OpenDriverReg(di3
.pEnvironment
, FALSE
);
4724 ERR("Can't create Drivers key\n");
4728 if(level
== 2) { /* apparently can't overwrite with level2 */
4729 if(RegOpenKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) == ERROR_SUCCESS
) {
4730 RegCloseKey(hkeyName
);
4731 RegCloseKey(hkeyDrivers
);
4732 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3
.pName
));
4733 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
4737 if(RegCreateKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) != ERROR_SUCCESS
) {
4738 RegCloseKey(hkeyDrivers
);
4739 ERR("Can't create Name key\n");
4742 RegSetValueExA(hkeyName
, "Configuration File", 0, REG_SZ
, (LPBYTE
) di3
.pConfigFile
,
4743 lstrlenA(di3
.pConfigFile
) + 1);
4744 RegSetValueExA(hkeyName
, "Data File", 0, REG_SZ
, (LPBYTE
) di3
.pDataFile
, lstrlenA(di3
.pDataFile
) + 1);
4745 RegSetValueExA(hkeyName
, "Driver", 0, REG_SZ
, (LPBYTE
) di3
.pDriverPath
, lstrlenA(di3
.pDriverPath
) + 1);
4746 RegSetValueExA(hkeyName
, "Version", 0, REG_DWORD
, (LPBYTE
) &di3
.cVersion
,
4748 RegSetValueExA(hkeyName
, "Datatype", 0, REG_SZ
, (LPBYTE
) di3
.pDefaultDataType
, lstrlenA(di3
.pDefaultDataType
));
4749 RegSetValueExA(hkeyName
, "Dependent Files", 0, REG_MULTI_SZ
,
4750 (LPBYTE
) di3
.pDependentFiles
, multi_sz_lenA(di3
.pDependentFiles
));
4751 RegSetValueExA(hkeyName
, "Help File", 0, REG_SZ
, (LPBYTE
) di3
.pHelpFile
, lstrlenA(di3
.pHelpFile
) + 1);
4752 RegSetValueExA(hkeyName
, "Monitor", 0, REG_SZ
, (LPBYTE
) di3
.pMonitorName
, lstrlenA(di3
.pMonitorName
) + 1);
4753 RegCloseKey(hkeyName
);
4754 RegCloseKey(hkeyDrivers
);
4759 /*****************************************************************************
4760 * AddPrinterDriverW [WINSPOOL.@]
4762 BOOL WINAPI
AddPrinterDriverW(LPWSTR printerName
,DWORD level
,
4765 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName
),
4770 /*****************************************************************************
4771 * AddPrintProcessorA [WINSPOOL.@]
4773 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4774 LPSTR pPrintProcessorName
)
4776 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4777 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4781 /*****************************************************************************
4782 * AddPrintProcessorW [WINSPOOL.@]
4784 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4785 LPWSTR pPrintProcessorName
)
4787 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4788 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4792 /*****************************************************************************
4793 * AddPrintProvidorA [WINSPOOL.@]
4795 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4797 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4801 /*****************************************************************************
4802 * AddPrintProvidorW [WINSPOOL.@]
4804 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4806 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4810 /*****************************************************************************
4811 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4813 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4814 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4816 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4817 pDevModeOutput
, pDevModeInput
);
4821 /*****************************************************************************
4822 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4824 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4825 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4827 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4828 pDevModeOutput
, pDevModeInput
);
4832 /*****************************************************************************
4833 * PrinterProperties [WINSPOOL.@]
4835 * Displays a dialog to set the properties of the printer.
4838 * nonzero on success or zero on failure
4841 * implemented as stub only
4843 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4844 HANDLE hPrinter
/* [in] handle to printer object */
4846 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4847 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4851 /*****************************************************************************
4852 * EnumJobsA [WINSPOOL.@]
4855 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4856 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4859 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4860 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4862 if(pcbNeeded
) *pcbNeeded
= 0;
4863 if(pcReturned
) *pcReturned
= 0;
4868 /*****************************************************************************
4869 * EnumJobsW [WINSPOOL.@]
4872 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4873 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4876 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4877 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4879 if(pcbNeeded
) *pcbNeeded
= 0;
4880 if(pcReturned
) *pcReturned
= 0;
4884 /*****************************************************************************
4885 * WINSPOOL_EnumPrinterDrivers [internal]
4887 * Delivers information about all printer drivers installed on the
4888 * localhost or a given server
4891 * nonzero on success or zero on failure. If the buffer for the returned
4892 * information is too small the function will return an error
4895 * - only implemented for localhost, foreign hosts will return an error
4897 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
4898 DWORD Level
, LPBYTE pDriverInfo
,
4899 DWORD cbBuf
, LPDWORD pcbNeeded
,
4900 LPDWORD pcReturned
, BOOL unicode
)
4903 DWORD i
, needed
, number
= 0, size
= 0;
4904 WCHAR DriverNameW
[255];
4906 const printenv_t
* env
;
4908 TRACE("%s,%s,%d,%p,%d,%d\n",
4909 debugstr_w(pName
), debugstr_w(pEnvironment
),
4910 Level
, pDriverInfo
, cbBuf
, unicode
);
4912 /* check for local drivers */
4913 if((pName
) && (pName
[0])) {
4914 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
4915 SetLastError(ERROR_ACCESS_DENIED
);
4919 env
= validate_envW(pEnvironment
);
4920 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4922 /* check input parameter */
4923 if((Level
< 1) || (Level
> 3)) {
4924 ERR("unsupported level %d\n", Level
);
4925 SetLastError(ERROR_INVALID_LEVEL
);
4929 /* initialize return values */
4931 memset( pDriverInfo
, 0, cbBuf
);
4935 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
4937 ERR("Can't open Drivers key\n");
4941 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4942 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4943 RegCloseKey(hkeyDrivers
);
4944 ERR("Can't query Drivers key\n");
4947 TRACE("Found %d Drivers\n", number
);
4949 /* get size of single struct
4950 * unicode and ascii structure have the same size
4954 size
= sizeof(DRIVER_INFO_1A
);
4957 size
= sizeof(DRIVER_INFO_2A
);
4960 size
= sizeof(DRIVER_INFO_3A
);
4964 /* calculate required buffer size */
4965 *pcbNeeded
= size
* number
;
4967 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
4969 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
4970 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
))
4972 ERR("Can't enum key number %d\n", i
);
4973 RegCloseKey(hkeyDrivers
);
4976 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
4978 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
4979 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
4980 &needed
, unicode
)) {
4981 RegCloseKey(hkeyDrivers
);
4984 (*pcbNeeded
) += needed
;
4987 RegCloseKey(hkeyDrivers
);
4989 if(cbBuf
< *pcbNeeded
){
4990 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4994 *pcReturned
= number
;
4998 /*****************************************************************************
4999 * EnumPrinterDriversW [WINSPOOL.@]
5001 * see function EnumPrinterDrivers for RETURNS, BUGS
5003 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5004 LPBYTE pDriverInfo
, DWORD cbBuf
,
5005 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5007 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5008 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
5011 /*****************************************************************************
5012 * EnumPrinterDriversA [WINSPOOL.@]
5014 * see function EnumPrinterDrivers for RETURNS, BUGS
5016 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5017 LPBYTE pDriverInfo
, DWORD cbBuf
,
5018 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5020 UNICODE_STRING pNameW
, pEnvironmentW
;
5021 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5023 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5024 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5026 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
5027 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
5029 RtlFreeUnicodeString(&pNameW
);
5030 RtlFreeUnicodeString(&pEnvironmentW
);
5035 /******************************************************************************
5036 * EnumPortsA (WINSPOOL.@)
5041 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5042 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5045 LPBYTE bufferW
= NULL
;
5046 LPWSTR nameW
= NULL
;
5048 DWORD numentries
= 0;
5051 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5052 cbBuf
, pcbNeeded
, pcReturned
);
5054 /* convert servername to unicode */
5056 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5057 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5058 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5060 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5061 needed
= cbBuf
* sizeof(WCHAR
);
5062 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5063 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5065 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5066 if (pcbNeeded
) needed
= *pcbNeeded
;
5067 /* HeapReAlloc return NULL, when bufferW was NULL */
5068 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5069 HeapAlloc(GetProcessHeap(), 0, needed
);
5071 /* Try again with the large Buffer */
5072 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5074 needed
= pcbNeeded
? *pcbNeeded
: 0;
5075 numentries
= pcReturned
? *pcReturned
: 0;
5078 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5079 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5082 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5083 DWORD entrysize
= 0;
5086 LPPORT_INFO_2W pi2w
;
5087 LPPORT_INFO_2A pi2a
;
5090 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5092 /* First pass: calculate the size for all Entries */
5093 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5094 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5096 while (index
< numentries
) {
5098 needed
+= entrysize
; /* PORT_INFO_?A */
5099 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5101 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5102 NULL
, 0, NULL
, NULL
);
5104 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5105 NULL
, 0, NULL
, NULL
);
5106 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5107 NULL
, 0, NULL
, NULL
);
5109 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5110 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5111 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5114 /* check for errors and quit on failure */
5115 if (cbBuf
< needed
) {
5116 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5120 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5121 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5122 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5123 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5124 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5126 /* Second Pass: Fill the User Buffer (if we have one) */
5127 while ((index
< numentries
) && pPorts
) {
5129 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5130 pi2a
->pPortName
= ptr
;
5131 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5132 ptr
, cbBuf
, NULL
, NULL
);
5136 pi2a
->pMonitorName
= ptr
;
5137 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5138 ptr
, cbBuf
, NULL
, NULL
);
5142 pi2a
->pDescription
= ptr
;
5143 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5144 ptr
, cbBuf
, NULL
, NULL
);
5148 pi2a
->fPortType
= pi2w
->fPortType
;
5149 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5152 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5153 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5154 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5159 if (pcbNeeded
) *pcbNeeded
= needed
;
5160 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5162 HeapFree(GetProcessHeap(), 0, nameW
);
5163 HeapFree(GetProcessHeap(), 0, bufferW
);
5165 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5166 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5172 /******************************************************************************
5173 * EnumPortsW (WINSPOOL.@)
5175 * Enumerate available Ports
5178 * name [I] Servername or NULL (local Computer)
5179 * level [I] Structure-Level (1 or 2)
5180 * buffer [O] PTR to Buffer that receives the Result
5181 * bufsize [I] Size of Buffer at buffer
5182 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5183 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5187 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5191 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5194 DWORD numentries
= 0;
5197 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5198 cbBuf
, pcbNeeded
, pcReturned
);
5200 if (pName
&& (pName
[0])) {
5201 FIXME("not implemented for Server %s\n", debugstr_w(pName
));
5202 SetLastError(ERROR_ACCESS_DENIED
);
5206 /* Level is not checked in win9x */
5207 if (!Level
|| (Level
> 2)) {
5208 WARN("level (%d) is ignored in win9x\n", Level
);
5209 SetLastError(ERROR_INVALID_LEVEL
);
5213 SetLastError(RPC_X_NULL_REF_POINTER
);
5217 EnterCriticalSection(&monitor_handles_cs
);
5220 /* Scan all local Ports */
5222 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
5224 /* we calculated the needed buffersize. now do the error-checks */
5225 if (cbBuf
< needed
) {
5226 monitor_unloadall();
5227 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5228 goto emP_cleanup_cs
;
5230 else if (!pPorts
|| !pcReturned
) {
5231 monitor_unloadall();
5232 SetLastError(RPC_X_NULL_REF_POINTER
);
5233 goto emP_cleanup_cs
;
5236 /* Fill the Buffer */
5237 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
5239 monitor_unloadall();
5242 LeaveCriticalSection(&monitor_handles_cs
);
5245 if (pcbNeeded
) *pcbNeeded
= needed
;
5246 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5248 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5249 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5254 /******************************************************************************
5255 * GetDefaultPrinterW (WINSPOOL.@)
5258 * This function must read the value from data 'device' of key
5259 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5261 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5265 WCHAR
*buffer
, *ptr
;
5269 SetLastError(ERROR_INVALID_PARAMETER
);
5273 /* make the buffer big enough for the stuff from the profile/registry,
5274 * the content must fit into the local buffer to compute the correct
5275 * size even if the extern buffer is too small or not given.
5276 * (20 for ,driver,port) */
5278 len
= max(100, (insize
+ 20));
5279 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5281 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5283 SetLastError (ERROR_FILE_NOT_FOUND
);
5287 TRACE("%s\n", debugstr_w(buffer
));
5289 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5291 SetLastError(ERROR_INVALID_NAME
);
5297 *namesize
= strlenW(buffer
) + 1;
5298 if(!name
|| (*namesize
> insize
))
5300 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5304 strcpyW(name
, buffer
);
5307 HeapFree( GetProcessHeap(), 0, buffer
);
5312 /******************************************************************************
5313 * GetDefaultPrinterA (WINSPOOL.@)
5315 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5319 WCHAR
*bufferW
= NULL
;
5323 SetLastError(ERROR_INVALID_PARAMETER
);
5327 if(name
&& *namesize
) {
5329 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5332 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5337 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5341 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5344 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5347 HeapFree( GetProcessHeap(), 0, bufferW
);
5352 /******************************************************************************
5353 * SetDefaultPrinterW (WINSPOOL.204)
5355 * Set the Name of the Default Printer
5358 * pszPrinter [I] Name of the Printer or NULL
5365 * When the Parameter is NULL or points to an Empty String and
5366 * a Default Printer was already present, then this Function changes nothing.
5367 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5368 * the First enumerated local Printer is used.
5371 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5374 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5376 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5380 /******************************************************************************
5381 * SetDefaultPrinterA (WINSPOOL.202)
5383 * See SetDefaultPrinterW.
5386 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5389 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5391 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5396 /******************************************************************************
5397 * SetPrinterDataExA (WINSPOOL.@)
5399 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5400 LPCSTR pValueName
, DWORD Type
,
5401 LPBYTE pData
, DWORD cbData
)
5403 HKEY hkeyPrinter
, hkeySubkey
;
5406 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5407 debugstr_a(pValueName
), Type
, pData
, cbData
);
5409 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5413 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5415 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5416 RegCloseKey(hkeyPrinter
);
5419 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5420 RegCloseKey(hkeySubkey
);
5421 RegCloseKey(hkeyPrinter
);
5425 /******************************************************************************
5426 * SetPrinterDataExW (WINSPOOL.@)
5428 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5429 LPCWSTR pValueName
, DWORD Type
,
5430 LPBYTE pData
, DWORD cbData
)
5432 HKEY hkeyPrinter
, hkeySubkey
;
5435 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5436 debugstr_w(pValueName
), Type
, pData
, cbData
);
5438 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5442 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5444 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5445 RegCloseKey(hkeyPrinter
);
5448 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5449 RegCloseKey(hkeySubkey
);
5450 RegCloseKey(hkeyPrinter
);
5454 /******************************************************************************
5455 * SetPrinterDataA (WINSPOOL.@)
5457 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5458 LPBYTE pData
, DWORD cbData
)
5460 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5464 /******************************************************************************
5465 * SetPrinterDataW (WINSPOOL.@)
5467 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5468 LPBYTE pData
, DWORD cbData
)
5470 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5474 /******************************************************************************
5475 * GetPrinterDataExA (WINSPOOL.@)
5477 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5478 LPCSTR pValueName
, LPDWORD pType
,
5479 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5481 HKEY hkeyPrinter
, hkeySubkey
;
5484 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5485 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
5488 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5492 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5494 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
5495 RegCloseKey(hkeyPrinter
);
5499 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5500 RegCloseKey(hkeySubkey
);
5501 RegCloseKey(hkeyPrinter
);
5505 /******************************************************************************
5506 * GetPrinterDataExW (WINSPOOL.@)
5508 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5509 LPCWSTR pValueName
, LPDWORD pType
,
5510 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5512 HKEY hkeyPrinter
, hkeySubkey
;
5515 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5516 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
5519 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5523 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5525 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
5526 RegCloseKey(hkeyPrinter
);
5530 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5531 RegCloseKey(hkeySubkey
);
5532 RegCloseKey(hkeyPrinter
);
5536 /******************************************************************************
5537 * GetPrinterDataA (WINSPOOL.@)
5539 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5540 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5542 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5543 pData
, nSize
, pcbNeeded
);
5546 /******************************************************************************
5547 * GetPrinterDataW (WINSPOOL.@)
5549 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5550 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5552 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5553 pData
, nSize
, pcbNeeded
);
5556 /*******************************************************************************
5557 * EnumPrinterDataExW [WINSPOOL.@]
5559 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5560 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5561 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5563 HKEY hkPrinter
, hkSubKey
;
5564 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5565 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5570 PPRINTER_ENUM_VALUESW ppev
;
5572 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5574 if (pKeyName
== NULL
|| *pKeyName
== 0)
5575 return ERROR_INVALID_PARAMETER
;
5577 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5578 if (ret
!= ERROR_SUCCESS
)
5580 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5585 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5586 if (ret
!= ERROR_SUCCESS
)
5588 r
= RegCloseKey (hkPrinter
);
5589 if (r
!= ERROR_SUCCESS
)
5590 WARN ("RegCloseKey returned %i\n", r
);
5591 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5592 debugstr_w (pKeyName
), ret
);
5596 ret
= RegCloseKey (hkPrinter
);
5597 if (ret
!= ERROR_SUCCESS
)
5599 ERR ("RegCloseKey returned %i\n", ret
);
5600 r
= RegCloseKey (hkSubKey
);
5601 if (r
!= ERROR_SUCCESS
)
5602 WARN ("RegCloseKey returned %i\n", r
);
5606 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5607 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5608 if (ret
!= ERROR_SUCCESS
)
5610 r
= RegCloseKey (hkSubKey
);
5611 if (r
!= ERROR_SUCCESS
)
5612 WARN ("RegCloseKey returned %i\n", r
);
5613 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5617 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5618 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5620 if (cValues
== 0) /* empty key */
5622 r
= RegCloseKey (hkSubKey
);
5623 if (r
!= ERROR_SUCCESS
)
5624 WARN ("RegCloseKey returned %i\n", r
);
5625 *pcbEnumValues
= *pnEnumValues
= 0;
5626 return ERROR_SUCCESS
;
5629 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5631 hHeap
= GetProcessHeap ();
5634 ERR ("GetProcessHeap failed\n");
5635 r
= RegCloseKey (hkSubKey
);
5636 if (r
!= ERROR_SUCCESS
)
5637 WARN ("RegCloseKey returned %i\n", r
);
5638 return ERROR_OUTOFMEMORY
;
5641 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5642 if (lpValueName
== NULL
)
5644 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5645 r
= RegCloseKey (hkSubKey
);
5646 if (r
!= ERROR_SUCCESS
)
5647 WARN ("RegCloseKey returned %i\n", r
);
5648 return ERROR_OUTOFMEMORY
;
5651 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5652 if (lpValue
== NULL
)
5654 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5655 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5656 WARN ("HeapFree failed with code %i\n", GetLastError ());
5657 r
= RegCloseKey (hkSubKey
);
5658 if (r
!= ERROR_SUCCESS
)
5659 WARN ("RegCloseKey returned %i\n", r
);
5660 return ERROR_OUTOFMEMORY
;
5663 TRACE ("pass 1: calculating buffer required for all names and values\n");
5665 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5667 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5669 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5671 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5672 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5673 NULL
, NULL
, lpValue
, &cbValueLen
);
5674 if (ret
!= ERROR_SUCCESS
)
5676 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5677 WARN ("HeapFree failed with code %i\n", GetLastError ());
5678 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5679 WARN ("HeapFree failed with code %i\n", GetLastError ());
5680 r
= RegCloseKey (hkSubKey
);
5681 if (r
!= ERROR_SUCCESS
)
5682 WARN ("RegCloseKey returned %i\n", r
);
5683 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5687 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5688 debugstr_w (lpValueName
), dwIndex
,
5689 cbValueNameLen
+ 1, cbValueLen
);
5691 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5692 cbBufSize
+= cbValueLen
;
5695 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5697 *pcbEnumValues
= cbBufSize
;
5698 *pnEnumValues
= cValues
;
5700 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5702 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5703 WARN ("HeapFree failed with code %i\n", GetLastError ());
5704 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5705 WARN ("HeapFree failed with code %i\n", GetLastError ());
5706 r
= RegCloseKey (hkSubKey
);
5707 if (r
!= ERROR_SUCCESS
)
5708 WARN ("RegCloseKey returned %i\n", r
);
5709 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5710 return ERROR_MORE_DATA
;
5713 TRACE ("pass 2: copying all names and values to buffer\n");
5715 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5716 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5718 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5720 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5721 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5722 NULL
, &dwType
, lpValue
, &cbValueLen
);
5723 if (ret
!= ERROR_SUCCESS
)
5725 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5726 WARN ("HeapFree failed with code %i\n", GetLastError ());
5727 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5728 WARN ("HeapFree failed with code %i\n", GetLastError ());
5729 r
= RegCloseKey (hkSubKey
);
5730 if (r
!= ERROR_SUCCESS
)
5731 WARN ("RegCloseKey returned %i\n", r
);
5732 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5736 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5737 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5738 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5739 pEnumValues
+= cbValueNameLen
;
5741 /* return # of *bytes* (including trailing \0), not # of chars */
5742 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5744 ppev
[dwIndex
].dwType
= dwType
;
5746 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5747 ppev
[dwIndex
].pData
= pEnumValues
;
5748 pEnumValues
+= cbValueLen
;
5750 ppev
[dwIndex
].cbData
= cbValueLen
;
5752 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5753 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5756 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5758 ret
= GetLastError ();
5759 ERR ("HeapFree failed with code %i\n", ret
);
5760 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5761 WARN ("HeapFree failed with code %i\n", GetLastError ());
5762 r
= RegCloseKey (hkSubKey
);
5763 if (r
!= ERROR_SUCCESS
)
5764 WARN ("RegCloseKey returned %i\n", r
);
5768 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5770 ret
= GetLastError ();
5771 ERR ("HeapFree failed with code %i\n", ret
);
5772 r
= RegCloseKey (hkSubKey
);
5773 if (r
!= ERROR_SUCCESS
)
5774 WARN ("RegCloseKey returned %i\n", r
);
5778 ret
= RegCloseKey (hkSubKey
);
5779 if (ret
!= ERROR_SUCCESS
)
5781 ERR ("RegCloseKey returned %i\n", ret
);
5785 return ERROR_SUCCESS
;
5788 /*******************************************************************************
5789 * EnumPrinterDataExA [WINSPOOL.@]
5791 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5792 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5793 * what Windows 2000 SP1 does.
5796 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5797 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5798 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5802 DWORD ret
, dwIndex
, dwBufSize
;
5806 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5808 if (pKeyName
== NULL
|| *pKeyName
== 0)
5809 return ERROR_INVALID_PARAMETER
;
5811 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5814 ret
= GetLastError ();
5815 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5819 hHeap
= GetProcessHeap ();
5822 ERR ("GetProcessHeap failed\n");
5823 return ERROR_OUTOFMEMORY
;
5826 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5827 if (pKeyNameW
== NULL
)
5829 ERR ("Failed to allocate %i bytes from process heap\n",
5830 (LONG
)(len
* sizeof (WCHAR
)));
5831 return ERROR_OUTOFMEMORY
;
5834 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
5836 ret
= GetLastError ();
5837 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5838 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5839 WARN ("HeapFree failed with code %i\n", GetLastError ());
5843 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
5844 pcbEnumValues
, pnEnumValues
);
5845 if (ret
!= ERROR_SUCCESS
)
5847 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5848 WARN ("HeapFree failed with code %i\n", GetLastError ());
5849 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
5853 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5855 ret
= GetLastError ();
5856 ERR ("HeapFree failed with code %i\n", ret
);
5860 if (*pnEnumValues
== 0) /* empty key */
5861 return ERROR_SUCCESS
;
5864 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5866 PPRINTER_ENUM_VALUESW ppev
=
5867 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5869 if (dwBufSize
< ppev
->cbValueName
)
5870 dwBufSize
= ppev
->cbValueName
;
5872 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
5873 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
5874 dwBufSize
= ppev
->cbData
;
5877 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
5879 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
5880 if (pBuffer
== NULL
)
5882 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
5883 return ERROR_OUTOFMEMORY
;
5886 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5888 PPRINTER_ENUM_VALUESW ppev
=
5889 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5891 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
5892 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
5896 ret
= GetLastError ();
5897 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5898 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5899 WARN ("HeapFree failed with code %i\n", GetLastError ());
5903 memcpy (ppev
->pValueName
, pBuffer
, len
);
5905 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5907 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
5908 ppev
->dwType
!= REG_MULTI_SZ
)
5911 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
5912 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
5915 ret
= GetLastError ();
5916 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5917 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5918 WARN ("HeapFree failed with code %i\n", GetLastError ());
5922 memcpy (ppev
->pData
, pBuffer
, len
);
5924 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5925 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5928 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5930 ret
= GetLastError ();
5931 ERR ("HeapFree failed with code %i\n", ret
);
5935 return ERROR_SUCCESS
;
5938 /******************************************************************************
5939 * AbortPrinter (WINSPOOL.@)
5941 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
5943 FIXME("(%p), stub!\n", hPrinter
);
5947 /******************************************************************************
5948 * AddPortA (WINSPOOL.@)
5953 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
5955 LPWSTR nameW
= NULL
;
5956 LPWSTR monitorW
= NULL
;
5960 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
5963 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5964 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5965 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5969 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
5970 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5971 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
5973 res
= AddPortW(nameW
, hWnd
, monitorW
);
5974 HeapFree(GetProcessHeap(), 0, nameW
);
5975 HeapFree(GetProcessHeap(), 0, monitorW
);
5979 /******************************************************************************
5980 * AddPortW (WINSPOOL.@)
5982 * Add a Port for a specific Monitor
5985 * pName [I] Servername or NULL (local Computer)
5986 * hWnd [I] Handle to parent Window for the Dialog-Box
5987 * pMonitorName [I] Name of the Monitor that manage the Port
5994 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6000 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6002 if (pName
&& pName
[0]) {
6003 SetLastError(ERROR_INVALID_PARAMETER
);
6007 if (!pMonitorName
) {
6008 SetLastError(RPC_X_NULL_REF_POINTER
);
6012 /* an empty Monitorname is Invalid */
6013 if (!pMonitorName
[0]) {
6014 SetLastError(ERROR_NOT_SUPPORTED
);
6018 pm
= monitor_load(pMonitorName
, NULL
);
6019 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
6020 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
6021 TRACE("got %d with %u\n", res
, GetLastError());
6026 pui
= monitor_loadui(pm
);
6027 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
6028 TRACE("use %p: %s\n", pui
, debugstr_w(pui
->dllname
));
6029 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
6030 TRACE("got %d with %u\n", res
, GetLastError());
6035 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName
),
6036 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6038 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6039 SetLastError(ERROR_NOT_SUPPORTED
);
6042 monitor_unload(pui
);
6045 TRACE("returning %d with %u\n", res
, GetLastError());
6049 /******************************************************************************
6050 * AddPortExA (WINSPOOL.@)
6055 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6058 PORT_INFO_2A
* pi2A
;
6059 LPWSTR nameW
= NULL
;
6060 LPWSTR monitorW
= NULL
;
6064 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6066 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6067 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6069 if ((level
< 1) || (level
> 2)) {
6070 SetLastError(ERROR_INVALID_LEVEL
);
6075 SetLastError(ERROR_INVALID_PARAMETER
);
6080 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6081 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6082 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6086 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6087 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6088 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6091 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6093 if (pi2A
->pPortName
) {
6094 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6095 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6096 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6100 if (pi2A
->pMonitorName
) {
6101 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6102 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6103 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6106 if (pi2A
->pDescription
) {
6107 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6108 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6109 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6111 pi2W
.fPortType
= pi2A
->fPortType
;
6112 pi2W
.Reserved
= pi2A
->Reserved
;
6115 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6117 HeapFree(GetProcessHeap(), 0, nameW
);
6118 HeapFree(GetProcessHeap(), 0, monitorW
);
6119 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6120 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6121 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6126 /******************************************************************************
6127 * AddPortExW (WINSPOOL.@)
6129 * Add a Port for a specific Monitor, without presenting a user interface
6132 * pName [I] Servername or NULL (local Computer)
6133 * level [I] Structure-Level (1 or 2) for pBuffer
6134 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6135 * pMonitorName [I] Name of the Monitor that manage the Port
6142 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6148 pi2
= (PORT_INFO_2W
*) pBuffer
;
6150 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6151 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6152 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6153 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6156 if ((level
< 1) || (level
> 2)) {
6157 SetLastError(ERROR_INVALID_LEVEL
);
6161 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6162 SetLastError(ERROR_INVALID_PARAMETER
);
6166 /* load the Monitor */
6167 pm
= monitor_load(pMonitorName
, NULL
);
6169 SetLastError(ERROR_INVALID_PARAMETER
);
6173 if (pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
6174 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6175 TRACE("got %u with %u\n", res
, GetLastError());
6179 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName
), pm
->monitor
);
6185 /******************************************************************************
6186 * AddPrinterConnectionA (WINSPOOL.@)
6188 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6190 FIXME("%s\n", debugstr_a(pName
));
6194 /******************************************************************************
6195 * AddPrinterConnectionW (WINSPOOL.@)
6197 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6199 FIXME("%s\n", debugstr_w(pName
));
6203 /******************************************************************************
6204 * AddPrinterDriverExW (WINSPOOL.@)
6206 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD Level
,
6207 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6209 FIXME("%s %d %p %d\n", debugstr_w(pName
),
6210 Level
, pDriverInfo
, dwFileCopyFlags
);
6211 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
6215 /******************************************************************************
6216 * AddPrinterDriverExA (WINSPOOL.@)
6218 BOOL WINAPI
AddPrinterDriverExA( LPSTR pName
, DWORD Level
,
6219 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6221 FIXME("%s %d %p %d\n", debugstr_a(pName
),
6222 Level
, pDriverInfo
, dwFileCopyFlags
);
6223 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
6227 /******************************************************************************
6228 * ConfigurePortA (WINSPOOL.@)
6230 * See ConfigurePortW.
6233 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6235 LPWSTR nameW
= NULL
;
6236 LPWSTR portW
= NULL
;
6240 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6242 /* convert servername to unicode */
6244 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6245 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6246 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6249 /* convert portname to unicode */
6251 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6252 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6253 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6256 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6257 HeapFree(GetProcessHeap(), 0, nameW
);
6258 HeapFree(GetProcessHeap(), 0, portW
);
6262 /******************************************************************************
6263 * ConfigurePortW (WINSPOOL.@)
6265 * Display the Configuration-Dialog for a specific Port
6268 * pName [I] Servername or NULL (local Computer)
6269 * hWnd [I] Handle to parent Window for the Dialog-Box
6270 * pPortName [I] Name of the Port, that should be configured
6277 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6283 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6285 if (pName
&& pName
[0]) {
6286 SetLastError(ERROR_INVALID_PARAMETER
);
6291 SetLastError(RPC_X_NULL_REF_POINTER
);
6295 /* an empty Portname is Invalid, but can popup a Dialog */
6296 if (!pPortName
[0]) {
6297 SetLastError(ERROR_NOT_SUPPORTED
);
6301 pm
= monitor_load_by_port(pPortName
);
6302 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
6303 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
6304 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
6305 TRACE("got %d with %u\n", res
, GetLastError());
6309 pui
= monitor_loadui(pm
);
6310 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
6311 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
6312 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
6313 TRACE("got %d with %u\n", res
, GetLastError());
6317 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
6318 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6320 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6321 SetLastError(ERROR_NOT_SUPPORTED
);
6324 monitor_unload(pui
);
6328 TRACE("returning %d with %u\n", res
, GetLastError());
6332 /******************************************************************************
6333 * ConnectToPrinterDlg (WINSPOOL.@)
6335 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6337 FIXME("%p %x\n", hWnd
, Flags
);
6341 /******************************************************************************
6342 * DeletePrinterConnectionA (WINSPOOL.@)
6344 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6346 FIXME("%s\n", debugstr_a(pName
));
6350 /******************************************************************************
6351 * DeletePrinterConnectionW (WINSPOOL.@)
6353 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6355 FIXME("%s\n", debugstr_w(pName
));
6359 /******************************************************************************
6360 * DeletePrinterDriverExW (WINSPOOL.@)
6362 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6363 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6368 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6369 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6371 if(pName
&& pName
[0])
6373 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6374 SetLastError(ERROR_INVALID_PARAMETER
);
6380 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6381 SetLastError(ERROR_INVALID_PARAMETER
);
6385 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
6389 ERR("Can't open drivers key\n");
6393 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6396 RegCloseKey(hkey_drivers
);
6401 /******************************************************************************
6402 * DeletePrinterDriverExA (WINSPOOL.@)
6404 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6405 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6407 UNICODE_STRING NameW
, EnvW
, DriverW
;
6410 asciitounicode(&NameW
, pName
);
6411 asciitounicode(&EnvW
, pEnvironment
);
6412 asciitounicode(&DriverW
, pDriverName
);
6414 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6416 RtlFreeUnicodeString(&DriverW
);
6417 RtlFreeUnicodeString(&EnvW
);
6418 RtlFreeUnicodeString(&NameW
);
6423 /******************************************************************************
6424 * DeletePrinterDataExW (WINSPOOL.@)
6426 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6429 FIXME("%p %s %s\n", hPrinter
,
6430 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6431 return ERROR_INVALID_PARAMETER
;
6434 /******************************************************************************
6435 * DeletePrinterDataExA (WINSPOOL.@)
6437 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6440 FIXME("%p %s %s\n", hPrinter
,
6441 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6442 return ERROR_INVALID_PARAMETER
;
6445 /******************************************************************************
6446 * DeletePrintProcessorA (WINSPOOL.@)
6448 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6450 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6451 debugstr_a(pPrintProcessorName
));
6455 /******************************************************************************
6456 * DeletePrintProcessorW (WINSPOOL.@)
6458 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6460 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6461 debugstr_w(pPrintProcessorName
));
6465 /******************************************************************************
6466 * DeletePrintProvidorA (WINSPOOL.@)
6468 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6470 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6471 debugstr_a(pPrintProviderName
));
6475 /******************************************************************************
6476 * DeletePrintProvidorW (WINSPOOL.@)
6478 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6480 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6481 debugstr_w(pPrintProviderName
));
6485 /******************************************************************************
6486 * EnumFormsA (WINSPOOL.@)
6488 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6489 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6491 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6492 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6496 /******************************************************************************
6497 * EnumFormsW (WINSPOOL.@)
6499 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6500 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6502 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6503 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6507 /*****************************************************************************
6508 * EnumMonitorsA [WINSPOOL.@]
6510 * See EnumMonitorsW.
6513 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6514 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6517 LPBYTE bufferW
= NULL
;
6518 LPWSTR nameW
= NULL
;
6520 DWORD numentries
= 0;
6523 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6524 cbBuf
, pcbNeeded
, pcReturned
);
6526 /* convert servername to unicode */
6528 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6529 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6530 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6532 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6533 needed
= cbBuf
* sizeof(WCHAR
);
6534 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6535 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6537 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6538 if (pcbNeeded
) needed
= *pcbNeeded
;
6539 /* HeapReAlloc return NULL, when bufferW was NULL */
6540 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6541 HeapAlloc(GetProcessHeap(), 0, needed
);
6543 /* Try again with the large Buffer */
6544 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6546 numentries
= pcReturned
? *pcReturned
: 0;
6549 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6550 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6553 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6554 DWORD entrysize
= 0;
6557 LPMONITOR_INFO_2W mi2w
;
6558 LPMONITOR_INFO_2A mi2a
;
6560 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6561 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6563 /* First pass: calculate the size for all Entries */
6564 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6565 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6567 while (index
< numentries
) {
6569 needed
+= entrysize
; /* MONITOR_INFO_?A */
6570 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6572 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6573 NULL
, 0, NULL
, NULL
);
6575 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6576 NULL
, 0, NULL
, NULL
);
6577 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6578 NULL
, 0, NULL
, NULL
);
6580 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6581 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6582 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6585 /* check for errors and quit on failure */
6586 if (cbBuf
< needed
) {
6587 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6591 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6592 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6593 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6594 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6595 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6597 /* Second Pass: Fill the User Buffer (if we have one) */
6598 while ((index
< numentries
) && pMonitors
) {
6600 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6602 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6603 ptr
, cbBuf
, NULL
, NULL
);
6607 mi2a
->pEnvironment
= ptr
;
6608 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6609 ptr
, cbBuf
, NULL
, NULL
);
6613 mi2a
->pDLLName
= ptr
;
6614 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6615 ptr
, cbBuf
, NULL
, NULL
);
6619 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6620 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6621 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6625 if (pcbNeeded
) *pcbNeeded
= needed
;
6626 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6628 HeapFree(GetProcessHeap(), 0, nameW
);
6629 HeapFree(GetProcessHeap(), 0, bufferW
);
6631 TRACE("returning %d with %d (%d byte for %d entries)\n",
6632 (res
), GetLastError(), needed
, numentries
);
6638 /*****************************************************************************
6639 * EnumMonitorsW [WINSPOOL.@]
6641 * Enumerate available Port-Monitors
6644 * pName [I] Servername or NULL (local Computer)
6645 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6646 * pMonitors [O] PTR to Buffer that receives the Result
6647 * cbBuf [I] Size of Buffer at pMonitors
6648 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6649 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6653 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6656 * Windows reads the Registry once and cache the Results.
6658 *| Language-Monitors are also installed in the same Registry-Location but
6659 *| they are filtered in Windows (not returned by EnumMonitors).
6660 *| We do no filtering to simplify our Code.
6663 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6664 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6667 DWORD numentries
= 0;
6670 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6671 cbBuf
, pcbNeeded
, pcReturned
);
6673 if (pName
&& (lstrlenW(pName
))) {
6674 FIXME("for Server %s not implemented\n", debugstr_w(pName
));
6675 SetLastError(ERROR_ACCESS_DENIED
);
6679 /* Level is not checked in win9x */
6680 if (!Level
|| (Level
> 2)) {
6681 WARN("level (%d) is ignored in win9x\n", Level
);
6682 SetLastError(ERROR_INVALID_LEVEL
);
6686 SetLastError(RPC_X_NULL_REF_POINTER
);
6690 /* Scan all Monitor-Keys */
6692 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
6694 /* we calculated the needed buffersize. now do the error-checks */
6695 if (cbBuf
< needed
) {
6696 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6699 else if (!pMonitors
|| !pcReturned
) {
6700 SetLastError(RPC_X_NULL_REF_POINTER
);
6704 /* fill the Buffer with the Monitor-Keys */
6705 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
6709 if (pcbNeeded
) *pcbNeeded
= needed
;
6710 if (pcReturned
) *pcReturned
= numentries
;
6712 TRACE("returning %d with %d (%d byte for %d entries)\n",
6713 res
, GetLastError(), needed
, numentries
);
6718 /******************************************************************************
6719 * XcvDataW (WINSPOOL.@)
6721 * Execute commands in the Printmonitor DLL
6724 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6725 * pszDataName [i] Name of the command to execute
6726 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6727 * cbInputData [i] Size in Bytes of Buffer at pInputData
6728 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6729 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6730 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6731 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6738 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6739 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6741 * Minimal List of commands, that a Printmonitor DLL should support:
6743 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6744 *| "AddPort" : Add a Port
6745 *| "DeletePort": Delete a Port
6747 * Many Printmonitors support additional commands. Examples for localspl.dll:
6748 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6749 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6752 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6753 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6754 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6756 opened_printer_t
*printer
;
6758 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6759 pInputData
, cbInputData
, pOutputData
,
6760 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6762 printer
= get_opened_printer(hXcv
);
6763 if (!printer
|| (!printer
->hXcv
)) {
6764 SetLastError(ERROR_INVALID_HANDLE
);
6768 if (!pcbOutputNeeded
) {
6769 SetLastError(ERROR_INVALID_PARAMETER
);
6773 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6774 SetLastError(RPC_X_NULL_REF_POINTER
);
6778 *pcbOutputNeeded
= 0;
6780 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
6781 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
6786 /*****************************************************************************
6787 * EnumPrinterDataA [WINSPOOL.@]
6790 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6791 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6792 DWORD cbData
, LPDWORD pcbData
)
6794 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6795 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6796 return ERROR_NO_MORE_ITEMS
;
6799 /*****************************************************************************
6800 * EnumPrinterDataW [WINSPOOL.@]
6803 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
6804 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6805 DWORD cbData
, LPDWORD pcbData
)
6807 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6808 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6809 return ERROR_NO_MORE_ITEMS
;
6812 /*****************************************************************************
6813 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6816 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
6817 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6818 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6820 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
6821 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6822 pcbNeeded
, pcReturned
);
6826 /*****************************************************************************
6827 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6830 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
6831 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6832 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6834 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6835 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6836 pcbNeeded
, pcReturned
);
6840 /*****************************************************************************
6841 * EnumPrintProcessorsA [WINSPOOL.@]
6844 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
6845 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
6847 FIXME("Stub: %s %s %d %p %d %p %p\n", pName
, pEnvironment
, Level
,
6848 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
6852 /*****************************************************************************
6853 * EnumPrintProcessorsW [WINSPOOL.@]
6856 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
6857 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
6859 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6860 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
6861 cbBuf
, pcbNeeded
, pcbReturned
);
6865 /*****************************************************************************
6866 * ExtDeviceMode [WINSPOOL.@]
6869 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
6870 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
6873 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
6874 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
6875 debugstr_a(pProfile
), fMode
);
6879 /*****************************************************************************
6880 * FindClosePrinterChangeNotification [WINSPOOL.@]
6883 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
6885 FIXME("Stub: %p\n", hChange
);
6889 /*****************************************************************************
6890 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6893 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
6894 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
6896 FIXME("Stub: %p %x %x %p\n",
6897 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
6898 return INVALID_HANDLE_VALUE
;
6901 /*****************************************************************************
6902 * FindNextPrinterChangeNotification [WINSPOOL.@]
6905 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
6906 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
6908 FIXME("Stub: %p %p %p %p\n",
6909 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
6913 /*****************************************************************************
6914 * FreePrinterNotifyInfo [WINSPOOL.@]
6917 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
6919 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
6923 /*****************************************************************************
6926 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6927 * ansi depending on the unicode parameter.
6929 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
6939 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
6942 memcpy(ptr
, str
, *size
);
6949 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
6952 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
6959 /*****************************************************************************
6962 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
6963 LPDWORD pcbNeeded
, BOOL unicode
)
6965 DWORD size
, left
= cbBuf
;
6966 BOOL space
= (cbBuf
> 0);
6973 ji1
->JobId
= job
->job_id
;
6976 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
6977 if(space
&& size
<= left
)
6979 ji1
->pDocument
= (LPWSTR
)ptr
;
6990 /*****************************************************************************
6993 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
6994 LPDWORD pcbNeeded
, BOOL unicode
)
6996 DWORD size
, left
= cbBuf
;
6997 BOOL space
= (cbBuf
> 0);
7004 ji2
->JobId
= job
->job_id
;
7007 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7008 if(space
&& size
<= left
)
7010 ji2
->pDocument
= (LPWSTR
)ptr
;
7021 /*****************************************************************************
7024 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7025 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7028 DWORD needed
= 0, size
;
7032 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7034 EnterCriticalSection(&printer_handles_cs
);
7035 job
= get_job(hPrinter
, JobId
);
7042 size
= sizeof(JOB_INFO_1W
);
7047 memset(pJob
, 0, size
);
7051 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7056 size
= sizeof(JOB_INFO_2W
);
7061 memset(pJob
, 0, size
);
7065 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7070 size
= sizeof(JOB_INFO_3
);
7074 memset(pJob
, 0, size
);
7083 SetLastError(ERROR_INVALID_LEVEL
);
7087 *pcbNeeded
= needed
;
7089 LeaveCriticalSection(&printer_handles_cs
);
7093 /*****************************************************************************
7094 * GetJobA [WINSPOOL.@]
7097 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7098 DWORD cbBuf
, LPDWORD pcbNeeded
)
7100 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7103 /*****************************************************************************
7104 * GetJobW [WINSPOOL.@]
7107 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7108 DWORD cbBuf
, LPDWORD pcbNeeded
)
7110 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7113 /*****************************************************************************
7116 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7118 char *unixname
, *queue
, *cmd
;
7119 char fmt
[] = "lpr -P%s %s";
7122 if(!(unixname
= wine_get_unix_file_name(filename
)))
7125 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7126 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7127 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7129 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7130 sprintf(cmd
, fmt
, queue
, unixname
);
7132 TRACE("printing with: %s\n", cmd
);
7135 HeapFree(GetProcessHeap(), 0, cmd
);
7136 HeapFree(GetProcessHeap(), 0, queue
);
7137 HeapFree(GetProcessHeap(), 0, unixname
);
7141 /*****************************************************************************
7144 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7146 #ifdef SONAME_LIBCUPS
7149 char *unixname
, *queue
, *doc_titleA
;
7153 if(!(unixname
= wine_get_unix_file_name(filename
)))
7156 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7157 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7158 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7160 len
= WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7161 doc_titleA
= HeapAlloc(GetProcessHeap(), 0, len
);
7162 WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, doc_titleA
, len
, NULL
, NULL
);
7164 TRACE("printing via cups\n");
7165 ret
= pcupsPrintFile(queue
, unixname
, doc_titleA
, 0, NULL
);
7166 HeapFree(GetProcessHeap(), 0, doc_titleA
);
7167 HeapFree(GetProcessHeap(), 0, queue
);
7168 HeapFree(GetProcessHeap(), 0, unixname
);
7174 return schedule_lpr(printer_name
, filename
);
7178 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7185 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7189 if(HIWORD(wparam
) == BN_CLICKED
)
7191 if(LOWORD(wparam
) == IDOK
)
7194 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7197 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7198 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7200 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7202 WCHAR caption
[200], message
[200];
7205 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7206 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7207 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7208 if(mb_ret
== IDCANCEL
)
7210 HeapFree(GetProcessHeap(), 0, filename
);
7214 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7215 if(hf
== INVALID_HANDLE_VALUE
)
7217 WCHAR caption
[200], message
[200];
7219 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7220 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7221 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7222 HeapFree(GetProcessHeap(), 0, filename
);
7226 DeleteFileW(filename
);
7227 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7229 EndDialog(hwnd
, IDOK
);
7232 if(LOWORD(wparam
) == IDCANCEL
)
7234 EndDialog(hwnd
, IDCANCEL
);
7243 /*****************************************************************************
7246 static BOOL
get_filename(LPWSTR
*filename
)
7248 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7249 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7252 /*****************************************************************************
7255 static BOOL
schedule_file(LPCWSTR filename
)
7257 LPWSTR output
= NULL
;
7259 if(get_filename(&output
))
7261 TRACE("copy to %s\n", debugstr_w(output
));
7262 CopyFileW(filename
, output
, FALSE
);
7263 HeapFree(GetProcessHeap(), 0, output
);
7269 /*****************************************************************************
7272 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7275 char *unixname
, *cmdA
;
7277 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7281 if(!(unixname
= wine_get_unix_file_name(filename
)))
7284 len
= WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7285 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7286 WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7288 TRACE("printing with: %s\n", cmdA
);
7290 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7295 ERR("pipe() failed!\n");
7305 /* reset signals that we previously set to SIG_IGN */
7306 signal(SIGPIPE
, SIG_DFL
);
7307 signal(SIGCHLD
, SIG_DFL
);
7309 execl("/bin/sh", "/bin/sh", "-c", cmdA
, (char*)0);
7313 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7314 write(fds
[1], buf
, no_read
);
7319 if(file_fd
!= -1) close(file_fd
);
7320 if(fds
[0] != -1) close(fds
[0]);
7321 if(fds
[1] != -1) close(fds
[1]);
7323 HeapFree(GetProcessHeap(), 0, cmdA
);
7324 HeapFree(GetProcessHeap(), 0, unixname
);
7331 /*****************************************************************************
7334 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7336 int in_fd
, out_fd
, no_read
;
7339 char *unixname
, *outputA
;
7342 if(!(unixname
= wine_get_unix_file_name(filename
)))
7345 len
= WideCharToMultiByte(CP_ACP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7346 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7347 WideCharToMultiByte(CP_ACP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7349 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7350 in_fd
= open(unixname
, O_RDONLY
);
7351 if(out_fd
== -1 || in_fd
== -1)
7354 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7355 write(out_fd
, buf
, no_read
);
7359 if(in_fd
!= -1) close(in_fd
);
7360 if(out_fd
!= -1) close(out_fd
);
7361 HeapFree(GetProcessHeap(), 0, outputA
);
7362 HeapFree(GetProcessHeap(), 0, unixname
);
7366 /*****************************************************************************
7367 * ScheduleJob [WINSPOOL.@]
7370 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7372 opened_printer_t
*printer
;
7374 struct list
*cursor
, *cursor2
;
7376 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7377 EnterCriticalSection(&printer_handles_cs
);
7378 printer
= get_opened_printer(hPrinter
);
7382 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7384 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7387 if(job
->job_id
!= dwJobID
) continue;
7389 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7390 if(hf
!= INVALID_HANDLE_VALUE
)
7392 PRINTER_INFO_5W
*pi5
;
7396 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7397 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7399 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7400 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7401 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7402 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7403 debugstr_w(pi5
->pPortName
));
7407 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7408 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7410 DWORD type
, count
= sizeof(output
);
7411 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
7414 if(output
[0] == '|')
7416 schedule_pipe(output
+ 1, job
->filename
);
7420 schedule_unixfile(output
, job
->filename
);
7422 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
7424 schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
7426 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
7428 schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7430 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
7432 schedule_file(job
->filename
);
7436 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
7438 HeapFree(GetProcessHeap(), 0, pi5
);
7440 DeleteFileW(job
->filename
);
7442 list_remove(cursor
);
7443 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7444 HeapFree(GetProcessHeap(), 0, job
->filename
);
7445 HeapFree(GetProcessHeap(), 0, job
);
7450 LeaveCriticalSection(&printer_handles_cs
);
7454 /*****************************************************************************
7455 * StartDocDlgA [WINSPOOL.@]
7457 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7459 UNICODE_STRING usBuffer
;
7462 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7465 docW
.cbSize
= sizeof(docW
);
7466 if (doc
->lpszDocName
)
7468 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7469 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7471 if (doc
->lpszOutput
)
7473 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7474 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7476 if (doc
->lpszDatatype
)
7478 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7479 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7481 docW
.fwType
= doc
->fwType
;
7483 retW
= StartDocDlgW(hPrinter
, &docW
);
7487 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7488 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7489 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7490 HeapFree(GetProcessHeap(), 0, retW
);
7493 HeapFree(GetProcessHeap(), 0, datatypeW
);
7494 HeapFree(GetProcessHeap(), 0, outputW
);
7495 HeapFree(GetProcessHeap(), 0, docnameW
);
7500 /*****************************************************************************
7501 * StartDocDlgW [WINSPOOL.@]
7503 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7504 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7505 * port is "FILE:". Also returns the full path if passed a relative path.
7507 * The caller should free the returned string from the process heap.
7509 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7514 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7516 PRINTER_INFO_5W
*pi5
;
7517 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7518 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7520 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7521 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7522 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7524 HeapFree(GetProcessHeap(), 0, pi5
);
7527 HeapFree(GetProcessHeap(), 0, pi5
);
7530 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7534 if (get_filename(&name
))
7536 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7538 HeapFree(GetProcessHeap(), 0, name
);
7541 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7542 GetFullPathNameW(name
, len
, ret
, NULL
);
7543 HeapFree(GetProcessHeap(), 0, name
);
7548 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7551 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7552 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7554 attr
= GetFileAttributesW(ret
);
7555 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7557 HeapFree(GetProcessHeap(), 0, ret
);