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 Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
196 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
197 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
198 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
200 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
201 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
203 static const WCHAR backslashW
[] = {'\\',0};
204 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
205 'i','o','n',' ','F','i','l','e',0};
206 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
207 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
208 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
209 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
210 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
211 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
212 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
213 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
214 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
215 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
216 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
217 static const WCHAR MonitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
218 static const WCHAR NameW
[] = {'N','a','m','e',0};
219 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
220 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
221 static const WCHAR PortW
[] = {'P','o','r','t',0};
222 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
223 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
224 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
225 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
226 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
227 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
228 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
229 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
230 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
231 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
232 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
233 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
234 static const WCHAR emptyStringW
[] = {0};
235 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
236 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
238 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
240 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
241 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
242 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
244 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
245 'D','o','c','u','m','e','n','t',0};
247 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
248 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
249 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
250 0, sizeof(DRIVER_INFO_8W
)};
252 /******************************************************************
253 * validate the user-supplied printing-environment [internal]
256 * env [I] PTR to Environment-String or NULL
260 * Success: PTR to printenv_t
263 * An empty string is handled the same way as NULL.
264 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
268 static const printenv_t
* validate_envW(LPCWSTR env
)
270 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
,
271 3, Version3_RegPathW
, Version3_SubdirW
};
272 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
,
273 0, Version0_RegPathW
, Version0_SubdirW
};
275 static const printenv_t
* const all_printenv
[]={&env_x86
, &env_win40
};
277 const printenv_t
*result
= NULL
;
280 TRACE("testing %s\n", debugstr_w(env
));
283 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
285 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
287 result
= all_printenv
[i
];
292 if (result
== NULL
) {
293 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
294 SetLastError(ERROR_INVALID_ENVIRONMENT
);
296 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
300 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
302 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
308 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
309 if passed a NULL string. This returns NULLs to the result.
311 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
315 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
316 return usBufferPtr
->Buffer
;
318 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
322 static LPWSTR
strdupW(LPCWSTR p
)
328 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
329 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
334 static LPSTR
strdupWtoA( LPCWSTR str
)
339 if (!str
) return NULL
;
340 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
341 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
342 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
346 /* Returns the number of bytes in an ansi \0\0 terminated string (multi_sz).
347 The result includes all \0s (specifically the last two). */
348 static int multi_sz_lenA(const char *str
)
350 const char *ptr
= str
;
354 ptr
+= lstrlenA(ptr
) + 1;
357 return ptr
- str
+ 1;
361 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
364 /* If forcing, or no profile string entry for device yet, set the entry
366 * The always change entry if not WINEPS yet is discussable.
369 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
371 !strstr(qbuf
,"WINEPS.DRV")
373 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
376 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
377 WriteProfileStringA("windows","device",buf
);
378 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
379 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
382 HeapFree(GetProcessHeap(),0,buf
);
386 static BOOL
add_printer_driver(const char *name
)
390 static char driver_path
[] = "wineps16",
391 data_file
[] = "<datafile?>",
392 config_file
[] = "wineps16",
393 help_file
[] = "<helpfile?>",
394 dep_file
[] = "<dependent files?>\0",
395 monitor_name
[] = "<monitor name?>",
396 default_data_type
[] = "RAW";
398 di3a
.cVersion
= (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
399 di3a
.pName
= (char *)name
;
400 di3a
.pEnvironment
= NULL
; /* NULL means auto */
401 di3a
.pDriverPath
= driver_path
;
402 di3a
.pDataFile
= data_file
;
403 di3a
.pConfigFile
= config_file
;
404 di3a
.pHelpFile
= help_file
;
405 di3a
.pDependentFiles
= dep_file
;
406 di3a
.pMonitorName
= monitor_name
;
407 di3a
.pDefaultDataType
= default_data_type
;
409 if (!AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
))
411 ERR("Failed adding driver (%d)\n", GetLastError());
417 #ifdef SONAME_LIBCUPS
418 static typeof(cupsGetDests
) *pcupsGetDests
;
419 static typeof(cupsGetPPD
) *pcupsGetPPD
;
420 static typeof(cupsPrintFile
) *pcupsPrintFile
;
421 static void *cupshandle
;
423 static BOOL
CUPS_LoadPrinters(void)
426 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
428 PRINTER_INFO_2A pinfo2a
;
430 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
433 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
435 TRACE("%s\n", loaderror
);
438 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
441 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
442 if (!p##x) return FALSE;
445 DYNCUPS(cupsGetDests
);
446 DYNCUPS(cupsPrintFile
);
449 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
451 ERR("Can't create Printers key\n");
455 nrofdests
= pcupsGetDests(&dests
);
456 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
457 for (i
=0;i
<nrofdests
;i
++) {
458 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests
[i
].name
)+1);
459 sprintf(port
,"LPR:%s",dests
[i
].name
);
460 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
461 sprintf(devline
,"WINEPS.DRV,%s",port
);
462 WriteProfileStringA("devices",dests
[i
].name
,devline
);
463 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
464 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
467 HeapFree(GetProcessHeap(),0,devline
);
469 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
470 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
471 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
473 TRACE("Printer already exists\n");
474 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
475 RegCloseKey(hkeyPrinter
);
477 static CHAR data_type
[] = "RAW",
478 print_proc
[] = "WinPrint",
479 comment
[] = "WINEPS Printer using CUPS",
480 location
[] = "<physical location of printer>",
481 params
[] = "<parameters?>",
482 share_name
[] = "<share name?>",
483 sep_file
[] = "<sep file?>";
485 add_printer_driver(dests
[i
].name
);
487 memset(&pinfo2a
,0,sizeof(pinfo2a
));
488 pinfo2a
.pPrinterName
= dests
[i
].name
;
489 pinfo2a
.pDatatype
= data_type
;
490 pinfo2a
.pPrintProcessor
= print_proc
;
491 pinfo2a
.pDriverName
= dests
[i
].name
;
492 pinfo2a
.pComment
= comment
;
493 pinfo2a
.pLocation
= location
;
494 pinfo2a
.pPortName
= port
;
495 pinfo2a
.pParameters
= params
;
496 pinfo2a
.pShareName
= share_name
;
497 pinfo2a
.pSepFile
= sep_file
;
499 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
500 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
501 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
504 HeapFree(GetProcessHeap(),0,port
);
507 if (dests
[i
].is_default
) {
508 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
512 if (hadprinter
& !haddefault
)
513 WINSPOOL_SetDefaultPrinter(dests
[0].name
, dests
[0].name
, TRUE
);
514 RegCloseKey(hkeyPrinters
);
520 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
521 PRINTER_INFO_2A pinfo2a
;
522 char *e
,*s
,*name
,*prettyname
,*devname
;
523 BOOL ret
= FALSE
, set_default
= FALSE
;
524 char *port
,*devline
,*env_default
;
525 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
527 while (isspace(*pent
)) pent
++;
528 s
= strchr(pent
,':');
530 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
538 TRACE("name=%s entry=%s\n",name
, pent
);
540 if(ispunct(*name
)) { /* a tc entry, not a real printer */
541 TRACE("skipping tc entry\n");
545 if(strstr(pent
,":server")) { /* server only version so skip */
546 TRACE("skipping server entry\n");
550 /* Determine whether this is a postscript printer. */
553 env_default
= getenv("PRINTER");
555 /* Get longest name, usually the one at the right for later display. */
556 while((s
=strchr(prettyname
,'|'))) {
559 while(isspace(*--e
)) *e
= '\0';
560 TRACE("\t%s\n", debugstr_a(prettyname
));
561 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
562 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
565 e
= prettyname
+ strlen(prettyname
);
566 while(isspace(*--e
)) *e
= '\0';
567 TRACE("\t%s\n", debugstr_a(prettyname
));
568 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
570 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
571 * if it is too long, we use it as comment below. */
572 devname
= prettyname
;
573 if (strlen(devname
)>=CCHDEVICENAME
-1)
575 if (strlen(devname
)>=CCHDEVICENAME
-1) {
580 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
581 sprintf(port
,"LPR:%s",name
);
583 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
584 sprintf(devline
,"WINEPS.DRV,%s",port
);
585 WriteProfileStringA("devices",devname
,devline
);
586 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
587 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
590 HeapFree(GetProcessHeap(),0,devline
);
592 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
594 ERR("Can't create Printers key\n");
598 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
599 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
601 TRACE("Printer already exists\n");
602 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
603 RegCloseKey(hkeyPrinter
);
605 static CHAR data_type
[] = "RAW",
606 print_proc
[] = "WinPrint",
607 comment
[] = "WINEPS Printer using LPR",
608 params
[] = "<parameters?>",
609 share_name
[] = "<share name?>",
610 sep_file
[] = "<sep file?>";
612 add_printer_driver(devname
);
614 memset(&pinfo2a
,0,sizeof(pinfo2a
));
615 pinfo2a
.pPrinterName
= devname
;
616 pinfo2a
.pDatatype
= data_type
;
617 pinfo2a
.pPrintProcessor
= print_proc
;
618 pinfo2a
.pDriverName
= devname
;
619 pinfo2a
.pComment
= comment
;
620 pinfo2a
.pLocation
= prettyname
;
621 pinfo2a
.pPortName
= port
;
622 pinfo2a
.pParameters
= params
;
623 pinfo2a
.pShareName
= share_name
;
624 pinfo2a
.pSepFile
= sep_file
;
626 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
627 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
628 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
631 RegCloseKey(hkeyPrinters
);
633 if (isfirst
|| set_default
)
634 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
636 HeapFree(GetProcessHeap(), 0, port
);
638 HeapFree(GetProcessHeap(), 0, name
);
643 PRINTCAP_LoadPrinters(void) {
644 BOOL hadprinter
= FALSE
;
648 BOOL had_bash
= FALSE
;
650 f
= fopen("/etc/printcap","r");
654 while(fgets(buf
,sizeof(buf
),f
)) {
657 end
=strchr(buf
,'\n');
661 while(isspace(*start
)) start
++;
662 if(*start
== '#' || *start
== '\0')
665 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
666 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
667 HeapFree(GetProcessHeap(),0,pent
);
671 if (end
&& *--end
== '\\') {
678 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
681 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
687 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
688 HeapFree(GetProcessHeap(),0,pent
);
694 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
697 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
698 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
700 return ERROR_FILE_NOT_FOUND
;
703 /*****************************************************************************
704 * enumerate the local monitors (INTERNAL)
706 * returns the needed size (in bytes) for pMonitors
707 * and *lpreturned is set to number of entries returned in pMonitors
710 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
715 LPMONITOR_INFO_2W mi
;
716 WCHAR buffer
[MAX_PATH
];
717 WCHAR dllname
[MAX_PATH
];
725 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
727 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
728 len
= entrysize
* numentries
;
729 ptr
= (LPWSTR
) &pMonitors
[len
];
732 len
= sizeof(buffer
);
735 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
736 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
737 /* Scan all Monitor-Registry-Keys */
738 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
739 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
740 dllsize
= sizeof(dllname
);
743 /* The Monitor must have a Driver-DLL */
744 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
745 if (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
746 /* We found a valid DLL for this Monitor. */
747 TRACE("using Driver: %s\n", debugstr_w(dllname
));
752 /* Windows returns only Port-Monitors here, but to simplify our code,
753 we do no filtering for Language-Monitors */
757 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
759 /* we install and return only monitors for "Windows NT x86" */
760 needed
+= (lstrlenW(envname_x86W
) +1) * sizeof(WCHAR
);
764 /* required size is calculated. Now fill the user-buffer */
765 if (pMonitors
&& (cbBuf
>= needed
)){
766 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
767 pMonitors
+= entrysize
;
769 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
771 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
772 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
774 mi
->pEnvironment
= ptr
;
775 lstrcpyW(ptr
, envname_x86W
); /* fixed to "Windows NT x86" */
776 ptr
+= (lstrlenW(envname_x86W
)+1);
779 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
780 ptr
+= (dllsize
/ sizeof(WCHAR
));
785 len
= sizeof(buffer
);
790 *lpreturned
= numentries
;
791 TRACE("need %d byte for %d entries\n", needed
, numentries
);
795 /******************************************************************
796 * monitor_unload [internal]
798 * release a printmonitor and unload it from memory, when needed
801 static void monitor_unload(monitor_t
* pm
)
803 if (pm
== NULL
) return;
804 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
806 EnterCriticalSection(&monitor_handles_cs
);
808 if (pm
->refcount
) pm
->refcount
--;
810 if (pm
->refcount
== 0) {
811 list_remove(&pm
->entry
);
812 FreeLibrary(pm
->hdll
);
813 HeapFree(GetProcessHeap(), 0, pm
->name
);
814 HeapFree(GetProcessHeap(), 0, pm
->dllname
);
815 HeapFree(GetProcessHeap(), 0, pm
);
817 LeaveCriticalSection(&monitor_handles_cs
);
820 /******************************************************************
821 * monitor_unloadall [internal]
823 * release all printmonitors and unload them from memory, when needed
826 static void monitor_unloadall(void)
831 EnterCriticalSection(&monitor_handles_cs
);
832 /* iterate through the list, with safety against removal */
833 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
837 LeaveCriticalSection(&monitor_handles_cs
);
840 /******************************************************************
841 * monitor_load [internal]
843 * load a printmonitor, get the dllname from the registry, when needed
844 * initialize the monitor and dump found function-pointers
846 * On failure, SetLastError() is called and NULL is returned
849 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
851 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
852 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
853 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
854 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
855 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
857 monitor_t
* pm
= NULL
;
859 LPWSTR regroot
= NULL
;
860 LPWSTR driver
= dllname
;
862 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
863 /* Is the Monitor already loaded? */
864 EnterCriticalSection(&monitor_handles_cs
);
867 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
869 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
877 pm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(monitor_t
));
878 if (pm
== NULL
) goto cleanup
;
879 list_add_tail(&monitor_handles
, &pm
->entry
);
883 if (pm
->name
== NULL
) {
884 /* Load the monitor */
885 LPMONITOREX pmonitorEx
;
889 len
= lstrlenW(MonitorsW
) + lstrlenW(name
) + 2;
890 regroot
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
894 lstrcpyW(regroot
, MonitorsW
);
895 lstrcatW(regroot
, name
);
896 /* Get the Driver from the Registry */
897 if (driver
== NULL
) {
900 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
901 if (RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, NULL
,
902 &namesize
) == ERROR_SUCCESS
) {
903 driver
= HeapAlloc(GetProcessHeap(), 0, namesize
);
904 RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
911 pm
->name
= strdupW(name
);
912 pm
->dllname
= strdupW(driver
);
914 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
916 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
921 pm
->hdll
= LoadLibraryW(driver
);
922 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
924 if (pm
->hdll
== NULL
) {
926 SetLastError(ERROR_MOD_NOT_FOUND
);
931 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
932 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
933 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
934 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
935 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
938 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
939 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
940 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
941 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
942 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
944 if (pInitializePrintMonitorUI
!= NULL
) {
945 pm
->monitorUI
= pInitializePrintMonitorUI();
946 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
948 TRACE( "0x%08x: dwMonitorSize (%d)\n",
949 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
954 if (pInitializePrintMonitor
&& regroot
) {
955 pmonitorEx
= pInitializePrintMonitor(regroot
);
956 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
957 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
960 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
961 pm
->monitor
= &(pmonitorEx
->Monitor
);
966 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
970 if (!pm
->monitor
&& regroot
) {
971 if (pInitializePrintMonitor2
!= NULL
) {
972 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
974 if (pInitializeMonitorEx
!= NULL
) {
975 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
977 if (pInitializeMonitor
!= NULL
) {
978 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
981 if (!pm
->monitor
&& !pm
->monitorUI
) {
983 SetLastError(ERROR_PROC_NOT_FOUND
);
988 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, LocalPortW
) == 0)) {
992 LeaveCriticalSection(&monitor_handles_cs
);
993 if (driver
!= dllname
) HeapFree(GetProcessHeap(), 0, driver
);
994 HeapFree(GetProcessHeap(), 0, regroot
);
995 TRACE("=> %p\n", pm
);
999 /******************************************************************
1000 * monitor_loadall [internal]
1002 * Load all registered monitors
1005 static DWORD
monitor_loadall(void)
1008 DWORD registered
= 0;
1011 WCHAR buffer
[MAX_PATH
];
1014 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
1015 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
1016 NULL
, NULL
, NULL
, NULL
, NULL
);
1018 TRACE("%d monitors registered\n", registered
);
1020 EnterCriticalSection(&monitor_handles_cs
);
1021 while (id
< registered
) {
1023 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
1024 pm
= monitor_load(buffer
, NULL
);
1028 LeaveCriticalSection(&monitor_handles_cs
);
1029 RegCloseKey(hmonitors
);
1031 TRACE("%d monitors loaded\n", loaded
);
1035 /******************************************************************
1036 * monitor_loadui [internal]
1038 * load the userinterface-dll for a given portmonitor
1040 * On failure, NULL is returned
1043 static monitor_t
* monitor_loadui(monitor_t
* pm
)
1045 monitor_t
* pui
= NULL
;
1046 LPWSTR buffer
[MAX_PATH
];
1051 if (pm
== NULL
) return NULL
;
1052 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
1054 /* Try the Portmonitor first; works for many monitors */
1055 if (pm
->monitorUI
) {
1056 EnterCriticalSection(&monitor_handles_cs
);
1058 LeaveCriticalSection(&monitor_handles_cs
);
1062 /* query the userinterface-dllname from the Portmonitor */
1063 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
1064 /* building (",XcvMonitor %s",pm->name) not needed yet */
1065 res
= pm
->monitor
->pfnXcvOpenPort(emptyStringW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
1066 TRACE("got %u with %p\n", res
, hXcv
);
1068 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, MonitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
1069 TRACE("got %u with %s\n", res
, debugstr_w((LPWSTR
) buffer
));
1070 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, (LPWSTR
) buffer
);
1071 pm
->monitor
->pfnXcvClosePort(hXcv
);
1078 /******************************************************************
1079 * monitor_load_by_port [internal]
1081 * load a printmonitor for a given port
1083 * On failure, NULL is returned
1086 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
1091 monitor_t
* pm
= NULL
;
1092 DWORD registered
= 0;
1096 TRACE("(%s)\n", debugstr_w(portname
));
1098 /* Try the Local Monitor first */
1099 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
) == ERROR_SUCCESS
) {
1100 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
1101 /* found the portname */
1103 return monitor_load(LocalPortW
, NULL
);
1108 len
= MAX_PATH
+ lstrlenW(bs_Ports_bsW
) + lstrlenW(portname
) + 1;
1109 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1110 if (buffer
== NULL
) return NULL
;
1112 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
1113 EnterCriticalSection(&monitor_handles_cs
);
1114 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1116 while ((pm
== NULL
) && (id
< registered
)) {
1118 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
1119 TRACE("testing %s\n", debugstr_w(buffer
));
1120 len
= lstrlenW(buffer
);
1121 lstrcatW(buffer
, bs_Ports_bsW
);
1122 lstrcatW(buffer
, portname
);
1123 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
1125 buffer
[len
] = '\0'; /* use only the Monitor-Name */
1126 pm
= monitor_load(buffer
, NULL
);
1130 LeaveCriticalSection(&monitor_handles_cs
);
1133 HeapFree(GetProcessHeap(), 0, buffer
);
1137 /******************************************************************
1138 * enumerate the local Ports from all loaded monitors (internal)
1140 * returns the needed size (in bytes) for pPorts
1141 * and *lpreturned is set to number of entries returned in pPorts
1144 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
1148 LPPORT_INFO_2W cache
;
1150 LPBYTE pi_buffer
= NULL
;
1151 DWORD pi_allocated
= 0;
1162 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
1163 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
1165 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1166 needed
= entrysize
* numentries
;
1167 ptr
= (LPWSTR
) &pPorts
[needed
];
1172 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
1174 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
1177 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1178 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
1179 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1180 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1181 pi_buffer
= HeapAlloc(GetProcessHeap(), 0, pi_needed
);
1182 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
1183 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1185 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1186 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
1188 numentries
+= pi_returned
;
1189 needed
+= pi_needed
;
1191 /* fill the output-buffer (pPorts), if we have one */
1192 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
1194 while (pi_returned
> pi_index
) {
1195 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
1196 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
1197 out
->pPortName
= ptr
;
1198 lstrcpyW(ptr
, cache
->pPortName
);
1199 ptr
+= (lstrlenW(ptr
)+1);
1201 out
->pMonitorName
= ptr
;
1202 lstrcpyW(ptr
, cache
->pMonitorName
);
1203 ptr
+= (lstrlenW(ptr
)+1);
1205 out
->pDescription
= ptr
;
1206 lstrcpyW(ptr
, cache
->pDescription
);
1207 ptr
+= (lstrlenW(ptr
)+1);
1208 out
->fPortType
= cache
->fPortType
;
1209 out
->Reserved
= cache
->Reserved
;
1217 /* the temporary portinfo-buffer is no longer needed */
1218 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1220 *lpreturned
= numentries
;
1221 TRACE("need %d byte for %d entries\n", needed
, numentries
);
1225 /******************************************************************
1226 * get_servername_from_name (internal)
1228 * for an external server, a copy of the serverpart from the full name is returned
1231 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1235 WCHAR buffer
[MAX_PATH
];
1238 if (name
== NULL
) return NULL
;
1239 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1241 server
= strdupW(&name
[2]); /* skip over both backslash */
1242 if (server
== NULL
) return NULL
;
1244 /* strip '\' and the printername */
1245 ptr
= strchrW(server
, '\\');
1246 if (ptr
) ptr
[0] = '\0';
1248 TRACE("found %s\n", debugstr_w(server
));
1250 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1251 if (GetComputerNameW(buffer
, &len
)) {
1252 if (lstrcmpW(buffer
, server
) == 0) {
1253 /* The requested Servername is our computername */
1254 HeapFree(GetProcessHeap(), 0, server
);
1261 /******************************************************************
1262 * get_basename_from_name (internal)
1264 * skip over the serverpart from the full name
1267 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1269 if (name
== NULL
) return NULL
;
1270 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1271 /* skip over the servername and search for the following '\' */
1272 name
= strchrW(&name
[2], '\\');
1273 if ((name
) && (name
[1])) {
1274 /* found a separator ('\') followed by a name:
1275 skip over the separator and return the rest */
1280 /* no basename present (we found only a servername) */
1287 /******************************************************************
1288 * get_opened_printer_entry
1289 * Get the first place empty in the opened printer table
1292 * - pDefault is ignored
1294 static HANDLE
get_opened_printer_entry(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1296 UINT_PTR handle
= nb_printer_handles
, i
;
1297 jobqueue_t
*queue
= NULL
;
1298 opened_printer_t
*printer
= NULL
;
1300 LPCWSTR printername
;
1305 servername
= get_servername_from_name(name
);
1307 FIXME("server %s not supported\n", debugstr_w(servername
));
1308 HeapFree(GetProcessHeap(), 0, servername
);
1309 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1313 printername
= get_basename_from_name(name
);
1314 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1316 /* an empty printername is invalid */
1317 if (printername
&& (!printername
[0])) {
1318 SetLastError(ERROR_INVALID_PARAMETER
);
1322 EnterCriticalSection(&printer_handles_cs
);
1324 for (i
= 0; i
< nb_printer_handles
; i
++)
1326 if (!printer_handles
[i
])
1328 if(handle
== nb_printer_handles
)
1333 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1334 queue
= printer_handles
[i
]->queue
;
1338 if (handle
>= nb_printer_handles
)
1340 opened_printer_t
**new_array
;
1341 if (printer_handles
)
1342 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1343 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1345 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1346 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1353 printer_handles
= new_array
;
1354 nb_printer_handles
+= 16;
1357 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1364 /* clone the base name. This is NULL for the printserver */
1365 printer
->printername
= strdupW(printername
);
1367 /* clone the full name */
1368 printer
->name
= strdupW(name
);
1369 if (name
&& (!printer
->name
)) {
1375 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1376 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1377 /* OpenPrinter(",XcvMonitor " detected */
1378 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1379 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1380 if (printer
->pm
== NULL
) {
1381 SetLastError(ERROR_UNKNOWN_PORT
);
1388 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1389 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1390 /* OpenPrinter(",XcvPort " detected */
1391 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1392 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1393 if (printer
->pm
== NULL
) {
1394 SetLastError(ERROR_UNKNOWN_PORT
);
1402 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1403 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1404 pDefault
? pDefault
->DesiredAccess
: 0,
1407 if (printer
->hXcv
== NULL
) {
1408 SetLastError(ERROR_INVALID_PARAMETER
);
1415 /* Does the Printer exist? */
1416 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1417 ERR("Can't create Printers key\n");
1421 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1422 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1423 RegCloseKey(hkeyPrinters
);
1424 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1428 RegCloseKey(hkeyPrinter
);
1429 RegCloseKey(hkeyPrinters
);
1434 TRACE("using the local printserver\n");
1438 printer
->queue
= queue
;
1441 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1442 if (!printer
->queue
) {
1446 list_init(&printer
->queue
->jobs
);
1447 printer
->queue
->ref
= 0;
1449 InterlockedIncrement(&printer
->queue
->ref
);
1451 printer_handles
[handle
] = printer
;
1454 LeaveCriticalSection(&printer_handles_cs
);
1455 if (!handle
&& printer
) {
1456 /* Something failed: Free all resources */
1457 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1458 monitor_unload(printer
->pm
);
1459 HeapFree(GetProcessHeap(), 0, printer
->printername
);
1460 HeapFree(GetProcessHeap(), 0, printer
->name
);
1461 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1462 HeapFree(GetProcessHeap(), 0, printer
);
1465 return (HANDLE
)handle
;
1468 /******************************************************************
1469 * get_opened_printer
1470 * Get the pointer to the opened printer referred by the handle
1472 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
1474 UINT_PTR idx
= (UINT_PTR
)hprn
;
1475 opened_printer_t
*ret
= NULL
;
1477 EnterCriticalSection(&printer_handles_cs
);
1479 if ((idx
<= 0) || (idx
> nb_printer_handles
))
1482 ret
= printer_handles
[idx
- 1];
1484 LeaveCriticalSection(&printer_handles_cs
);
1488 /******************************************************************
1489 * get_opened_printer_name
1490 * Get the pointer to the opened printer name referred by the handle
1492 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
1494 opened_printer_t
*printer
= get_opened_printer(hprn
);
1495 if(!printer
) return NULL
;
1496 return printer
->name
;
1499 /******************************************************************
1500 * WINSPOOL_GetOpenedPrinterRegKey
1503 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
1505 LPCWSTR name
= get_opened_printer_name(hPrinter
);
1509 if(!name
) return ERROR_INVALID_HANDLE
;
1511 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
1515 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
1517 ERR("Can't find opened printer %s in registry\n",
1519 RegCloseKey(hkeyPrinters
);
1520 return ERROR_INVALID_PRINTER_NAME
; /* ? */
1522 RegCloseKey(hkeyPrinters
);
1523 return ERROR_SUCCESS
;
1526 void WINSPOOL_LoadSystemPrinters(void)
1528 HKEY hkey
, hkeyPrinters
;
1530 DWORD needed
, num
, i
;
1531 WCHAR PrinterName
[256];
1534 /* This ensures that all printer entries have a valid Name value. If causes
1535 problems later if they don't. If one is found to be missed we create one
1536 and set it equal to the name of the key */
1537 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1538 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1539 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1540 for(i
= 0; i
< num
; i
++) {
1541 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) == ERROR_SUCCESS
) {
1542 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1543 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1544 set_reg_szW(hkey
, NameW
, PrinterName
);
1551 RegCloseKey(hkeyPrinters
);
1554 /* We want to avoid calling AddPrinter on printers as much as
1555 possible, because on cups printers this will (eventually) lead
1556 to a call to cupsGetPPD which takes forever, even with non-cups
1557 printers AddPrinter takes a while. So we'll tag all printers that
1558 were automatically added last time around, if they still exist
1559 we'll leave them be otherwise we'll delete them. */
1560 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1562 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1563 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1564 for(i
= 0; i
< num
; i
++) {
1565 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1566 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1567 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1569 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1577 HeapFree(GetProcessHeap(), 0, pi
);
1581 #ifdef SONAME_LIBCUPS
1582 done
= CUPS_LoadPrinters();
1585 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1586 PRINTCAP_LoadPrinters();
1588 /* Now enumerate the list again and delete any printers that a still tagged */
1589 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1591 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1592 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1593 for(i
= 0; i
< num
; i
++) {
1594 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1595 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1596 BOOL delete_driver
= FALSE
;
1597 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1598 DWORD dw
, type
, size
= sizeof(dw
);
1599 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1600 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1601 DeletePrinter(hprn
);
1602 delete_driver
= TRUE
;
1608 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1613 HeapFree(GetProcessHeap(), 0, pi
);
1620 /******************************************************************
1623 * Get the pointer to the specified job.
1624 * Should hold the printer_handles_cs before calling.
1626 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1628 opened_printer_t
*printer
= get_opened_printer(hprn
);
1631 if(!printer
) return NULL
;
1632 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1634 if(job
->job_id
== JobId
)
1640 /***********************************************************
1643 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1646 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1649 Formname
= (dmA
->dmSize
> off_formname
);
1650 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1651 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1652 dmW
->dmDeviceName
, CCHDEVICENAME
);
1654 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1655 dmA
->dmSize
- CCHDEVICENAME
);
1657 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1658 off_formname
- CCHDEVICENAME
);
1659 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1660 dmW
->dmFormName
, CCHFORMNAME
);
1661 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1662 (off_formname
+ CCHFORMNAME
));
1665 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1666 dmA
->dmDriverExtra
);
1670 /***********************************************************
1672 * Creates an ascii copy of supplied devmode on heap
1674 static LPDEVMODEA
DEVMODEdupWtoA(HANDLE heap
, const DEVMODEW
*dmW
)
1679 ptrdiff_t off_formname
= (const char *)dmW
->dmFormName
- (const char *)dmW
;
1681 if(!dmW
) return NULL
;
1682 Formname
= (dmW
->dmSize
> off_formname
);
1683 size
= dmW
->dmSize
- CCHDEVICENAME
- (Formname
? CCHFORMNAME
: 0);
1684 dmA
= HeapAlloc(heap
, HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1685 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1686 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1688 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1689 dmW
->dmSize
- CCHDEVICENAME
* sizeof(WCHAR
));
1691 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1692 off_formname
- CCHDEVICENAME
* sizeof(WCHAR
));
1693 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1694 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1695 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
-
1696 (off_formname
+ CCHFORMNAME
* sizeof(WCHAR
)));
1699 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
,
1700 dmW
->dmDriverExtra
);
1704 /***********************************************************
1705 * PRINTER_INFO_2AtoW
1706 * Creates a unicode copy of PRINTER_INFO_2A on heap
1708 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1710 LPPRINTER_INFO_2W piW
;
1711 UNICODE_STRING usBuffer
;
1713 if(!piA
) return NULL
;
1714 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1715 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1717 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1718 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1719 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1720 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1721 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1722 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1723 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1724 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1725 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1726 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1727 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1728 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1732 /***********************************************************
1733 * FREE_PRINTER_INFO_2W
1734 * Free PRINTER_INFO_2W and all strings
1736 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1740 HeapFree(heap
,0,piW
->pServerName
);
1741 HeapFree(heap
,0,piW
->pPrinterName
);
1742 HeapFree(heap
,0,piW
->pShareName
);
1743 HeapFree(heap
,0,piW
->pPortName
);
1744 HeapFree(heap
,0,piW
->pDriverName
);
1745 HeapFree(heap
,0,piW
->pComment
);
1746 HeapFree(heap
,0,piW
->pLocation
);
1747 HeapFree(heap
,0,piW
->pDevMode
);
1748 HeapFree(heap
,0,piW
->pSepFile
);
1749 HeapFree(heap
,0,piW
->pPrintProcessor
);
1750 HeapFree(heap
,0,piW
->pDatatype
);
1751 HeapFree(heap
,0,piW
->pParameters
);
1752 HeapFree(heap
,0,piW
);
1756 /******************************************************************
1757 * DeviceCapabilities [WINSPOOL.@]
1758 * DeviceCapabilitiesA [WINSPOOL.@]
1761 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1762 LPSTR pOutput
, LPDEVMODEA lpdm
)
1766 if (!GDI_CallDeviceCapabilities16
)
1768 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1770 if (!GDI_CallDeviceCapabilities16
) return -1;
1772 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1774 /* If DC_PAPERSIZE map POINT16s to POINTs */
1775 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1776 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1777 POINT
*pt
= (POINT
*)pOutput
;
1779 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1780 for(i
= 0; i
< ret
; i
++, pt
++)
1785 HeapFree( GetProcessHeap(), 0, tmp
);
1791 /*****************************************************************************
1792 * DeviceCapabilitiesW [WINSPOOL.@]
1794 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1797 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1798 WORD fwCapability
, LPWSTR pOutput
,
1799 const DEVMODEW
*pDevMode
)
1801 LPDEVMODEA dmA
= DEVMODEdupWtoA(GetProcessHeap(), pDevMode
);
1802 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1803 LPSTR pPortA
= strdupWtoA(pPort
);
1806 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1807 fwCapability
== DC_FILEDEPENDENCIES
||
1808 fwCapability
== DC_PAPERNAMES
)) {
1809 /* These need A -> W translation */
1812 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1816 switch(fwCapability
) {
1821 case DC_FILEDEPENDENCIES
:
1825 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1826 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1828 for(i
= 0; i
< ret
; i
++)
1829 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1830 pOutput
+ (i
* size
), size
);
1831 HeapFree(GetProcessHeap(), 0, pOutputA
);
1833 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1834 (LPSTR
)pOutput
, dmA
);
1836 HeapFree(GetProcessHeap(),0,pPortA
);
1837 HeapFree(GetProcessHeap(),0,pDeviceA
);
1838 HeapFree(GetProcessHeap(),0,dmA
);
1842 /******************************************************************
1843 * DocumentPropertiesA [WINSPOOL.@]
1845 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1847 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1848 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1849 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1851 LPSTR lpName
= pDeviceName
;
1852 static CHAR port
[] = "LPT1:";
1855 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1856 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1860 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1862 ERR("no name from hPrinter?\n");
1863 SetLastError(ERROR_INVALID_HANDLE
);
1866 lpName
= strdupWtoA(lpNameW
);
1869 if (!GDI_CallExtDeviceMode16
)
1871 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1873 if (!GDI_CallExtDeviceMode16
) {
1874 ERR("No CallExtDeviceMode16?\n");
1878 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1879 pDevModeInput
, NULL
, fMode
);
1882 HeapFree(GetProcessHeap(),0,lpName
);
1887 /*****************************************************************************
1888 * DocumentPropertiesW (WINSPOOL.@)
1890 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1892 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1894 LPDEVMODEW pDevModeOutput
,
1895 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1898 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1899 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput
);
1900 LPDEVMODEA pDevModeOutputA
= NULL
;
1903 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1904 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1906 if(pDevModeOutput
) {
1907 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1908 if(ret
< 0) return ret
;
1909 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1911 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1912 pDevModeInputA
, fMode
);
1913 if(pDevModeOutput
) {
1914 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1915 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1917 if(fMode
== 0 && ret
> 0)
1918 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1919 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1920 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1924 /******************************************************************
1925 * OpenPrinterA [WINSPOOL.@]
1930 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1931 LPPRINTER_DEFAULTSA pDefault
)
1933 UNICODE_STRING lpPrinterNameW
;
1934 UNICODE_STRING usBuffer
;
1935 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1936 PWSTR pwstrPrinterNameW
;
1939 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1942 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1943 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1944 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1945 pDefaultW
= &DefaultW
;
1947 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1949 RtlFreeUnicodeString(&usBuffer
);
1950 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1952 RtlFreeUnicodeString(&lpPrinterNameW
);
1956 /******************************************************************
1957 * OpenPrinterW [WINSPOOL.@]
1959 * Open a Printer / Printserver or a Printer-Object
1962 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1963 * phPrinter [O] The resulting Handle is stored here
1964 * pDefault [I] PTR to Default Printer Settings or NULL
1971 * lpPrinterName is one of:
1972 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1973 *| Printer: "PrinterName"
1974 *| Printer-Object: "PrinterName,Job xxx"
1975 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1976 *| XcvPort: "Servername,XcvPort PortName"
1979 *| Printer-Object not supported
1980 *| pDefaults is ignored
1983 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1986 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
1988 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1989 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
1993 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1994 SetLastError(ERROR_INVALID_PARAMETER
);
1998 /* Get the unique handle of the printer or Printserver */
1999 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2000 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2001 return (*phPrinter
!= 0);
2004 /******************************************************************
2005 * AddMonitorA [WINSPOOL.@]
2010 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2012 LPWSTR nameW
= NULL
;
2015 LPMONITOR_INFO_2A mi2a
;
2016 MONITOR_INFO_2W mi2w
;
2018 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2019 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2020 mi2a
? debugstr_a(mi2a
->pName
) : NULL
,
2021 mi2a
? debugstr_a(mi2a
->pEnvironment
) : NULL
,
2022 mi2a
? debugstr_a(mi2a
->pDLLName
) : NULL
);
2025 SetLastError(ERROR_INVALID_LEVEL
);
2029 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2035 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2036 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2037 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2040 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2042 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2043 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2044 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2046 if (mi2a
->pEnvironment
) {
2047 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2048 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2049 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2051 if (mi2a
->pDLLName
) {
2052 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2053 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2054 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2057 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2059 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2060 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2061 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2063 HeapFree(GetProcessHeap(), 0, nameW
);
2067 /******************************************************************************
2068 * AddMonitorW [WINSPOOL.@]
2070 * Install a Printmonitor
2073 * pName [I] Servername or NULL (local Computer)
2074 * Level [I] Structure-Level (Must be 2)
2075 * pMonitors [I] PTR to MONITOR_INFO_2
2082 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2085 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2087 monitor_t
* pm
= NULL
;
2088 LPMONITOR_INFO_2W mi2w
;
2094 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2095 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2096 mi2w
? debugstr_w(mi2w
->pName
) : NULL
,
2097 mi2w
? debugstr_w(mi2w
->pEnvironment
) : NULL
,
2098 mi2w
? debugstr_w(mi2w
->pDLLName
) : NULL
);
2101 SetLastError(ERROR_INVALID_LEVEL
);
2105 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2110 if (pName
&& (pName
[0])) {
2111 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2112 SetLastError(ERROR_ACCESS_DENIED
);
2117 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
2118 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
2119 SetLastError(ERROR_INVALID_PARAMETER
);
2122 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, envname_x86W
)) {
2123 WARN("Environment %s requested (we support only %s)\n",
2124 debugstr_w(mi2w
->pEnvironment
), debugstr_w(envname_x86W
));
2125 SetLastError(ERROR_INVALID_ENVIRONMENT
);
2129 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
2130 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
2131 SetLastError(ERROR_INVALID_PARAMETER
);
2135 /* Load and initialize the monitor. SetLastError() is called on failure */
2136 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
2141 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2142 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2146 if(RegCreateKeyExW( hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2147 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
2148 &disposition
) == ERROR_SUCCESS
) {
2150 /* Some installers set options for the port before calling AddMonitor.
2151 We query the "Driver" entry to verify that the monitor is installed,
2152 before we return an error.
2153 When a user installs two print monitors at the same time with the
2154 same name but with a different driver DLL and a task switch comes
2155 between RegQueryValueExW and RegSetValueExW, a race condition
2156 is possible but silently ignored. */
2160 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
2161 (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, NULL
,
2162 &namesize
) == ERROR_SUCCESS
)) {
2163 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
2164 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2165 9x: ERROR_ALREADY_EXISTS (183) */
2166 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
2171 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
2172 res
= (RegSetValueExW(hentry
, DriverW
, 0,
2173 REG_SZ
, (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
2175 RegCloseKey(hentry
);
2182 /******************************************************************
2183 * DeletePrinterDriverA [WINSPOOL.@]
2186 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2188 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2191 /******************************************************************
2192 * DeletePrinterDriverW [WINSPOOL.@]
2195 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2197 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2200 /******************************************************************
2201 * DeleteMonitorA [WINSPOOL.@]
2203 * See DeleteMonitorW.
2206 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2208 LPWSTR nameW
= NULL
;
2209 LPWSTR EnvironmentW
= NULL
;
2210 LPWSTR MonitorNameW
= NULL
;
2215 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2216 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2217 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2221 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2222 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2223 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2226 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2227 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2228 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2231 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2233 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2234 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2235 HeapFree(GetProcessHeap(), 0, nameW
);
2239 /******************************************************************
2240 * DeleteMonitorW [WINSPOOL.@]
2242 * Delete a specific Printmonitor from a Printing-Environment
2245 * pName [I] Servername or NULL (local Computer)
2246 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2247 * pMonitorName [I] Name of the Monitor, that should be deleted
2254 * pEnvironment is ignored in Windows for the local Computer.
2258 BOOL WINAPI
DeleteMonitorW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2262 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2263 debugstr_w(pMonitorName
));
2265 if (pName
&& (pName
[0])) {
2266 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2267 SetLastError(ERROR_ACCESS_DENIED
);
2271 /* pEnvironment is ignored in Windows for the local Computer */
2273 if (!pMonitorName
|| !pMonitorName
[0]) {
2274 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
2275 SetLastError(ERROR_INVALID_PARAMETER
);
2279 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2280 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2284 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
2285 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName
));
2290 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName
));
2293 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2294 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
2298 /******************************************************************
2299 * DeletePortA [WINSPOOL.@]
2304 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2306 LPWSTR nameW
= NULL
;
2307 LPWSTR portW
= NULL
;
2311 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2313 /* convert servername to unicode */
2315 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2316 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2317 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2320 /* convert portname to unicode */
2322 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2323 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2324 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2327 res
= DeletePortW(nameW
, hWnd
, portW
);
2328 HeapFree(GetProcessHeap(), 0, nameW
);
2329 HeapFree(GetProcessHeap(), 0, portW
);
2333 /******************************************************************
2334 * DeletePortW [WINSPOOL.@]
2336 * Delete a specific Port
2339 * pName [I] Servername or NULL (local Computer)
2340 * hWnd [I] Handle to parent Window for the Dialog-Box
2341 * pPortName [I] Name of the Port, that should be deleted
2348 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2354 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2356 if (pName
&& pName
[0]) {
2357 SetLastError(ERROR_INVALID_PARAMETER
);
2362 SetLastError(RPC_X_NULL_REF_POINTER
);
2366 /* an empty Portname is Invalid */
2367 if (!pPortName
[0]) {
2368 SetLastError(ERROR_NOT_SUPPORTED
);
2372 pm
= monitor_load_by_port(pPortName
);
2373 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
2374 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2375 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
2376 TRACE("got %d with %u\n", res
, GetLastError());
2380 pui
= monitor_loadui(pm
);
2381 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2382 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2383 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2384 TRACE("got %d with %u\n", res
, GetLastError());
2388 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
2389 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
2391 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2392 SetLastError(ERROR_NOT_SUPPORTED
);
2395 monitor_unload(pui
);
2399 TRACE("returning %d with %u\n", res
, GetLastError());
2403 /******************************************************************************
2404 * SetPrinterW [WINSPOOL.@]
2406 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2408 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2409 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2413 /******************************************************************************
2414 * WritePrinter [WINSPOOL.@]
2416 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2418 opened_printer_t
*printer
;
2421 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2423 EnterCriticalSection(&printer_handles_cs
);
2424 printer
= get_opened_printer(hPrinter
);
2427 SetLastError(ERROR_INVALID_HANDLE
);
2433 SetLastError(ERROR_SPL_NO_STARTDOC
);
2437 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2439 LeaveCriticalSection(&printer_handles_cs
);
2443 /*****************************************************************************
2444 * AddFormA [WINSPOOL.@]
2446 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2448 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2452 /*****************************************************************************
2453 * AddFormW [WINSPOOL.@]
2455 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2457 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2461 /*****************************************************************************
2462 * AddJobA [WINSPOOL.@]
2464 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2467 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2471 SetLastError(ERROR_INVALID_LEVEL
);
2475 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2478 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2479 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2480 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2481 if(*pcbNeeded
> cbBuf
) {
2482 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2485 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2486 addjobA
->JobId
= addjobW
->JobId
;
2487 addjobA
->Path
= (char *)(addjobA
+ 1);
2488 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2494 /*****************************************************************************
2495 * AddJobW [WINSPOOL.@]
2497 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2499 opened_printer_t
*printer
;
2502 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2503 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2504 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2506 ADDJOB_INFO_1W
*addjob
;
2508 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2510 EnterCriticalSection(&printer_handles_cs
);
2512 printer
= get_opened_printer(hPrinter
);
2515 SetLastError(ERROR_INVALID_HANDLE
);
2520 SetLastError(ERROR_INVALID_LEVEL
);
2524 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2528 job
->job_id
= InterlockedIncrement(&next_job_id
);
2530 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2531 if(path
[len
- 1] != '\\')
2533 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2534 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2536 len
= strlenW(filename
);
2537 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2538 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2539 job
->document_title
= strdupW(default_doc_title
);
2540 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2542 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2543 if(*pcbNeeded
<= cbBuf
) {
2544 addjob
= (ADDJOB_INFO_1W
*)pData
;
2545 addjob
->JobId
= job
->job_id
;
2546 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2547 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2550 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2553 LeaveCriticalSection(&printer_handles_cs
);
2557 /*****************************************************************************
2558 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2560 * Return the PATH for the Print-Processors
2562 * See GetPrintProcessorDirectoryW.
2566 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2567 DWORD level
, LPBYTE Info
,
2568 DWORD cbBuf
, LPDWORD pcbNeeded
)
2570 LPWSTR serverW
= NULL
;
2575 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2576 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2580 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2581 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2582 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2586 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2587 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2588 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2591 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2592 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2594 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2597 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2598 cbBuf
, NULL
, NULL
) > 0;
2601 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2602 HeapFree(GetProcessHeap(), 0, envW
);
2603 HeapFree(GetProcessHeap(), 0, serverW
);
2607 /*****************************************************************************
2608 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2610 * Return the PATH for the Print-Processors
2613 * server [I] Servername (NT only) or NULL (local Computer)
2614 * env [I] Printing-Environment (see below) or NULL (Default)
2615 * level [I] Structure-Level (must be 1)
2616 * Info [O] PTR to Buffer that receives the Result
2617 * cbBuf [I] Size of Buffer at "Info"
2618 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2619 * required for the Buffer at "Info"
2622 * Success: TRUE and in pcbNeeded the Bytes used in Info
2623 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2624 * if cbBuf is too small
2626 * Native Values returned in Info on Success:
2627 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2628 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2629 *| win9x(Windows 4.0): "%winsysdir%"
2631 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2634 * Only NULL or "" is supported for server
2637 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2638 DWORD level
, LPBYTE Info
,
2639 DWORD cbBuf
, LPDWORD pcbNeeded
)
2642 const printenv_t
* env_t
;
2644 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
),
2645 debugstr_w(env
), level
, Info
, cbBuf
, pcbNeeded
);
2647 if(server
!= NULL
&& server
[0]) {
2648 FIXME("server not supported: %s\n", debugstr_w(server
));
2649 SetLastError(ERROR_INVALID_PARAMETER
);
2653 env_t
= validate_envW(env
);
2654 if(!env_t
) return FALSE
; /* environment invalid or unsupported */
2657 WARN("(Level: %d) is ignored in win9x\n", level
);
2658 SetLastError(ERROR_INVALID_LEVEL
);
2662 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2663 needed
= GetSystemDirectoryW(NULL
, 0);
2664 /* add the Size for the Subdirectories */
2665 needed
+= lstrlenW(spoolprtprocsW
);
2666 needed
+= lstrlenW(env_t
->subdir
);
2667 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2669 if(pcbNeeded
) *pcbNeeded
= needed
;
2670 TRACE ("required: 0x%x/%d\n", needed
, needed
);
2671 if (needed
> cbBuf
) {
2672 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2675 if(pcbNeeded
== NULL
) {
2676 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2677 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2678 SetLastError(RPC_X_NULL_REF_POINTER
);
2682 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2683 SetLastError(RPC_X_NULL_REF_POINTER
);
2687 GetSystemDirectoryW((LPWSTR
) Info
, cbBuf
/sizeof(WCHAR
));
2688 /* add the Subdirectories */
2689 lstrcatW((LPWSTR
) Info
, spoolprtprocsW
);
2690 lstrcatW((LPWSTR
) Info
, env_t
->subdir
);
2691 TRACE(" => %s\n", debugstr_w((LPWSTR
) Info
));
2695 /*****************************************************************************
2696 * WINSPOOL_OpenDriverReg [internal]
2698 * opens the registry for the printer drivers depending on the given input
2699 * variable pEnvironment
2702 * the opened hkey on success
2705 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
, BOOL unicode
)
2709 const printenv_t
* env
;
2712 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
), unicode
);
2714 if (!pEnvironment
|| unicode
) {
2715 /* pEnvironment was NULL or an Unicode-String: use it direct */
2716 env
= validate_envW(pEnvironment
);
2720 /* pEnvironment was an ANSI-String: convert to unicode first */
2722 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
2723 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2724 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
2725 env
= validate_envW(buffer
);
2726 HeapFree(GetProcessHeap(), 0, buffer
);
2728 if (!env
) return NULL
;
2730 buffer
= HeapAlloc( GetProcessHeap(), 0,
2731 (strlenW(DriversW
) + strlenW(env
->envname
) +
2732 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2734 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2735 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2736 HeapFree(GetProcessHeap(), 0, buffer
);
2741 /*****************************************************************************
2742 * AddPrinterW [WINSPOOL.@]
2744 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2746 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2750 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2752 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2753 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2754 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2755 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2756 statusW
[] = {'S','t','a','t','u','s',0},
2757 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2759 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2762 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2763 SetLastError(ERROR_INVALID_PARAMETER
);
2767 ERR("Level = %d, unsupported!\n", Level
);
2768 SetLastError(ERROR_INVALID_LEVEL
);
2772 SetLastError(ERROR_INVALID_PARAMETER
);
2775 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2777 ERR("Can't create Printers key\n");
2780 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2781 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2782 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2783 RegCloseKey(hkeyPrinter
);
2784 RegCloseKey(hkeyPrinters
);
2787 RegCloseKey(hkeyPrinter
);
2789 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
2791 ERR("Can't create Drivers key\n");
2792 RegCloseKey(hkeyPrinters
);
2795 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2797 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2798 RegCloseKey(hkeyPrinters
);
2799 RegCloseKey(hkeyDrivers
);
2800 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2803 RegCloseKey(hkeyDriver
);
2804 RegCloseKey(hkeyDrivers
);
2806 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2807 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2808 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2809 RegCloseKey(hkeyPrinters
);
2813 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2815 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2816 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2817 RegCloseKey(hkeyPrinters
);
2820 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2821 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2822 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2824 /* See if we can load the driver. We may need the devmode structure anyway
2827 * Note that DocumentPropertiesW will briefly try to open the printer we
2828 * just create to find a DEVMODEA struct (it will use the WINEPS default
2829 * one in case it is not there, so we are ok).
2831 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2834 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2835 size
= sizeof(DEVMODEW
);
2841 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2843 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2845 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2846 HeapFree(GetProcessHeap(),0,dmW
);
2851 /* set devmode to printer name */
2852 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2856 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2857 and we support these drivers. NT writes DEVMODEW so somehow
2858 we'll need to distinguish between these when we support NT
2862 dmA
= DEVMODEdupWtoA(GetProcessHeap(), dmW
);
2863 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2864 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2865 HeapFree(GetProcessHeap(), 0, dmA
);
2867 HeapFree(GetProcessHeap(), 0, dmW
);
2869 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2870 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2871 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2872 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2874 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2875 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2876 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2877 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2878 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2879 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2880 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2881 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2882 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2883 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2884 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2885 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2886 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2888 RegCloseKey(hkeyPrinter
);
2889 RegCloseKey(hkeyPrinters
);
2890 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2891 ERR("OpenPrinter failing\n");
2897 /*****************************************************************************
2898 * AddPrinterA [WINSPOOL.@]
2900 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2902 UNICODE_STRING pNameW
;
2904 PRINTER_INFO_2W
*piW
;
2905 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2908 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
2910 ERR("Level = %d, unsupported!\n", Level
);
2911 SetLastError(ERROR_INVALID_LEVEL
);
2914 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2915 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2917 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2919 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2920 RtlFreeUnicodeString(&pNameW
);
2925 /*****************************************************************************
2926 * ClosePrinter [WINSPOOL.@]
2928 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2930 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2931 opened_printer_t
*printer
= NULL
;
2934 TRACE("(%p)\n", hPrinter
);
2936 EnterCriticalSection(&printer_handles_cs
);
2938 if ((i
> 0) && (i
<= nb_printer_handles
))
2939 printer
= printer_handles
[i
- 1];
2944 struct list
*cursor
, *cursor2
;
2946 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer
->pm
,
2947 debugstr_w(printer
->pm
? printer
->pm
->dllname
: NULL
),
2948 printer
->hXcv
, debugstr_w(printer
->name
), printer
->doc
);
2951 EndDocPrinter(hPrinter
);
2953 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2955 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2957 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2958 ScheduleJob(hPrinter
, job
->job_id
);
2960 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2962 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
2963 monitor_unload(printer
->pm
);
2964 HeapFree(GetProcessHeap(), 0, printer
->printername
);
2965 HeapFree(GetProcessHeap(), 0, printer
->name
);
2966 HeapFree(GetProcessHeap(), 0, printer
);
2967 printer_handles
[i
- 1] = NULL
;
2970 LeaveCriticalSection(&printer_handles_cs
);
2974 /*****************************************************************************
2975 * DeleteFormA [WINSPOOL.@]
2977 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2979 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2983 /*****************************************************************************
2984 * DeleteFormW [WINSPOOL.@]
2986 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2988 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2992 /*****************************************************************************
2993 * DeletePrinter [WINSPOOL.@]
2995 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2997 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2998 HKEY hkeyPrinters
, hkey
;
3001 SetLastError(ERROR_INVALID_HANDLE
);
3004 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3005 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3006 RegCloseKey(hkeyPrinters
);
3008 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3009 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3010 RegDeleteValueW(hkey
, lpNameW
);
3016 /*****************************************************************************
3017 * SetPrinterA [WINSPOOL.@]
3019 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3022 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
3026 /*****************************************************************************
3027 * SetJobA [WINSPOOL.@]
3029 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3030 LPBYTE pJob
, DWORD Command
)
3034 UNICODE_STRING usBuffer
;
3036 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3038 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3039 are all ignored by SetJob, so we don't bother copying them */
3047 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3048 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3050 JobW
= (LPBYTE
)info1W
;
3051 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3052 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3053 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3054 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3055 info1W
->Status
= info1A
->Status
;
3056 info1W
->Priority
= info1A
->Priority
;
3057 info1W
->Position
= info1A
->Position
;
3058 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3063 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3064 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3066 JobW
= (LPBYTE
)info2W
;
3067 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3068 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3069 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3070 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3071 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3072 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3073 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3074 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3075 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3076 info2W
->Status
= info2A
->Status
;
3077 info2W
->Priority
= info2A
->Priority
;
3078 info2W
->Position
= info2A
->Position
;
3079 info2W
->StartTime
= info2A
->StartTime
;
3080 info2W
->UntilTime
= info2A
->UntilTime
;
3081 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3085 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3086 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3089 SetLastError(ERROR_INVALID_LEVEL
);
3093 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3099 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3100 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3101 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3102 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3103 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3108 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3109 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3110 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3111 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3112 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3113 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3114 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3115 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3116 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3120 HeapFree(GetProcessHeap(), 0, JobW
);
3125 /*****************************************************************************
3126 * SetJobW [WINSPOOL.@]
3128 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3129 LPBYTE pJob
, DWORD Command
)
3134 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3135 FIXME("Ignoring everything other than document title\n");
3137 EnterCriticalSection(&printer_handles_cs
);
3138 job
= get_job(hPrinter
, JobId
);
3148 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3149 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3150 job
->document_title
= strdupW(info1
->pDocument
);
3155 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3156 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3157 job
->document_title
= strdupW(info2
->pDocument
);
3163 SetLastError(ERROR_INVALID_LEVEL
);
3168 LeaveCriticalSection(&printer_handles_cs
);
3172 /*****************************************************************************
3173 * EndDocPrinter [WINSPOOL.@]
3175 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3177 opened_printer_t
*printer
;
3179 TRACE("(%p)\n", hPrinter
);
3181 EnterCriticalSection(&printer_handles_cs
);
3183 printer
= get_opened_printer(hPrinter
);
3186 SetLastError(ERROR_INVALID_HANDLE
);
3192 SetLastError(ERROR_SPL_NO_STARTDOC
);
3196 CloseHandle(printer
->doc
->hf
);
3197 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3198 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3199 printer
->doc
= NULL
;
3202 LeaveCriticalSection(&printer_handles_cs
);
3206 /*****************************************************************************
3207 * EndPagePrinter [WINSPOOL.@]
3209 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3211 FIXME("(%p): stub\n", hPrinter
);
3215 /*****************************************************************************
3216 * StartDocPrinterA [WINSPOOL.@]
3218 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3220 UNICODE_STRING usBuffer
;
3222 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3225 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3226 or one (DOC_INFO_3) extra DWORDs */
3230 doc2W
.JobId
= doc2
->JobId
;
3233 doc2W
.dwMode
= doc2
->dwMode
;
3236 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3237 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3238 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3242 SetLastError(ERROR_INVALID_LEVEL
);
3246 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3248 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3249 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3250 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3255 /*****************************************************************************
3256 * StartDocPrinterW [WINSPOOL.@]
3258 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3260 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3261 opened_printer_t
*printer
;
3262 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3263 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3264 JOB_INFO_1W job_info
;
3265 DWORD needed
, ret
= 0;
3269 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3270 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3271 debugstr_w(doc
->pDatatype
));
3273 if(Level
< 1 || Level
> 3)
3275 SetLastError(ERROR_INVALID_LEVEL
);
3279 EnterCriticalSection(&printer_handles_cs
);
3280 printer
= get_opened_printer(hPrinter
);
3283 SetLastError(ERROR_INVALID_HANDLE
);
3289 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3293 /* Even if we're printing to a file we still add a print job, we'll
3294 just ignore the spool file name */
3296 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3298 ERR("AddJob failed gle %u\n", GetLastError());
3302 if(doc
->pOutputFile
)
3303 filename
= doc
->pOutputFile
;
3305 filename
= addjob
->Path
;
3307 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3308 if(hf
== INVALID_HANDLE_VALUE
)
3311 memset(&job_info
, 0, sizeof(job_info
));
3312 job_info
.pDocument
= doc
->pDocName
;
3313 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3315 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3316 printer
->doc
->hf
= hf
;
3317 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3319 LeaveCriticalSection(&printer_handles_cs
);
3324 /*****************************************************************************
3325 * StartPagePrinter [WINSPOOL.@]
3327 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3329 FIXME("(%p): stub\n", hPrinter
);
3333 /*****************************************************************************
3334 * GetFormA [WINSPOOL.@]
3336 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3337 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3339 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3340 Level
,pForm
,cbBuf
,pcbNeeded
);
3344 /*****************************************************************************
3345 * GetFormW [WINSPOOL.@]
3347 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3348 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3350 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3351 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3355 /*****************************************************************************
3356 * SetFormA [WINSPOOL.@]
3358 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3361 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3365 /*****************************************************************************
3366 * SetFormW [WINSPOOL.@]
3368 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3371 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3375 /*****************************************************************************
3376 * ReadPrinter [WINSPOOL.@]
3378 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3379 LPDWORD pNoBytesRead
)
3381 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3385 /*****************************************************************************
3386 * ResetPrinterA [WINSPOOL.@]
3388 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3390 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3394 /*****************************************************************************
3395 * ResetPrinterW [WINSPOOL.@]
3397 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3399 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3403 /*****************************************************************************
3404 * WINSPOOL_GetDWORDFromReg
3406 * Return DWORD associated with ValueName from hkey.
3408 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3410 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3413 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3415 if(ret
!= ERROR_SUCCESS
) {
3416 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3419 if(type
!= REG_DWORD
) {
3420 ERR("Got type %d\n", type
);
3427 /*****************************************************************************
3428 * get_filename_from_reg [internal]
3430 * Get ValueName from hkey storing result in out
3431 * when the Value in the registry has only a filename, use driverdir as prefix
3432 * outlen is space left in out
3433 * String is stored either as unicode or ascii
3437 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3438 LPBYTE out
, DWORD outlen
, LPDWORD needed
, BOOL unicode
)
3440 WCHAR filename
[MAX_PATH
];
3444 LPWSTR buffer
= filename
;
3448 size
= sizeof(filename
);
3450 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3451 if (ret
== ERROR_MORE_DATA
) {
3452 TRACE("need dynamic buffer: %u\n", size
);
3453 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3455 /* No Memory is bad */
3459 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3462 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3463 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3469 /* do we have a full path ? */
3470 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3471 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3474 /* we must build the full Path */
3476 if ((out
) && (outlen
> dirlen
)) {
3478 lstrcpyW((LPWSTR
)out
, driverdir
);
3482 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3491 /* write the filename */
3493 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3494 if ((out
) && (outlen
>= size
)) {
3495 lstrcpyW((LPWSTR
)out
, ptr
);
3504 size
= WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, NULL
, 0, NULL
, NULL
);
3505 if ((out
) && (outlen
>= size
)) {
3506 WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3514 ptr
+= lstrlenW(ptr
)+1;
3515 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3518 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3520 /* write the multisz-termination */
3521 if (type
== REG_MULTI_SZ
) {
3522 size
= (unicode
) ? sizeof(WCHAR
) : 1;
3525 if (out
&& (outlen
>= size
)) {
3526 memset (out
, 0, size
);
3532 /*****************************************************************************
3533 * WINSPOOL_GetStringFromReg
3535 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3536 * String is stored either as unicode or ascii.
3537 * Bit of a hack here to get the ValueName if we want ascii.
3539 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3540 DWORD buflen
, DWORD
*needed
,
3543 DWORD sz
= buflen
, type
;
3547 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3549 LPSTR ValueNameA
= strdupWtoA(ValueName
);
3550 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
3551 HeapFree(GetProcessHeap(),0,ValueNameA
);
3553 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3554 WARN("Got ret = %d\n", ret
);
3558 /* add space for terminating '\0' */
3559 sz
+= unicode
? sizeof(WCHAR
) : 1;
3563 TRACE("%s: %s\n", debugstr_w(ValueName
), unicode
? debugstr_w((LPCWSTR
)ptr
) : debugstr_a((LPCSTR
)ptr
));
3568 /*****************************************************************************
3569 * WINSPOOL_GetDefaultDevMode
3571 * Get a default DevMode values for wineps.
3575 static void WINSPOOL_GetDefaultDevMode(
3577 DWORD buflen
, DWORD
*needed
,
3581 static const char szwps
[] = "wineps.drv";
3583 /* fill default DEVMODE - should be read from ppd... */
3584 ZeroMemory( &dm
, sizeof(dm
) );
3585 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
3586 dm
.dmSpecVersion
= DM_SPECVERSION
;
3587 dm
.dmDriverVersion
= 1;
3588 dm
.dmSize
= sizeof(DEVMODEA
);
3589 dm
.dmDriverExtra
= 0;
3591 DM_ORIENTATION
| DM_PAPERSIZE
|
3592 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3595 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3596 DM_YRESOLUTION
| DM_TTOPTION
;
3598 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3599 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3600 dm
.u1
.s1
.dmPaperLength
= 2970;
3601 dm
.u1
.s1
.dmPaperWidth
= 2100;
3605 dm
.dmDefaultSource
= DMBIN_AUTO
;
3606 dm
.dmPrintQuality
= DMRES_MEDIUM
;
3609 dm
.dmYResolution
= 300; /* 300dpi */
3610 dm
.dmTTOption
= DMTT_BITMAP
;
3613 /* dm.dmLogPixels */
3614 /* dm.dmBitsPerPel */
3615 /* dm.dmPelsWidth */
3616 /* dm.dmPelsHeight */
3617 /* dm.dmDisplayFlags */
3618 /* dm.dmDisplayFrequency */
3619 /* dm.dmICMMethod */
3620 /* dm.dmICMIntent */
3621 /* dm.dmMediaType */
3622 /* dm.dmDitherType */
3623 /* dm.dmReserved1 */
3624 /* dm.dmReserved2 */
3625 /* dm.dmPanningWidth */
3626 /* dm.dmPanningHeight */
3629 if(buflen
>= sizeof(DEVMODEW
)) {
3630 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
3631 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
3632 HeapFree(GetProcessHeap(),0,pdmW
);
3634 *needed
= sizeof(DEVMODEW
);
3638 if(buflen
>= sizeof(DEVMODEA
)) {
3639 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
3641 *needed
= sizeof(DEVMODEA
);
3645 /*****************************************************************************
3646 * WINSPOOL_GetDevModeFromReg
3648 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3649 * DevMode is stored either as unicode or ascii.
3651 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3653 DWORD buflen
, DWORD
*needed
,
3656 DWORD sz
= buflen
, type
;
3659 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3660 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3661 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3662 if (sz
< sizeof(DEVMODEA
))
3664 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3667 /* ensures that dmSize is not erratically bogus if registry is invalid */
3668 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3669 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3671 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3673 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3674 memcpy(ptr
, dmW
, sz
);
3675 HeapFree(GetProcessHeap(),0,dmW
);
3682 /*********************************************************************
3683 * WINSPOOL_GetPrinter_1
3685 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3686 * The strings are either stored as unicode or ascii.
3688 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3689 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3692 DWORD size
, left
= cbBuf
;
3693 BOOL space
= (cbBuf
> 0);
3698 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3700 if(space
&& size
<= left
) {
3701 pi1
->pName
= (LPWSTR
)ptr
;
3709 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3710 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3712 if(space
&& size
<= left
) {
3713 pi1
->pDescription
= (LPWSTR
)ptr
;
3721 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3723 if(space
&& size
<= left
) {
3724 pi1
->pComment
= (LPWSTR
)ptr
;
3732 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3734 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3735 memset(pi1
, 0, sizeof(*pi1
));
3739 /*********************************************************************
3740 * WINSPOOL_GetPrinter_2
3742 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3743 * The strings are either stored as unicode or ascii.
3745 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3746 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3749 DWORD size
, left
= cbBuf
;
3750 BOOL space
= (cbBuf
> 0);
3755 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3757 if(space
&& size
<= left
) {
3758 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3765 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
3767 if(space
&& size
<= left
) {
3768 pi2
->pShareName
= (LPWSTR
)ptr
;
3775 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3777 if(space
&& size
<= left
) {
3778 pi2
->pPortName
= (LPWSTR
)ptr
;
3785 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
3787 if(space
&& size
<= left
) {
3788 pi2
->pDriverName
= (LPWSTR
)ptr
;
3795 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3797 if(space
&& size
<= left
) {
3798 pi2
->pComment
= (LPWSTR
)ptr
;
3805 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
3807 if(space
&& size
<= left
) {
3808 pi2
->pLocation
= (LPWSTR
)ptr
;
3815 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
3817 if(space
&& size
<= left
) {
3818 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3827 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
3828 if(space
&& size
<= left
) {
3829 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3836 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
3838 if(space
&& size
<= left
) {
3839 pi2
->pSepFile
= (LPWSTR
)ptr
;
3846 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
3848 if(space
&& size
<= left
) {
3849 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3856 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
3858 if(space
&& size
<= left
) {
3859 pi2
->pDatatype
= (LPWSTR
)ptr
;
3866 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
3868 if(space
&& size
<= left
) {
3869 pi2
->pParameters
= (LPWSTR
)ptr
;
3877 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3878 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3879 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3880 "Default Priority");
3881 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3882 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3885 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3886 memset(pi2
, 0, sizeof(*pi2
));
3891 /*********************************************************************
3892 * WINSPOOL_GetPrinter_4
3894 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3896 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3897 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3900 DWORD size
, left
= cbBuf
;
3901 BOOL space
= (cbBuf
> 0);
3906 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3908 if(space
&& size
<= left
) {
3909 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3917 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3920 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3921 memset(pi4
, 0, sizeof(*pi4
));
3926 /*********************************************************************
3927 * WINSPOOL_GetPrinter_5
3929 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3931 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3932 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3935 DWORD size
, left
= cbBuf
;
3936 BOOL space
= (cbBuf
> 0);
3941 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3943 if(space
&& size
<= left
) {
3944 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3951 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3953 if(space
&& size
<= left
) {
3954 pi5
->pPortName
= (LPWSTR
)ptr
;
3962 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3963 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3965 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3969 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3970 memset(pi5
, 0, sizeof(*pi5
));
3975 /*****************************************************************************
3976 * WINSPOOL_GetPrinter
3978 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3979 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3980 * just a collection of pointers to strings.
3982 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3983 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
3986 DWORD size
, needed
= 0;
3988 HKEY hkeyPrinter
, hkeyPrinters
;
3991 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3993 if (!(name
= get_opened_printer_name(hPrinter
))) {
3994 SetLastError(ERROR_INVALID_HANDLE
);
3998 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4000 ERR("Can't create Printers key\n");
4003 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
4005 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4006 RegCloseKey(hkeyPrinters
);
4007 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4014 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4016 size
= sizeof(PRINTER_INFO_2W
);
4018 ptr
= pPrinter
+ size
;
4020 memset(pPrinter
, 0, size
);
4025 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
4033 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4035 size
= sizeof(PRINTER_INFO_4W
);
4037 ptr
= pPrinter
+ size
;
4039 memset(pPrinter
, 0, size
);
4044 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
4053 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4055 size
= sizeof(PRINTER_INFO_5W
);
4057 ptr
= pPrinter
+ size
;
4059 memset(pPrinter
, 0, size
);
4065 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
4072 FIXME("Unimplemented level %d\n", Level
);
4073 SetLastError(ERROR_INVALID_LEVEL
);
4074 RegCloseKey(hkeyPrinters
);
4075 RegCloseKey(hkeyPrinter
);
4079 RegCloseKey(hkeyPrinter
);
4080 RegCloseKey(hkeyPrinters
);
4082 TRACE("returning %d needed = %d\n", ret
, needed
);
4083 if(pcbNeeded
) *pcbNeeded
= needed
;
4085 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4089 /*****************************************************************************
4090 * GetPrinterW [WINSPOOL.@]
4092 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4093 DWORD cbBuf
, LPDWORD pcbNeeded
)
4095 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4099 /*****************************************************************************
4100 * GetPrinterA [WINSPOOL.@]
4102 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4103 DWORD cbBuf
, LPDWORD pcbNeeded
)
4105 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4109 /*****************************************************************************
4110 * WINSPOOL_EnumPrinters
4112 * Implementation of EnumPrintersA|W
4114 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
4115 DWORD dwLevel
, LPBYTE lpbPrinters
,
4116 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4117 LPDWORD lpdwReturned
, BOOL unicode
)
4120 HKEY hkeyPrinters
, hkeyPrinter
;
4121 WCHAR PrinterName
[255];
4122 DWORD needed
= 0, number
= 0;
4123 DWORD used
, i
, left
;
4127 memset(lpbPrinters
, 0, cbBuf
);
4133 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4134 if(dwType
== PRINTER_ENUM_DEFAULT
)
4137 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4138 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4139 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4141 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4149 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4150 FIXME("dwType = %08x\n", dwType
);
4151 SetLastError(ERROR_INVALID_FLAGS
);
4155 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4157 ERR("Can't create Printers key\n");
4161 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4162 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4163 RegCloseKey(hkeyPrinters
);
4164 ERR("Can't query Printers key\n");
4167 TRACE("Found %d printers\n", number
);
4171 used
= number
* sizeof(PRINTER_INFO_1W
);
4174 used
= number
* sizeof(PRINTER_INFO_2W
);
4177 used
= number
* sizeof(PRINTER_INFO_4W
);
4180 used
= number
* sizeof(PRINTER_INFO_5W
);
4184 SetLastError(ERROR_INVALID_LEVEL
);
4185 RegCloseKey(hkeyPrinters
);
4188 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4190 for(i
= 0; i
< number
; i
++) {
4191 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) !=
4193 ERR("Can't enum key number %d\n", i
);
4194 RegCloseKey(hkeyPrinters
);
4197 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4198 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4200 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4201 RegCloseKey(hkeyPrinters
);
4206 buf
= lpbPrinters
+ used
;
4207 left
= cbBuf
- used
;
4215 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4216 left
, &needed
, unicode
);
4218 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4221 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4222 left
, &needed
, unicode
);
4224 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4227 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4228 left
, &needed
, unicode
);
4230 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4233 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4234 left
, &needed
, unicode
);
4236 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4239 ERR("Shouldn't be here!\n");
4240 RegCloseKey(hkeyPrinter
);
4241 RegCloseKey(hkeyPrinters
);
4244 RegCloseKey(hkeyPrinter
);
4246 RegCloseKey(hkeyPrinters
);
4253 memset(lpbPrinters
, 0, cbBuf
);
4254 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4258 *lpdwReturned
= number
;
4259 SetLastError(ERROR_SUCCESS
);
4264 /******************************************************************
4265 * EnumPrintersW [WINSPOOL.@]
4267 * Enumerates the available printers, print servers and print
4268 * providers, depending on the specified flags, name and level.
4272 * If level is set to 1:
4273 * Returns an array of PRINTER_INFO_1 data structures in the
4274 * lpbPrinters buffer.
4276 * If level is set to 2:
4277 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4278 * Returns an array of PRINTER_INFO_2 data structures in the
4279 * lpbPrinters buffer. Note that according to MSDN also an
4280 * OpenPrinter should be performed on every remote printer.
4282 * If level is set to 4 (officially WinNT only):
4283 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4284 * Fast: Only the registry is queried to retrieve printer names,
4285 * no connection to the driver is made.
4286 * Returns an array of PRINTER_INFO_4 data structures in the
4287 * lpbPrinters buffer.
4289 * If level is set to 5 (officially WinNT4/Win9x only):
4290 * Fast: Only the registry is queried to retrieve printer names,
4291 * no connection to the driver is made.
4292 * Returns an array of PRINTER_INFO_5 data structures in the
4293 * lpbPrinters buffer.
4295 * If level set to 3 or 6+:
4296 * returns zero (failure!)
4298 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4302 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4303 * - Only levels 2, 4 and 5 are implemented at the moment.
4304 * - 16-bit printer drivers are not enumerated.
4305 * - Returned amount of bytes used/needed does not match the real Windoze
4306 * implementation (as in this implementation, all strings are part
4307 * of the buffer, whereas Win32 keeps them somewhere else)
4308 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4311 * - In a regular Wine installation, no registry settings for printers
4312 * exist, which makes this function return an empty list.
4314 BOOL WINAPI
EnumPrintersW(
4315 DWORD dwType
, /* [in] Types of print objects to enumerate */
4316 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4317 DWORD dwLevel
, /* [in] type of printer info structure */
4318 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4319 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4320 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4321 LPDWORD lpdwReturned
/* [out] number of entries returned */
4324 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4325 lpdwNeeded
, lpdwReturned
, TRUE
);
4328 /******************************************************************
4329 * EnumPrintersA [WINSPOOL.@]
4332 BOOL WINAPI
EnumPrintersA(DWORD dwType
, LPSTR lpszName
,
4333 DWORD dwLevel
, LPBYTE lpbPrinters
,
4334 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4335 LPDWORD lpdwReturned
)
4337 BOOL ret
, unicode
= FALSE
;
4338 UNICODE_STRING lpszNameW
;
4341 pwstrNameW
= asciitounicode(&lpszNameW
,lpszName
);
4342 if(!cbBuf
) unicode
= TRUE
; /* return a buffer that's big enough for the unicode version */
4343 ret
= WINSPOOL_EnumPrinters(dwType
, pwstrNameW
, dwLevel
, lpbPrinters
, cbBuf
,
4344 lpdwNeeded
, lpdwReturned
, unicode
);
4345 RtlFreeUnicodeString(&lpszNameW
);
4349 /*****************************************************************************
4350 * WINSPOOL_GetDriverInfoFromReg [internal]
4352 * Enters the information from the registry into the DRIVER_INFO struct
4355 * zero if the printer driver does not exist in the registry
4356 * (only if Level > 1) otherwise nonzero
4358 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4361 const printenv_t
* env
,
4363 LPBYTE ptr
, /* DRIVER_INFO */
4364 LPBYTE pDriverStrings
, /* strings buffer */
4365 DWORD cbBuf
, /* size of string buffer */
4366 LPDWORD pcbNeeded
, /* space needed for str. */
4367 BOOL unicode
) /* type of strings */
4371 WCHAR driverdir
[MAX_PATH
];
4373 LPBYTE strPtr
= pDriverStrings
;
4374 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4376 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers
,
4377 debugstr_w(DriverName
), env
,
4378 Level
, di
, pDriverStrings
, cbBuf
, unicode
);
4380 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4383 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4384 if (*pcbNeeded
<= cbBuf
)
4385 strcpyW((LPWSTR
)strPtr
, DriverName
);
4389 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0, NULL
, NULL
);
4390 if (*pcbNeeded
<= cbBuf
)
4391 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
4394 /* pName for level 1 has a different offset! */
4396 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4400 /* .cVersion and .pName for level > 1 */
4402 di
->cVersion
= env
->driverversion
;
4403 di
->pName
= (LPWSTR
) strPtr
;
4404 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4407 /* Reserve Space for the largest subdir and a Backslash*/
4408 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4409 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4410 /* Should never Fail */
4413 lstrcatW(driverdir
, env
->versionsubdir
);
4414 lstrcatW(driverdir
, backslashW
);
4416 /* dirlen must not include the terminating zero */
4417 dirlen
= (unicode
) ? lstrlenW(driverdir
) * sizeof(WCHAR
) :
4418 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, NULL
, 0, NULL
, NULL
) -1;
4420 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4421 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4422 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4428 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4430 size
= WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, NULL
, 0, NULL
, NULL
);
4433 if (*pcbNeeded
<= cbBuf
) {
4435 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4439 WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, (LPSTR
)strPtr
, size
, NULL
, NULL
);
4441 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4442 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4445 /* .pDriverPath is the Graphics rendering engine.
4446 The full Path is required to avoid a crash in some apps */
4447 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
, unicode
)) {
4449 if (*pcbNeeded
<= cbBuf
)
4450 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
, unicode
);
4452 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4453 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4456 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4457 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
, unicode
)) {
4459 if (*pcbNeeded
<= cbBuf
)
4460 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
, unicode
);
4462 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4463 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4466 /* .pConfigFile is the Driver user Interface */
4467 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
, unicode
)) {
4469 if (*pcbNeeded
<= cbBuf
)
4470 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
, unicode
);
4472 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4473 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4477 RegCloseKey(hkeyDriver
);
4478 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4483 RegCloseKey(hkeyDriver
);
4484 FIXME("level 5: incomplete\n");
4489 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
, unicode
)) {
4491 if (*pcbNeeded
<= cbBuf
)
4492 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
, unicode
);
4494 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4495 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4498 /* .pDependentFiles */
4499 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
, unicode
)) {
4501 if (*pcbNeeded
<= cbBuf
)
4502 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
, unicode
);
4504 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4505 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4508 /* .pMonitorName is the optional Language Monitor */
4509 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
, unicode
)) {
4511 if (*pcbNeeded
<= cbBuf
)
4512 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
, unicode
);
4514 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4515 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4518 /* .pDefaultDataType */
4519 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
, unicode
)) {
4521 if(*pcbNeeded
<= cbBuf
)
4522 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
, unicode
);
4524 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4525 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4529 RegCloseKey(hkeyDriver
);
4530 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4534 /* .pszzPreviousNames */
4535 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
, unicode
)) {
4537 if(*pcbNeeded
<= cbBuf
)
4538 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
, unicode
);
4540 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4541 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4545 RegCloseKey(hkeyDriver
);
4546 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4550 /* support is missing, but not important enough for a FIXME */
4551 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4554 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
, unicode
)) {
4556 if(*pcbNeeded
<= cbBuf
)
4557 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
, unicode
);
4559 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4560 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4564 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
, unicode
)) {
4566 if(*pcbNeeded
<= cbBuf
)
4567 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
, unicode
);
4569 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4570 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4573 /* .pszHardwareID */
4574 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
, unicode
)) {
4576 if(*pcbNeeded
<= cbBuf
)
4577 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
, unicode
);
4579 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4580 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4584 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
, unicode
)) {
4586 if(*pcbNeeded
<= cbBuf
)
4587 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
, unicode
);
4589 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4590 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4594 RegCloseKey(hkeyDriver
);
4598 /* support is missing, but not important enough for a FIXME */
4599 TRACE("level 8: incomplete\n");
4601 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4602 RegCloseKey(hkeyDriver
);
4606 /*****************************************************************************
4607 * WINSPOOL_GetPrinterDriver
4609 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPCWSTR pEnvironment
,
4610 DWORD Level
, LPBYTE pDriverInfo
,
4611 DWORD cbBuf
, LPDWORD pcbNeeded
,
4615 WCHAR DriverName
[100];
4616 DWORD ret
, type
, size
, needed
= 0;
4618 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4619 const printenv_t
* env
;
4621 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4622 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4625 if (!(name
= get_opened_printer_name(hPrinter
))) {
4626 SetLastError(ERROR_INVALID_HANDLE
);
4630 if (Level
< 1 || Level
== 7 || Level
> 8) {
4631 SetLastError(ERROR_INVALID_LEVEL
);
4635 env
= validate_envW(pEnvironment
);
4636 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4638 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4640 ERR("Can't create Printers key\n");
4643 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4645 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4646 RegCloseKey(hkeyPrinters
);
4647 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4650 size
= sizeof(DriverName
);
4652 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4653 (LPBYTE
)DriverName
, &size
);
4654 RegCloseKey(hkeyPrinter
);
4655 RegCloseKey(hkeyPrinters
);
4656 if(ret
!= ERROR_SUCCESS
) {
4657 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4661 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
4663 ERR("Can't create Drivers key\n");
4667 size
= di_sizeof
[Level
];
4668 if ((size
<= cbBuf
) && pDriverInfo
)
4669 ptr
= pDriverInfo
+ size
;
4671 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4672 env
, Level
, pDriverInfo
, ptr
,
4673 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4674 &needed
, unicode
)) {
4675 RegCloseKey(hkeyDrivers
);
4679 RegCloseKey(hkeyDrivers
);
4681 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4682 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4683 if(cbBuf
>= needed
) return TRUE
;
4684 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4688 /*****************************************************************************
4689 * GetPrinterDriverA [WINSPOOL.@]
4691 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4692 DWORD Level
, LPBYTE pDriverInfo
,
4693 DWORD cbBuf
, LPDWORD pcbNeeded
)
4696 UNICODE_STRING pEnvW
;
4699 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4700 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
4701 cbBuf
, pcbNeeded
, FALSE
);
4702 RtlFreeUnicodeString(&pEnvW
);
4705 /*****************************************************************************
4706 * GetPrinterDriverW [WINSPOOL.@]
4708 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4709 DWORD Level
, LPBYTE pDriverInfo
,
4710 DWORD cbBuf
, LPDWORD pcbNeeded
)
4712 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
4713 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
4716 /*****************************************************************************
4717 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4719 * Return the PATH for the Printer-Drivers (UNICODE)
4722 * pName [I] Servername (NT only) or NULL (local Computer)
4723 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4724 * Level [I] Structure-Level (must be 1)
4725 * pDriverDirectory [O] PTR to Buffer that receives the Result
4726 * cbBuf [I] Size of Buffer at pDriverDirectory
4727 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4728 * required for pDriverDirectory
4731 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4732 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4733 * if cbBuf is too small
4735 * Native Values returned in pDriverDirectory on Success:
4736 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4737 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4738 *| win9x(Windows 4.0): "%winsysdir%"
4740 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4743 *- Only NULL or "" is supported for pName
4746 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4747 DWORD Level
, LPBYTE pDriverDirectory
,
4748 DWORD cbBuf
, LPDWORD pcbNeeded
)
4751 const printenv_t
* env
;
4753 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4754 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4755 if(pName
!= NULL
&& pName
[0]) {
4756 FIXME("pName unsupported: %s\n", debugstr_w(pName
));
4757 SetLastError(ERROR_INVALID_PARAMETER
);
4761 env
= validate_envW(pEnvironment
);
4762 if(!env
) return FALSE
; /* pEnvironment invalid or unsupported */
4765 WARN("(Level: %d) is ignored in win9x\n", Level
);
4766 SetLastError(ERROR_INVALID_LEVEL
);
4770 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4771 needed
= GetSystemDirectoryW(NULL
, 0);
4772 /* add the Size for the Subdirectories */
4773 needed
+= lstrlenW(spooldriversW
);
4774 needed
+= lstrlenW(env
->subdir
);
4775 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
4778 *pcbNeeded
= needed
;
4779 TRACE("required: 0x%x/%d\n", needed
, needed
);
4780 if(needed
> cbBuf
) {
4781 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4784 if(pcbNeeded
== NULL
) {
4785 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4786 SetLastError(RPC_X_NULL_REF_POINTER
);
4789 if(pDriverDirectory
== NULL
) {
4790 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4791 SetLastError(ERROR_INVALID_USER_BUFFER
);
4795 GetSystemDirectoryW((LPWSTR
) pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
4796 /* add the Subdirectories */
4797 lstrcatW((LPWSTR
) pDriverDirectory
, spooldriversW
);
4798 lstrcatW((LPWSTR
) pDriverDirectory
, env
->subdir
);
4799 TRACE(" => %s\n", debugstr_w((LPWSTR
) pDriverDirectory
));
4804 /*****************************************************************************
4805 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4807 * Return the PATH for the Printer-Drivers (ANSI)
4809 * See GetPrinterDriverDirectoryW.
4812 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4815 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4816 DWORD Level
, LPBYTE pDriverDirectory
,
4817 DWORD cbBuf
, LPDWORD pcbNeeded
)
4819 UNICODE_STRING nameW
, environmentW
;
4822 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4823 WCHAR
*driverDirectoryW
= NULL
;
4825 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4826 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4828 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4830 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4831 else nameW
.Buffer
= NULL
;
4832 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4833 else environmentW
.Buffer
= NULL
;
4835 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4836 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4839 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4840 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4842 *pcbNeeded
= needed
;
4843 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4845 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4847 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4849 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4850 RtlFreeUnicodeString(&environmentW
);
4851 RtlFreeUnicodeString(&nameW
);
4856 /*****************************************************************************
4857 * AddPrinterDriverA [WINSPOOL.@]
4859 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4862 HKEY hkeyDrivers
, hkeyName
;
4863 static CHAR empty
[] = "",
4866 TRACE("(%s,%d,%p)\n",debugstr_a(pName
),level
,pDriverInfo
);
4868 if(level
!= 2 && level
!= 3) {
4869 SetLastError(ERROR_INVALID_LEVEL
);
4872 if ((pName
) && (pName
[0])) {
4873 FIXME("pName= %s - unsupported\n", debugstr_a(pName
));
4874 SetLastError(ERROR_INVALID_PARAMETER
);
4878 WARN("pDriverInfo == NULL\n");
4879 SetLastError(ERROR_INVALID_PARAMETER
);
4884 di3
= *(DRIVER_INFO_3A
*)pDriverInfo
;
4886 memset(&di3
, 0, sizeof(di3
));
4887 memcpy(&di3
, pDriverInfo
, sizeof(DRIVER_INFO_2A
));
4890 if(!di3
.pName
|| !di3
.pDriverPath
|| !di3
.pConfigFile
||
4892 SetLastError(ERROR_INVALID_PARAMETER
);
4896 if(!di3
.pDefaultDataType
) di3
.pDefaultDataType
= empty
;
4897 if(!di3
.pDependentFiles
) di3
.pDependentFiles
= nullnull
;
4898 if(!di3
.pHelpFile
) di3
.pHelpFile
= empty
;
4899 if(!di3
.pMonitorName
) di3
.pMonitorName
= empty
;
4901 hkeyDrivers
= WINSPOOL_OpenDriverReg(di3
.pEnvironment
, FALSE
);
4904 ERR("Can't create Drivers key\n");
4908 if(level
== 2) { /* apparently can't overwrite with level2 */
4909 if(RegOpenKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) == ERROR_SUCCESS
) {
4910 RegCloseKey(hkeyName
);
4911 RegCloseKey(hkeyDrivers
);
4912 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3
.pName
));
4913 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
4917 if(RegCreateKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) != ERROR_SUCCESS
) {
4918 RegCloseKey(hkeyDrivers
);
4919 ERR("Can't create Name key\n");
4922 RegSetValueExA(hkeyName
, "Configuration File", 0, REG_SZ
, (LPBYTE
) di3
.pConfigFile
,
4923 lstrlenA(di3
.pConfigFile
) + 1);
4924 RegSetValueExA(hkeyName
, "Data File", 0, REG_SZ
, (LPBYTE
) di3
.pDataFile
, lstrlenA(di3
.pDataFile
) + 1);
4925 RegSetValueExA(hkeyName
, "Driver", 0, REG_SZ
, (LPBYTE
) di3
.pDriverPath
, lstrlenA(di3
.pDriverPath
) + 1);
4926 RegSetValueExA(hkeyName
, "Version", 0, REG_DWORD
, (LPBYTE
) &di3
.cVersion
,
4928 RegSetValueExA(hkeyName
, "Datatype", 0, REG_SZ
, (LPBYTE
) di3
.pDefaultDataType
, lstrlenA(di3
.pDefaultDataType
));
4929 RegSetValueExA(hkeyName
, "Dependent Files", 0, REG_MULTI_SZ
,
4930 (LPBYTE
) di3
.pDependentFiles
, multi_sz_lenA(di3
.pDependentFiles
));
4931 RegSetValueExA(hkeyName
, "Help File", 0, REG_SZ
, (LPBYTE
) di3
.pHelpFile
, lstrlenA(di3
.pHelpFile
) + 1);
4932 RegSetValueExA(hkeyName
, "Monitor", 0, REG_SZ
, (LPBYTE
) di3
.pMonitorName
, lstrlenA(di3
.pMonitorName
) + 1);
4933 RegCloseKey(hkeyName
);
4934 RegCloseKey(hkeyDrivers
);
4939 /*****************************************************************************
4940 * AddPrinterDriverW [WINSPOOL.@]
4942 BOOL WINAPI
AddPrinterDriverW(LPWSTR printerName
,DWORD level
,
4945 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName
),
4950 /*****************************************************************************
4951 * AddPrintProcessorA [WINSPOOL.@]
4953 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4954 LPSTR pPrintProcessorName
)
4956 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4957 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4961 /*****************************************************************************
4962 * AddPrintProcessorW [WINSPOOL.@]
4964 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4965 LPWSTR pPrintProcessorName
)
4967 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4968 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4972 /*****************************************************************************
4973 * AddPrintProvidorA [WINSPOOL.@]
4975 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4977 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4981 /*****************************************************************************
4982 * AddPrintProvidorW [WINSPOOL.@]
4984 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4986 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4990 /*****************************************************************************
4991 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4993 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4994 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4996 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4997 pDevModeOutput
, pDevModeInput
);
5001 /*****************************************************************************
5002 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5004 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5005 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5007 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5008 pDevModeOutput
, pDevModeInput
);
5012 /*****************************************************************************
5013 * PrinterProperties [WINSPOOL.@]
5015 * Displays a dialog to set the properties of the printer.
5018 * nonzero on success or zero on failure
5021 * implemented as stub only
5023 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5024 HANDLE hPrinter
/* [in] handle to printer object */
5026 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5027 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5031 /*****************************************************************************
5032 * EnumJobsA [WINSPOOL.@]
5035 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5036 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5039 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5040 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5042 if(pcbNeeded
) *pcbNeeded
= 0;
5043 if(pcReturned
) *pcReturned
= 0;
5048 /*****************************************************************************
5049 * EnumJobsW [WINSPOOL.@]
5052 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5053 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5056 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5057 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5059 if(pcbNeeded
) *pcbNeeded
= 0;
5060 if(pcReturned
) *pcReturned
= 0;
5064 /*****************************************************************************
5065 * WINSPOOL_EnumPrinterDrivers [internal]
5067 * Delivers information about all printer drivers installed on the
5068 * localhost or a given server
5071 * nonzero on success or zero on failure. If the buffer for the returned
5072 * information is too small the function will return an error
5075 * - only implemented for localhost, foreign hosts will return an error
5077 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5078 DWORD Level
, LPBYTE pDriverInfo
,
5079 DWORD cbBuf
, LPDWORD pcbNeeded
,
5080 LPDWORD pcReturned
, BOOL unicode
)
5083 DWORD i
, needed
, number
= 0, size
= 0;
5084 WCHAR DriverNameW
[255];
5086 const printenv_t
* env
;
5088 TRACE("%s,%s,%d,%p,%d,%d\n",
5089 debugstr_w(pName
), debugstr_w(pEnvironment
),
5090 Level
, pDriverInfo
, cbBuf
, unicode
);
5092 /* check for local drivers */
5093 if((pName
) && (pName
[0])) {
5094 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5095 SetLastError(ERROR_ACCESS_DENIED
);
5099 env
= validate_envW(pEnvironment
);
5100 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5102 /* check input parameter */
5103 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5104 SetLastError(ERROR_INVALID_LEVEL
);
5108 /* initialize return values */
5110 memset( pDriverInfo
, 0, cbBuf
);
5114 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
5116 ERR("Can't open Drivers key\n");
5120 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
5121 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5122 RegCloseKey(hkeyDrivers
);
5123 ERR("Can't query Drivers key\n");
5126 TRACE("Found %d Drivers\n", number
);
5128 /* get size of single struct
5129 * unicode and ascii structure have the same size
5131 size
= di_sizeof
[Level
];
5133 /* calculate required buffer size */
5134 *pcbNeeded
= size
* number
;
5136 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
5138 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
5139 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
))
5141 ERR("Can't enum key number %d\n", i
);
5142 RegCloseKey(hkeyDrivers
);
5145 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5147 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
5148 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5149 &needed
, unicode
)) {
5150 RegCloseKey(hkeyDrivers
);
5153 (*pcbNeeded
) += needed
;
5156 RegCloseKey(hkeyDrivers
);
5158 if(cbBuf
< *pcbNeeded
){
5159 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5163 *pcReturned
= number
;
5167 /*****************************************************************************
5168 * EnumPrinterDriversW [WINSPOOL.@]
5170 * see function EnumPrinterDrivers for RETURNS, BUGS
5172 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5173 LPBYTE pDriverInfo
, DWORD cbBuf
,
5174 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5176 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5177 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
5180 /*****************************************************************************
5181 * EnumPrinterDriversA [WINSPOOL.@]
5183 * see function EnumPrinterDrivers for RETURNS, BUGS
5185 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5186 LPBYTE pDriverInfo
, DWORD cbBuf
,
5187 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5189 UNICODE_STRING pNameW
, pEnvironmentW
;
5190 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5192 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5193 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5195 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
5196 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
5198 RtlFreeUnicodeString(&pNameW
);
5199 RtlFreeUnicodeString(&pEnvironmentW
);
5204 /******************************************************************************
5205 * EnumPortsA (WINSPOOL.@)
5210 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5211 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5214 LPBYTE bufferW
= NULL
;
5215 LPWSTR nameW
= NULL
;
5217 DWORD numentries
= 0;
5220 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5221 cbBuf
, pcbNeeded
, pcReturned
);
5223 /* convert servername to unicode */
5225 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5226 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5227 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5229 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5230 needed
= cbBuf
* sizeof(WCHAR
);
5231 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5232 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5234 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5235 if (pcbNeeded
) needed
= *pcbNeeded
;
5236 /* HeapReAlloc return NULL, when bufferW was NULL */
5237 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5238 HeapAlloc(GetProcessHeap(), 0, needed
);
5240 /* Try again with the large Buffer */
5241 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5243 needed
= pcbNeeded
? *pcbNeeded
: 0;
5244 numentries
= pcReturned
? *pcReturned
: 0;
5247 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5248 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5251 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5252 DWORD entrysize
= 0;
5255 LPPORT_INFO_2W pi2w
;
5256 LPPORT_INFO_2A pi2a
;
5259 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5261 /* First pass: calculate the size for all Entries */
5262 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5263 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5265 while (index
< numentries
) {
5267 needed
+= entrysize
; /* PORT_INFO_?A */
5268 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5270 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5271 NULL
, 0, NULL
, NULL
);
5273 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5274 NULL
, 0, NULL
, NULL
);
5275 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5276 NULL
, 0, NULL
, NULL
);
5278 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5279 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5280 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5283 /* check for errors and quit on failure */
5284 if (cbBuf
< needed
) {
5285 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5289 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5290 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5291 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5292 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5293 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5295 /* Second Pass: Fill the User Buffer (if we have one) */
5296 while ((index
< numentries
) && pPorts
) {
5298 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5299 pi2a
->pPortName
= ptr
;
5300 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5301 ptr
, cbBuf
, NULL
, NULL
);
5305 pi2a
->pMonitorName
= ptr
;
5306 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5307 ptr
, cbBuf
, NULL
, NULL
);
5311 pi2a
->pDescription
= ptr
;
5312 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5313 ptr
, cbBuf
, NULL
, NULL
);
5317 pi2a
->fPortType
= pi2w
->fPortType
;
5318 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5321 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5322 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5323 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5328 if (pcbNeeded
) *pcbNeeded
= needed
;
5329 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5331 HeapFree(GetProcessHeap(), 0, nameW
);
5332 HeapFree(GetProcessHeap(), 0, bufferW
);
5334 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5335 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5341 /******************************************************************************
5342 * EnumPortsW (WINSPOOL.@)
5344 * Enumerate available Ports
5347 * name [I] Servername or NULL (local Computer)
5348 * level [I] Structure-Level (1 or 2)
5349 * buffer [O] PTR to Buffer that receives the Result
5350 * bufsize [I] Size of Buffer at buffer
5351 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5352 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5356 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5360 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5363 DWORD numentries
= 0;
5366 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5367 cbBuf
, pcbNeeded
, pcReturned
);
5369 if (pName
&& (pName
[0])) {
5370 FIXME("not implemented for Server %s\n", debugstr_w(pName
));
5371 SetLastError(ERROR_ACCESS_DENIED
);
5375 /* Level is not checked in win9x */
5376 if (!Level
|| (Level
> 2)) {
5377 WARN("level (%d) is ignored in win9x\n", Level
);
5378 SetLastError(ERROR_INVALID_LEVEL
);
5382 SetLastError(RPC_X_NULL_REF_POINTER
);
5386 EnterCriticalSection(&monitor_handles_cs
);
5389 /* Scan all local Ports */
5391 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
5393 /* we calculated the needed buffersize. now do the error-checks */
5394 if (cbBuf
< needed
) {
5395 monitor_unloadall();
5396 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5397 goto emP_cleanup_cs
;
5399 else if (!pPorts
|| !pcReturned
) {
5400 monitor_unloadall();
5401 SetLastError(RPC_X_NULL_REF_POINTER
);
5402 goto emP_cleanup_cs
;
5405 /* Fill the Buffer */
5406 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
5408 monitor_unloadall();
5411 LeaveCriticalSection(&monitor_handles_cs
);
5414 if (pcbNeeded
) *pcbNeeded
= needed
;
5415 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5417 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5418 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5423 /******************************************************************************
5424 * GetDefaultPrinterW (WINSPOOL.@)
5427 * This function must read the value from data 'device' of key
5428 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5430 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5434 WCHAR
*buffer
, *ptr
;
5438 SetLastError(ERROR_INVALID_PARAMETER
);
5442 /* make the buffer big enough for the stuff from the profile/registry,
5443 * the content must fit into the local buffer to compute the correct
5444 * size even if the extern buffer is too small or not given.
5445 * (20 for ,driver,port) */
5447 len
= max(100, (insize
+ 20));
5448 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5450 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5452 SetLastError (ERROR_FILE_NOT_FOUND
);
5456 TRACE("%s\n", debugstr_w(buffer
));
5458 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5460 SetLastError(ERROR_INVALID_NAME
);
5466 *namesize
= strlenW(buffer
) + 1;
5467 if(!name
|| (*namesize
> insize
))
5469 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5473 strcpyW(name
, buffer
);
5476 HeapFree( GetProcessHeap(), 0, buffer
);
5481 /******************************************************************************
5482 * GetDefaultPrinterA (WINSPOOL.@)
5484 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5488 WCHAR
*bufferW
= NULL
;
5492 SetLastError(ERROR_INVALID_PARAMETER
);
5496 if(name
&& *namesize
) {
5498 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5501 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5506 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5510 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5513 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5516 HeapFree( GetProcessHeap(), 0, bufferW
);
5521 /******************************************************************************
5522 * SetDefaultPrinterW (WINSPOOL.204)
5524 * Set the Name of the Default Printer
5527 * pszPrinter [I] Name of the Printer or NULL
5534 * When the Parameter is NULL or points to an Empty String and
5535 * a Default Printer was already present, then this Function changes nothing.
5536 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5537 * the First enumerated local Printer is used.
5540 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5543 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5545 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5549 /******************************************************************************
5550 * SetDefaultPrinterA (WINSPOOL.202)
5552 * See SetDefaultPrinterW.
5555 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5558 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5560 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5565 /******************************************************************************
5566 * SetPrinterDataExA (WINSPOOL.@)
5568 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5569 LPCSTR pValueName
, DWORD Type
,
5570 LPBYTE pData
, DWORD cbData
)
5572 HKEY hkeyPrinter
, hkeySubkey
;
5575 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5576 debugstr_a(pValueName
), Type
, pData
, cbData
);
5578 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5582 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5584 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5585 RegCloseKey(hkeyPrinter
);
5588 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5589 RegCloseKey(hkeySubkey
);
5590 RegCloseKey(hkeyPrinter
);
5594 /******************************************************************************
5595 * SetPrinterDataExW (WINSPOOL.@)
5597 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5598 LPCWSTR pValueName
, DWORD Type
,
5599 LPBYTE pData
, DWORD cbData
)
5601 HKEY hkeyPrinter
, hkeySubkey
;
5604 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5605 debugstr_w(pValueName
), Type
, pData
, cbData
);
5607 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5611 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5613 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5614 RegCloseKey(hkeyPrinter
);
5617 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5618 RegCloseKey(hkeySubkey
);
5619 RegCloseKey(hkeyPrinter
);
5623 /******************************************************************************
5624 * SetPrinterDataA (WINSPOOL.@)
5626 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5627 LPBYTE pData
, DWORD cbData
)
5629 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5633 /******************************************************************************
5634 * SetPrinterDataW (WINSPOOL.@)
5636 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5637 LPBYTE pData
, DWORD cbData
)
5639 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5643 /******************************************************************************
5644 * GetPrinterDataExA (WINSPOOL.@)
5646 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5647 LPCSTR pValueName
, LPDWORD pType
,
5648 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5650 HKEY hkeyPrinter
, hkeySubkey
;
5653 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5654 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
5657 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5661 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5663 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
5664 RegCloseKey(hkeyPrinter
);
5668 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5669 RegCloseKey(hkeySubkey
);
5670 RegCloseKey(hkeyPrinter
);
5674 /******************************************************************************
5675 * GetPrinterDataExW (WINSPOOL.@)
5677 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5678 LPCWSTR pValueName
, LPDWORD pType
,
5679 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5681 HKEY hkeyPrinter
, hkeySubkey
;
5684 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5685 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
5688 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5692 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5694 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
5695 RegCloseKey(hkeyPrinter
);
5699 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5700 RegCloseKey(hkeySubkey
);
5701 RegCloseKey(hkeyPrinter
);
5705 /******************************************************************************
5706 * GetPrinterDataA (WINSPOOL.@)
5708 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5709 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5711 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5712 pData
, nSize
, pcbNeeded
);
5715 /******************************************************************************
5716 * GetPrinterDataW (WINSPOOL.@)
5718 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5719 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5721 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5722 pData
, nSize
, pcbNeeded
);
5725 /*******************************************************************************
5726 * EnumPrinterDataExW [WINSPOOL.@]
5728 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5729 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5730 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5732 HKEY hkPrinter
, hkSubKey
;
5733 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5734 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5739 PPRINTER_ENUM_VALUESW ppev
;
5741 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5743 if (pKeyName
== NULL
|| *pKeyName
== 0)
5744 return ERROR_INVALID_PARAMETER
;
5746 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5747 if (ret
!= ERROR_SUCCESS
)
5749 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5754 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5755 if (ret
!= ERROR_SUCCESS
)
5757 r
= RegCloseKey (hkPrinter
);
5758 if (r
!= ERROR_SUCCESS
)
5759 WARN ("RegCloseKey returned %i\n", r
);
5760 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5761 debugstr_w (pKeyName
), ret
);
5765 ret
= RegCloseKey (hkPrinter
);
5766 if (ret
!= ERROR_SUCCESS
)
5768 ERR ("RegCloseKey returned %i\n", ret
);
5769 r
= RegCloseKey (hkSubKey
);
5770 if (r
!= ERROR_SUCCESS
)
5771 WARN ("RegCloseKey returned %i\n", r
);
5775 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5776 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5777 if (ret
!= ERROR_SUCCESS
)
5779 r
= RegCloseKey (hkSubKey
);
5780 if (r
!= ERROR_SUCCESS
)
5781 WARN ("RegCloseKey returned %i\n", r
);
5782 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5786 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5787 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5789 if (cValues
== 0) /* empty key */
5791 r
= RegCloseKey (hkSubKey
);
5792 if (r
!= ERROR_SUCCESS
)
5793 WARN ("RegCloseKey returned %i\n", r
);
5794 *pcbEnumValues
= *pnEnumValues
= 0;
5795 return ERROR_SUCCESS
;
5798 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5800 hHeap
= GetProcessHeap ();
5803 ERR ("GetProcessHeap failed\n");
5804 r
= RegCloseKey (hkSubKey
);
5805 if (r
!= ERROR_SUCCESS
)
5806 WARN ("RegCloseKey returned %i\n", r
);
5807 return ERROR_OUTOFMEMORY
;
5810 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5811 if (lpValueName
== NULL
)
5813 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5814 r
= RegCloseKey (hkSubKey
);
5815 if (r
!= ERROR_SUCCESS
)
5816 WARN ("RegCloseKey returned %i\n", r
);
5817 return ERROR_OUTOFMEMORY
;
5820 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5821 if (lpValue
== NULL
)
5823 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5824 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5825 WARN ("HeapFree failed with code %i\n", GetLastError ());
5826 r
= RegCloseKey (hkSubKey
);
5827 if (r
!= ERROR_SUCCESS
)
5828 WARN ("RegCloseKey returned %i\n", r
);
5829 return ERROR_OUTOFMEMORY
;
5832 TRACE ("pass 1: calculating buffer required for all names and values\n");
5834 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5836 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5838 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5840 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5841 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5842 NULL
, NULL
, lpValue
, &cbValueLen
);
5843 if (ret
!= ERROR_SUCCESS
)
5845 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5846 WARN ("HeapFree failed with code %i\n", GetLastError ());
5847 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5848 WARN ("HeapFree failed with code %i\n", GetLastError ());
5849 r
= RegCloseKey (hkSubKey
);
5850 if (r
!= ERROR_SUCCESS
)
5851 WARN ("RegCloseKey returned %i\n", r
);
5852 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5856 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5857 debugstr_w (lpValueName
), dwIndex
,
5858 cbValueNameLen
+ 1, cbValueLen
);
5860 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5861 cbBufSize
+= cbValueLen
;
5864 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5866 *pcbEnumValues
= cbBufSize
;
5867 *pnEnumValues
= cValues
;
5869 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5871 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5872 WARN ("HeapFree failed with code %i\n", GetLastError ());
5873 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5874 WARN ("HeapFree failed with code %i\n", GetLastError ());
5875 r
= RegCloseKey (hkSubKey
);
5876 if (r
!= ERROR_SUCCESS
)
5877 WARN ("RegCloseKey returned %i\n", r
);
5878 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5879 return ERROR_MORE_DATA
;
5882 TRACE ("pass 2: copying all names and values to buffer\n");
5884 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5885 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5887 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5889 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5890 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5891 NULL
, &dwType
, lpValue
, &cbValueLen
);
5892 if (ret
!= ERROR_SUCCESS
)
5894 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5895 WARN ("HeapFree failed with code %i\n", GetLastError ());
5896 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5897 WARN ("HeapFree failed with code %i\n", GetLastError ());
5898 r
= RegCloseKey (hkSubKey
);
5899 if (r
!= ERROR_SUCCESS
)
5900 WARN ("RegCloseKey returned %i\n", r
);
5901 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5905 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5906 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5907 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5908 pEnumValues
+= cbValueNameLen
;
5910 /* return # of *bytes* (including trailing \0), not # of chars */
5911 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5913 ppev
[dwIndex
].dwType
= dwType
;
5915 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5916 ppev
[dwIndex
].pData
= pEnumValues
;
5917 pEnumValues
+= cbValueLen
;
5919 ppev
[dwIndex
].cbData
= cbValueLen
;
5921 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5922 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5925 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5927 ret
= GetLastError ();
5928 ERR ("HeapFree failed with code %i\n", ret
);
5929 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5930 WARN ("HeapFree failed with code %i\n", GetLastError ());
5931 r
= RegCloseKey (hkSubKey
);
5932 if (r
!= ERROR_SUCCESS
)
5933 WARN ("RegCloseKey returned %i\n", r
);
5937 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5939 ret
= GetLastError ();
5940 ERR ("HeapFree failed with code %i\n", ret
);
5941 r
= RegCloseKey (hkSubKey
);
5942 if (r
!= ERROR_SUCCESS
)
5943 WARN ("RegCloseKey returned %i\n", r
);
5947 ret
= RegCloseKey (hkSubKey
);
5948 if (ret
!= ERROR_SUCCESS
)
5950 ERR ("RegCloseKey returned %i\n", ret
);
5954 return ERROR_SUCCESS
;
5957 /*******************************************************************************
5958 * EnumPrinterDataExA [WINSPOOL.@]
5960 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5961 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5962 * what Windows 2000 SP1 does.
5965 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5966 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5967 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5971 DWORD ret
, dwIndex
, dwBufSize
;
5975 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5977 if (pKeyName
== NULL
|| *pKeyName
== 0)
5978 return ERROR_INVALID_PARAMETER
;
5980 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5983 ret
= GetLastError ();
5984 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5988 hHeap
= GetProcessHeap ();
5991 ERR ("GetProcessHeap failed\n");
5992 return ERROR_OUTOFMEMORY
;
5995 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5996 if (pKeyNameW
== NULL
)
5998 ERR ("Failed to allocate %i bytes from process heap\n",
5999 (LONG
)(len
* sizeof (WCHAR
)));
6000 return ERROR_OUTOFMEMORY
;
6003 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6005 ret
= GetLastError ();
6006 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6007 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6008 WARN ("HeapFree failed with code %i\n", GetLastError ());
6012 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6013 pcbEnumValues
, pnEnumValues
);
6014 if (ret
!= ERROR_SUCCESS
)
6016 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6017 WARN ("HeapFree failed with code %i\n", GetLastError ());
6018 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6022 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6024 ret
= GetLastError ();
6025 ERR ("HeapFree failed with code %i\n", ret
);
6029 if (*pnEnumValues
== 0) /* empty key */
6030 return ERROR_SUCCESS
;
6033 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6035 PPRINTER_ENUM_VALUESW ppev
=
6036 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6038 if (dwBufSize
< ppev
->cbValueName
)
6039 dwBufSize
= ppev
->cbValueName
;
6041 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6042 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6043 dwBufSize
= ppev
->cbData
;
6046 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6048 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6049 if (pBuffer
== NULL
)
6051 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6052 return ERROR_OUTOFMEMORY
;
6055 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6057 PPRINTER_ENUM_VALUESW ppev
=
6058 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6060 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6061 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6065 ret
= GetLastError ();
6066 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6067 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6068 WARN ("HeapFree failed with code %i\n", GetLastError ());
6072 memcpy (ppev
->pValueName
, pBuffer
, len
);
6074 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6076 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6077 ppev
->dwType
!= REG_MULTI_SZ
)
6080 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6081 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6084 ret
= GetLastError ();
6085 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6086 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6087 WARN ("HeapFree failed with code %i\n", GetLastError ());
6091 memcpy (ppev
->pData
, pBuffer
, len
);
6093 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6094 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6097 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6099 ret
= GetLastError ();
6100 ERR ("HeapFree failed with code %i\n", ret
);
6104 return ERROR_SUCCESS
;
6107 /******************************************************************************
6108 * AbortPrinter (WINSPOOL.@)
6110 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6112 FIXME("(%p), stub!\n", hPrinter
);
6116 /******************************************************************************
6117 * AddPortA (WINSPOOL.@)
6122 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6124 LPWSTR nameW
= NULL
;
6125 LPWSTR monitorW
= NULL
;
6129 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6132 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6133 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6134 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6138 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6139 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6140 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6142 res
= AddPortW(nameW
, hWnd
, monitorW
);
6143 HeapFree(GetProcessHeap(), 0, nameW
);
6144 HeapFree(GetProcessHeap(), 0, monitorW
);
6148 /******************************************************************************
6149 * AddPortW (WINSPOOL.@)
6151 * Add a Port for a specific Monitor
6154 * pName [I] Servername or NULL (local Computer)
6155 * hWnd [I] Handle to parent Window for the Dialog-Box
6156 * pMonitorName [I] Name of the Monitor that manage the Port
6163 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6169 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6171 if (pName
&& pName
[0]) {
6172 SetLastError(ERROR_INVALID_PARAMETER
);
6176 if (!pMonitorName
) {
6177 SetLastError(RPC_X_NULL_REF_POINTER
);
6181 /* an empty Monitorname is Invalid */
6182 if (!pMonitorName
[0]) {
6183 SetLastError(ERROR_NOT_SUPPORTED
);
6187 pm
= monitor_load(pMonitorName
, NULL
);
6188 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
6189 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
6190 TRACE("got %d with %u\n", res
, GetLastError());
6195 pui
= monitor_loadui(pm
);
6196 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
6197 TRACE("use %p: %s\n", pui
, debugstr_w(pui
->dllname
));
6198 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
6199 TRACE("got %d with %u\n", res
, GetLastError());
6204 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName
),
6205 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6207 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6208 SetLastError(ERROR_NOT_SUPPORTED
);
6211 monitor_unload(pui
);
6214 TRACE("returning %d with %u\n", res
, GetLastError());
6218 /******************************************************************************
6219 * AddPortExA (WINSPOOL.@)
6224 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6227 PORT_INFO_2A
* pi2A
;
6228 LPWSTR nameW
= NULL
;
6229 LPWSTR monitorW
= NULL
;
6233 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6235 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6236 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6238 if ((level
< 1) || (level
> 2)) {
6239 SetLastError(ERROR_INVALID_LEVEL
);
6244 SetLastError(ERROR_INVALID_PARAMETER
);
6249 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6250 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6251 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6255 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6256 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6257 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6260 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6262 if (pi2A
->pPortName
) {
6263 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6264 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6265 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6269 if (pi2A
->pMonitorName
) {
6270 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6271 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6272 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6275 if (pi2A
->pDescription
) {
6276 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6277 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6278 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6280 pi2W
.fPortType
= pi2A
->fPortType
;
6281 pi2W
.Reserved
= pi2A
->Reserved
;
6284 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6286 HeapFree(GetProcessHeap(), 0, nameW
);
6287 HeapFree(GetProcessHeap(), 0, monitorW
);
6288 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6289 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6290 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6295 /******************************************************************************
6296 * AddPortExW (WINSPOOL.@)
6298 * Add a Port for a specific Monitor, without presenting a user interface
6301 * pName [I] Servername or NULL (local Computer)
6302 * level [I] Structure-Level (1 or 2) for pBuffer
6303 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6304 * pMonitorName [I] Name of the Monitor that manage the Port
6311 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6317 pi2
= (PORT_INFO_2W
*) pBuffer
;
6319 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6320 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6321 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6322 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6325 if ((level
< 1) || (level
> 2)) {
6326 SetLastError(ERROR_INVALID_LEVEL
);
6330 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6331 SetLastError(ERROR_INVALID_PARAMETER
);
6335 /* load the Monitor */
6336 pm
= monitor_load(pMonitorName
, NULL
);
6338 SetLastError(ERROR_INVALID_PARAMETER
);
6342 if (pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
6343 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6344 TRACE("got %u with %u\n", res
, GetLastError());
6348 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName
), pm
->monitor
);
6354 /******************************************************************************
6355 * AddPrinterConnectionA (WINSPOOL.@)
6357 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6359 FIXME("%s\n", debugstr_a(pName
));
6363 /******************************************************************************
6364 * AddPrinterConnectionW (WINSPOOL.@)
6366 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6368 FIXME("%s\n", debugstr_w(pName
));
6372 /******************************************************************************
6373 * AddPrinterDriverExW (WINSPOOL.@)
6375 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD Level
,
6376 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6378 FIXME("%s %d %p %d\n", debugstr_w(pName
),
6379 Level
, pDriverInfo
, dwFileCopyFlags
);
6380 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
6384 /******************************************************************************
6385 * AddPrinterDriverExA (WINSPOOL.@)
6387 BOOL WINAPI
AddPrinterDriverExA( LPSTR pName
, DWORD Level
,
6388 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6390 FIXME("%s %d %p %d\n", debugstr_a(pName
),
6391 Level
, pDriverInfo
, dwFileCopyFlags
);
6392 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
6396 /******************************************************************************
6397 * ConfigurePortA (WINSPOOL.@)
6399 * See ConfigurePortW.
6402 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6404 LPWSTR nameW
= NULL
;
6405 LPWSTR portW
= NULL
;
6409 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6411 /* convert servername to unicode */
6413 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6414 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6415 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6418 /* convert portname to unicode */
6420 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6421 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6422 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6425 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6426 HeapFree(GetProcessHeap(), 0, nameW
);
6427 HeapFree(GetProcessHeap(), 0, portW
);
6431 /******************************************************************************
6432 * ConfigurePortW (WINSPOOL.@)
6434 * Display the Configuration-Dialog for a specific Port
6437 * pName [I] Servername or NULL (local Computer)
6438 * hWnd [I] Handle to parent Window for the Dialog-Box
6439 * pPortName [I] Name of the Port, that should be configured
6446 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6452 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6454 if (pName
&& pName
[0]) {
6455 SetLastError(ERROR_INVALID_PARAMETER
);
6460 SetLastError(RPC_X_NULL_REF_POINTER
);
6464 /* an empty Portname is Invalid, but can popup a Dialog */
6465 if (!pPortName
[0]) {
6466 SetLastError(ERROR_NOT_SUPPORTED
);
6470 pm
= monitor_load_by_port(pPortName
);
6471 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
6472 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
6473 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
6474 TRACE("got %d with %u\n", res
, GetLastError());
6478 pui
= monitor_loadui(pm
);
6479 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
6480 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
6481 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
6482 TRACE("got %d with %u\n", res
, GetLastError());
6486 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
6487 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6489 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6490 SetLastError(ERROR_NOT_SUPPORTED
);
6493 monitor_unload(pui
);
6497 TRACE("returning %d with %u\n", res
, GetLastError());
6501 /******************************************************************************
6502 * ConnectToPrinterDlg (WINSPOOL.@)
6504 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6506 FIXME("%p %x\n", hWnd
, Flags
);
6510 /******************************************************************************
6511 * DeletePrinterConnectionA (WINSPOOL.@)
6513 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6515 FIXME("%s\n", debugstr_a(pName
));
6519 /******************************************************************************
6520 * DeletePrinterConnectionW (WINSPOOL.@)
6522 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6524 FIXME("%s\n", debugstr_w(pName
));
6528 /******************************************************************************
6529 * DeletePrinterDriverExW (WINSPOOL.@)
6531 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6532 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6537 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6538 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6540 if(pName
&& pName
[0])
6542 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6543 SetLastError(ERROR_INVALID_PARAMETER
);
6549 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6550 SetLastError(ERROR_INVALID_PARAMETER
);
6554 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
6558 ERR("Can't open drivers key\n");
6562 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6565 RegCloseKey(hkey_drivers
);
6570 /******************************************************************************
6571 * DeletePrinterDriverExA (WINSPOOL.@)
6573 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6574 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6576 UNICODE_STRING NameW
, EnvW
, DriverW
;
6579 asciitounicode(&NameW
, pName
);
6580 asciitounicode(&EnvW
, pEnvironment
);
6581 asciitounicode(&DriverW
, pDriverName
);
6583 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6585 RtlFreeUnicodeString(&DriverW
);
6586 RtlFreeUnicodeString(&EnvW
);
6587 RtlFreeUnicodeString(&NameW
);
6592 /******************************************************************************
6593 * DeletePrinterDataExW (WINSPOOL.@)
6595 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6598 FIXME("%p %s %s\n", hPrinter
,
6599 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6600 return ERROR_INVALID_PARAMETER
;
6603 /******************************************************************************
6604 * DeletePrinterDataExA (WINSPOOL.@)
6606 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6609 FIXME("%p %s %s\n", hPrinter
,
6610 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6611 return ERROR_INVALID_PARAMETER
;
6614 /******************************************************************************
6615 * DeletePrintProcessorA (WINSPOOL.@)
6617 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6619 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6620 debugstr_a(pPrintProcessorName
));
6624 /******************************************************************************
6625 * DeletePrintProcessorW (WINSPOOL.@)
6627 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6629 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6630 debugstr_w(pPrintProcessorName
));
6634 /******************************************************************************
6635 * DeletePrintProvidorA (WINSPOOL.@)
6637 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6639 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6640 debugstr_a(pPrintProviderName
));
6644 /******************************************************************************
6645 * DeletePrintProvidorW (WINSPOOL.@)
6647 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6649 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6650 debugstr_w(pPrintProviderName
));
6654 /******************************************************************************
6655 * EnumFormsA (WINSPOOL.@)
6657 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6658 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6660 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6661 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6665 /******************************************************************************
6666 * EnumFormsW (WINSPOOL.@)
6668 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6669 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6671 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6672 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6676 /*****************************************************************************
6677 * EnumMonitorsA [WINSPOOL.@]
6679 * See EnumMonitorsW.
6682 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6683 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6686 LPBYTE bufferW
= NULL
;
6687 LPWSTR nameW
= NULL
;
6689 DWORD numentries
= 0;
6692 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6693 cbBuf
, pcbNeeded
, pcReturned
);
6695 /* convert servername to unicode */
6697 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6698 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6699 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6701 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6702 needed
= cbBuf
* sizeof(WCHAR
);
6703 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6704 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6706 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6707 if (pcbNeeded
) needed
= *pcbNeeded
;
6708 /* HeapReAlloc return NULL, when bufferW was NULL */
6709 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6710 HeapAlloc(GetProcessHeap(), 0, needed
);
6712 /* Try again with the large Buffer */
6713 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6715 numentries
= pcReturned
? *pcReturned
: 0;
6718 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6719 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6722 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6723 DWORD entrysize
= 0;
6726 LPMONITOR_INFO_2W mi2w
;
6727 LPMONITOR_INFO_2A mi2a
;
6729 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6730 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6732 /* First pass: calculate the size for all Entries */
6733 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6734 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6736 while (index
< numentries
) {
6738 needed
+= entrysize
; /* MONITOR_INFO_?A */
6739 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6741 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6742 NULL
, 0, NULL
, NULL
);
6744 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6745 NULL
, 0, NULL
, NULL
);
6746 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6747 NULL
, 0, NULL
, NULL
);
6749 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6750 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6751 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6754 /* check for errors and quit on failure */
6755 if (cbBuf
< needed
) {
6756 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6760 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6761 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6762 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6763 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6764 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6766 /* Second Pass: Fill the User Buffer (if we have one) */
6767 while ((index
< numentries
) && pMonitors
) {
6769 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6771 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6772 ptr
, cbBuf
, NULL
, NULL
);
6776 mi2a
->pEnvironment
= ptr
;
6777 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6778 ptr
, cbBuf
, NULL
, NULL
);
6782 mi2a
->pDLLName
= ptr
;
6783 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6784 ptr
, cbBuf
, NULL
, NULL
);
6788 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6789 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6790 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6794 if (pcbNeeded
) *pcbNeeded
= needed
;
6795 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6797 HeapFree(GetProcessHeap(), 0, nameW
);
6798 HeapFree(GetProcessHeap(), 0, bufferW
);
6800 TRACE("returning %d with %d (%d byte for %d entries)\n",
6801 (res
), GetLastError(), needed
, numentries
);
6807 /*****************************************************************************
6808 * EnumMonitorsW [WINSPOOL.@]
6810 * Enumerate available Port-Monitors
6813 * pName [I] Servername or NULL (local Computer)
6814 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6815 * pMonitors [O] PTR to Buffer that receives the Result
6816 * cbBuf [I] Size of Buffer at pMonitors
6817 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6818 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6822 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6825 * Windows reads the Registry once and cache the Results.
6827 *| Language-Monitors are also installed in the same Registry-Location but
6828 *| they are filtered in Windows (not returned by EnumMonitors).
6829 *| We do no filtering to simplify our Code.
6832 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6833 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6836 DWORD numentries
= 0;
6839 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6840 cbBuf
, pcbNeeded
, pcReturned
);
6842 if (pName
&& (lstrlenW(pName
))) {
6843 FIXME("for Server %s not implemented\n", debugstr_w(pName
));
6844 SetLastError(ERROR_ACCESS_DENIED
);
6848 /* Level is not checked in win9x */
6849 if (!Level
|| (Level
> 2)) {
6850 WARN("level (%d) is ignored in win9x\n", Level
);
6851 SetLastError(ERROR_INVALID_LEVEL
);
6855 SetLastError(RPC_X_NULL_REF_POINTER
);
6859 /* Scan all Monitor-Keys */
6861 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
6863 /* we calculated the needed buffersize. now do the error-checks */
6864 if (cbBuf
< needed
) {
6865 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6868 else if (!pMonitors
|| !pcReturned
) {
6869 SetLastError(RPC_X_NULL_REF_POINTER
);
6873 /* fill the Buffer with the Monitor-Keys */
6874 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
6878 if (pcbNeeded
) *pcbNeeded
= needed
;
6879 if (pcReturned
) *pcReturned
= numentries
;
6881 TRACE("returning %d with %d (%d byte for %d entries)\n",
6882 res
, GetLastError(), needed
, numentries
);
6887 /******************************************************************************
6888 * XcvDataW (WINSPOOL.@)
6890 * Execute commands in the Printmonitor DLL
6893 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6894 * pszDataName [i] Name of the command to execute
6895 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6896 * cbInputData [i] Size in Bytes of Buffer at pInputData
6897 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6898 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6899 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6900 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6907 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6908 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6910 * Minimal List of commands, that a Printmonitor DLL should support:
6912 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6913 *| "AddPort" : Add a Port
6914 *| "DeletePort": Delete a Port
6916 * Many Printmonitors support additional commands. Examples for localspl.dll:
6917 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6918 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6921 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6922 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6923 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6925 opened_printer_t
*printer
;
6927 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6928 pInputData
, cbInputData
, pOutputData
,
6929 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6931 printer
= get_opened_printer(hXcv
);
6932 if (!printer
|| (!printer
->hXcv
)) {
6933 SetLastError(ERROR_INVALID_HANDLE
);
6937 if (!pcbOutputNeeded
) {
6938 SetLastError(ERROR_INVALID_PARAMETER
);
6942 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6943 SetLastError(RPC_X_NULL_REF_POINTER
);
6947 *pcbOutputNeeded
= 0;
6949 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
6950 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
6955 /*****************************************************************************
6956 * EnumPrinterDataA [WINSPOOL.@]
6959 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6960 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6961 DWORD cbData
, LPDWORD pcbData
)
6963 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6964 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6965 return ERROR_NO_MORE_ITEMS
;
6968 /*****************************************************************************
6969 * EnumPrinterDataW [WINSPOOL.@]
6972 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
6973 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6974 DWORD cbData
, LPDWORD pcbData
)
6976 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6977 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6978 return ERROR_NO_MORE_ITEMS
;
6981 /*****************************************************************************
6982 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6985 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
6986 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6987 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6989 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
6990 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6991 pcbNeeded
, pcReturned
);
6995 /*****************************************************************************
6996 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6999 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7000 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7001 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7003 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7004 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7005 pcbNeeded
, pcReturned
);
7009 /*****************************************************************************
7010 * EnumPrintProcessorsA [WINSPOOL.@]
7013 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7014 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7016 FIXME("Stub: %s %s %d %p %d %p %p\n", pName
, pEnvironment
, Level
,
7017 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
7021 /*****************************************************************************
7022 * EnumPrintProcessorsW [WINSPOOL.@]
7025 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7026 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7028 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7029 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
7030 cbBuf
, pcbNeeded
, pcbReturned
);
7034 /*****************************************************************************
7035 * ExtDeviceMode [WINSPOOL.@]
7038 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7039 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7042 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7043 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7044 debugstr_a(pProfile
), fMode
);
7048 /*****************************************************************************
7049 * FindClosePrinterChangeNotification [WINSPOOL.@]
7052 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7054 FIXME("Stub: %p\n", hChange
);
7058 /*****************************************************************************
7059 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7062 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7063 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7065 FIXME("Stub: %p %x %x %p\n",
7066 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7067 return INVALID_HANDLE_VALUE
;
7070 /*****************************************************************************
7071 * FindNextPrinterChangeNotification [WINSPOOL.@]
7074 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7075 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7077 FIXME("Stub: %p %p %p %p\n",
7078 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7082 /*****************************************************************************
7083 * FreePrinterNotifyInfo [WINSPOOL.@]
7086 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7088 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7092 /*****************************************************************************
7095 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7096 * ansi depending on the unicode parameter.
7098 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7108 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7111 memcpy(ptr
, str
, *size
);
7118 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7121 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7128 /*****************************************************************************
7131 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7132 LPDWORD pcbNeeded
, BOOL unicode
)
7134 DWORD size
, left
= cbBuf
;
7135 BOOL space
= (cbBuf
> 0);
7142 ji1
->JobId
= job
->job_id
;
7145 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7146 if(space
&& size
<= left
)
7148 ji1
->pDocument
= (LPWSTR
)ptr
;
7159 /*****************************************************************************
7162 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7163 LPDWORD pcbNeeded
, BOOL unicode
)
7165 DWORD size
, left
= cbBuf
;
7166 BOOL space
= (cbBuf
> 0);
7173 ji2
->JobId
= job
->job_id
;
7176 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7177 if(space
&& size
<= left
)
7179 ji2
->pDocument
= (LPWSTR
)ptr
;
7190 /*****************************************************************************
7193 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7194 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7197 DWORD needed
= 0, size
;
7201 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7203 EnterCriticalSection(&printer_handles_cs
);
7204 job
= get_job(hPrinter
, JobId
);
7211 size
= sizeof(JOB_INFO_1W
);
7216 memset(pJob
, 0, size
);
7220 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7225 size
= sizeof(JOB_INFO_2W
);
7230 memset(pJob
, 0, size
);
7234 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7239 size
= sizeof(JOB_INFO_3
);
7243 memset(pJob
, 0, size
);
7252 SetLastError(ERROR_INVALID_LEVEL
);
7256 *pcbNeeded
= needed
;
7258 LeaveCriticalSection(&printer_handles_cs
);
7262 /*****************************************************************************
7263 * GetJobA [WINSPOOL.@]
7266 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7267 DWORD cbBuf
, LPDWORD pcbNeeded
)
7269 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7272 /*****************************************************************************
7273 * GetJobW [WINSPOOL.@]
7276 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7277 DWORD cbBuf
, LPDWORD pcbNeeded
)
7279 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7282 /*****************************************************************************
7285 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7287 char *unixname
, *queue
, *cmd
;
7288 char fmt
[] = "lpr -P%s %s";
7291 if(!(unixname
= wine_get_unix_file_name(filename
)))
7294 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7295 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7296 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7298 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7299 sprintf(cmd
, fmt
, queue
, unixname
);
7301 TRACE("printing with: %s\n", cmd
);
7304 HeapFree(GetProcessHeap(), 0, cmd
);
7305 HeapFree(GetProcessHeap(), 0, queue
);
7306 HeapFree(GetProcessHeap(), 0, unixname
);
7310 /*****************************************************************************
7313 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7315 #ifdef SONAME_LIBCUPS
7318 char *unixname
, *queue
, *doc_titleA
;
7322 if(!(unixname
= wine_get_unix_file_name(filename
)))
7325 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7326 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7327 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7329 len
= WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7330 doc_titleA
= HeapAlloc(GetProcessHeap(), 0, len
);
7331 WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, doc_titleA
, len
, NULL
, NULL
);
7333 TRACE("printing via cups\n");
7334 ret
= pcupsPrintFile(queue
, unixname
, doc_titleA
, 0, NULL
);
7335 HeapFree(GetProcessHeap(), 0, doc_titleA
);
7336 HeapFree(GetProcessHeap(), 0, queue
);
7337 HeapFree(GetProcessHeap(), 0, unixname
);
7343 return schedule_lpr(printer_name
, filename
);
7347 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7354 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7358 if(HIWORD(wparam
) == BN_CLICKED
)
7360 if(LOWORD(wparam
) == IDOK
)
7363 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7366 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7367 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7369 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7371 WCHAR caption
[200], message
[200];
7374 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7375 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7376 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7377 if(mb_ret
== IDCANCEL
)
7379 HeapFree(GetProcessHeap(), 0, filename
);
7383 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7384 if(hf
== INVALID_HANDLE_VALUE
)
7386 WCHAR caption
[200], message
[200];
7388 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7389 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7390 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7391 HeapFree(GetProcessHeap(), 0, filename
);
7395 DeleteFileW(filename
);
7396 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7398 EndDialog(hwnd
, IDOK
);
7401 if(LOWORD(wparam
) == IDCANCEL
)
7403 EndDialog(hwnd
, IDCANCEL
);
7412 /*****************************************************************************
7415 static BOOL
get_filename(LPWSTR
*filename
)
7417 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7418 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7421 /*****************************************************************************
7424 static BOOL
schedule_file(LPCWSTR filename
)
7426 LPWSTR output
= NULL
;
7428 if(get_filename(&output
))
7430 TRACE("copy to %s\n", debugstr_w(output
));
7431 CopyFileW(filename
, output
, FALSE
);
7432 HeapFree(GetProcessHeap(), 0, output
);
7438 /*****************************************************************************
7441 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7444 char *unixname
, *cmdA
;
7446 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7450 if(!(unixname
= wine_get_unix_file_name(filename
)))
7453 len
= WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7454 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7455 WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7457 TRACE("printing with: %s\n", cmdA
);
7459 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7464 ERR("pipe() failed!\n");
7474 /* reset signals that we previously set to SIG_IGN */
7475 signal(SIGPIPE
, SIG_DFL
);
7476 signal(SIGCHLD
, SIG_DFL
);
7478 execl("/bin/sh", "/bin/sh", "-c", cmdA
, (char*)0);
7482 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7483 write(fds
[1], buf
, no_read
);
7488 if(file_fd
!= -1) close(file_fd
);
7489 if(fds
[0] != -1) close(fds
[0]);
7490 if(fds
[1] != -1) close(fds
[1]);
7492 HeapFree(GetProcessHeap(), 0, cmdA
);
7493 HeapFree(GetProcessHeap(), 0, unixname
);
7500 /*****************************************************************************
7503 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7505 int in_fd
, out_fd
, no_read
;
7508 char *unixname
, *outputA
;
7511 if(!(unixname
= wine_get_unix_file_name(filename
)))
7514 len
= WideCharToMultiByte(CP_ACP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7515 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7516 WideCharToMultiByte(CP_ACP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7518 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7519 in_fd
= open(unixname
, O_RDONLY
);
7520 if(out_fd
== -1 || in_fd
== -1)
7523 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7524 write(out_fd
, buf
, no_read
);
7528 if(in_fd
!= -1) close(in_fd
);
7529 if(out_fd
!= -1) close(out_fd
);
7530 HeapFree(GetProcessHeap(), 0, outputA
);
7531 HeapFree(GetProcessHeap(), 0, unixname
);
7535 /*****************************************************************************
7536 * ScheduleJob [WINSPOOL.@]
7539 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7541 opened_printer_t
*printer
;
7543 struct list
*cursor
, *cursor2
;
7545 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7546 EnterCriticalSection(&printer_handles_cs
);
7547 printer
= get_opened_printer(hPrinter
);
7551 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7553 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7556 if(job
->job_id
!= dwJobID
) continue;
7558 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7559 if(hf
!= INVALID_HANDLE_VALUE
)
7561 PRINTER_INFO_5W
*pi5
;
7565 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7566 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7568 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7569 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7570 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7571 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7572 debugstr_w(pi5
->pPortName
));
7576 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7577 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7579 DWORD type
, count
= sizeof(output
);
7580 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
7583 if(output
[0] == '|')
7585 schedule_pipe(output
+ 1, job
->filename
);
7589 schedule_unixfile(output
, job
->filename
);
7591 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
7593 schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
7595 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
7597 schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7599 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
7601 schedule_file(job
->filename
);
7605 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
7607 HeapFree(GetProcessHeap(), 0, pi5
);
7609 DeleteFileW(job
->filename
);
7611 list_remove(cursor
);
7612 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7613 HeapFree(GetProcessHeap(), 0, job
->filename
);
7614 HeapFree(GetProcessHeap(), 0, job
);
7619 LeaveCriticalSection(&printer_handles_cs
);
7623 /*****************************************************************************
7624 * StartDocDlgA [WINSPOOL.@]
7626 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7628 UNICODE_STRING usBuffer
;
7631 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7634 docW
.cbSize
= sizeof(docW
);
7635 if (doc
->lpszDocName
)
7637 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7638 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7640 if (doc
->lpszOutput
)
7642 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7643 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7645 if (doc
->lpszDatatype
)
7647 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7648 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7650 docW
.fwType
= doc
->fwType
;
7652 retW
= StartDocDlgW(hPrinter
, &docW
);
7656 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7657 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7658 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7659 HeapFree(GetProcessHeap(), 0, retW
);
7662 HeapFree(GetProcessHeap(), 0, datatypeW
);
7663 HeapFree(GetProcessHeap(), 0, outputW
);
7664 HeapFree(GetProcessHeap(), 0, docnameW
);
7669 /*****************************************************************************
7670 * StartDocDlgW [WINSPOOL.@]
7672 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7673 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7674 * port is "FILE:". Also returns the full path if passed a relative path.
7676 * The caller should free the returned string from the process heap.
7678 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7683 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7685 PRINTER_INFO_5W
*pi5
;
7686 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7687 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7689 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7690 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7691 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7693 HeapFree(GetProcessHeap(), 0, pi5
);
7696 HeapFree(GetProcessHeap(), 0, pi5
);
7699 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7703 if (get_filename(&name
))
7705 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7707 HeapFree(GetProcessHeap(), 0, name
);
7710 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7711 GetFullPathNameW(name
, len
, ret
, NULL
);
7712 HeapFree(GetProcessHeap(), 0, name
);
7717 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7720 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7721 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7723 attr
= GetFileAttributesW(ret
);
7724 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7726 HeapFree(GetProcessHeap(), 0, ret
);