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
;
432 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, NULL
, 0);
435 TRACE("loaded %s\n", SONAME_LIBCUPS
);
438 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
439 if (!p##x) return FALSE;
442 DYNCUPS(cupsGetDests
);
443 DYNCUPS(cupsPrintFile
);
446 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
448 ERR("Can't create Printers key\n");
452 nrofdests
= pcupsGetDests(&dests
);
453 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
454 for (i
=0;i
<nrofdests
;i
++) {
455 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests
[i
].name
)+1);
456 sprintf(port
,"LPR:%s",dests
[i
].name
);
457 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
458 sprintf(devline
,"WINEPS.DRV,%s",port
);
459 WriteProfileStringA("devices",dests
[i
].name
,devline
);
460 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
461 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
464 HeapFree(GetProcessHeap(),0,devline
);
466 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
467 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
468 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
470 TRACE("Printer already exists\n");
471 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
472 RegCloseKey(hkeyPrinter
);
474 static CHAR data_type
[] = "RAW",
475 print_proc
[] = "WinPrint",
476 comment
[] = "WINEPS Printer using CUPS",
477 location
[] = "<physical location of printer>",
478 params
[] = "<parameters?>",
479 share_name
[] = "<share name?>",
480 sep_file
[] = "<sep file?>";
482 add_printer_driver(dests
[i
].name
);
484 memset(&pinfo2a
,0,sizeof(pinfo2a
));
485 pinfo2a
.pPrinterName
= dests
[i
].name
;
486 pinfo2a
.pDatatype
= data_type
;
487 pinfo2a
.pPrintProcessor
= print_proc
;
488 pinfo2a
.pDriverName
= dests
[i
].name
;
489 pinfo2a
.pComment
= comment
;
490 pinfo2a
.pLocation
= location
;
491 pinfo2a
.pPortName
= port
;
492 pinfo2a
.pParameters
= params
;
493 pinfo2a
.pShareName
= share_name
;
494 pinfo2a
.pSepFile
= sep_file
;
496 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
497 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
498 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
501 HeapFree(GetProcessHeap(),0,port
);
504 if (dests
[i
].is_default
) {
505 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
509 if (hadprinter
& !haddefault
)
510 WINSPOOL_SetDefaultPrinter(dests
[0].name
, dests
[0].name
, TRUE
);
511 RegCloseKey(hkeyPrinters
);
517 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
518 PRINTER_INFO_2A pinfo2a
;
519 char *e
,*s
,*name
,*prettyname
,*devname
;
520 BOOL ret
= FALSE
, set_default
= FALSE
;
521 char *port
,*devline
,*env_default
;
522 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
524 while (isspace(*pent
)) pent
++;
525 s
= strchr(pent
,':');
527 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
535 TRACE("name=%s entry=%s\n",name
, pent
);
537 if(ispunct(*name
)) { /* a tc entry, not a real printer */
538 TRACE("skipping tc entry\n");
542 if(strstr(pent
,":server")) { /* server only version so skip */
543 TRACE("skipping server entry\n");
547 /* Determine whether this is a postscript printer. */
550 env_default
= getenv("PRINTER");
552 /* Get longest name, usually the one at the right for later display. */
553 while((s
=strchr(prettyname
,'|'))) {
556 while(isspace(*--e
)) *e
= '\0';
557 TRACE("\t%s\n", debugstr_a(prettyname
));
558 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
559 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
562 e
= prettyname
+ strlen(prettyname
);
563 while(isspace(*--e
)) *e
= '\0';
564 TRACE("\t%s\n", debugstr_a(prettyname
));
565 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
567 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
568 * if it is too long, we use it as comment below. */
569 devname
= prettyname
;
570 if (strlen(devname
)>=CCHDEVICENAME
-1)
572 if (strlen(devname
)>=CCHDEVICENAME
-1) {
577 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
578 sprintf(port
,"LPR:%s",name
);
580 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
581 sprintf(devline
,"WINEPS.DRV,%s",port
);
582 WriteProfileStringA("devices",devname
,devline
);
583 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
584 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
587 HeapFree(GetProcessHeap(),0,devline
);
589 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
591 ERR("Can't create Printers key\n");
595 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
596 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
598 TRACE("Printer already exists\n");
599 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
600 RegCloseKey(hkeyPrinter
);
602 static CHAR data_type
[] = "RAW",
603 print_proc
[] = "WinPrint",
604 comment
[] = "WINEPS Printer using LPR",
605 params
[] = "<parameters?>",
606 share_name
[] = "<share name?>",
607 sep_file
[] = "<sep file?>";
609 add_printer_driver(devname
);
611 memset(&pinfo2a
,0,sizeof(pinfo2a
));
612 pinfo2a
.pPrinterName
= devname
;
613 pinfo2a
.pDatatype
= data_type
;
614 pinfo2a
.pPrintProcessor
= print_proc
;
615 pinfo2a
.pDriverName
= devname
;
616 pinfo2a
.pComment
= comment
;
617 pinfo2a
.pLocation
= prettyname
;
618 pinfo2a
.pPortName
= port
;
619 pinfo2a
.pParameters
= params
;
620 pinfo2a
.pShareName
= share_name
;
621 pinfo2a
.pSepFile
= sep_file
;
623 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
624 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
625 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
628 RegCloseKey(hkeyPrinters
);
630 if (isfirst
|| set_default
)
631 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
633 HeapFree(GetProcessHeap(), 0, port
);
635 HeapFree(GetProcessHeap(), 0, name
);
640 PRINTCAP_LoadPrinters(void) {
641 BOOL hadprinter
= FALSE
;
645 BOOL had_bash
= FALSE
;
647 f
= fopen("/etc/printcap","r");
651 while(fgets(buf
,sizeof(buf
),f
)) {
654 end
=strchr(buf
,'\n');
658 while(isspace(*start
)) start
++;
659 if(*start
== '#' || *start
== '\0')
662 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
663 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
664 HeapFree(GetProcessHeap(),0,pent
);
668 if (end
&& *--end
== '\\') {
675 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
678 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
684 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
685 HeapFree(GetProcessHeap(),0,pent
);
691 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
694 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
695 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
697 return ERROR_FILE_NOT_FOUND
;
700 /*****************************************************************************
701 * enumerate the local monitors (INTERNAL)
703 * returns the needed size (in bytes) for pMonitors
704 * and *lpreturned is set to number of entries returned in pMonitors
707 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
712 LPMONITOR_INFO_2W mi
;
713 WCHAR buffer
[MAX_PATH
];
714 WCHAR dllname
[MAX_PATH
];
722 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
724 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
725 len
= entrysize
* numentries
;
726 ptr
= (LPWSTR
) &pMonitors
[len
];
729 len
= sizeof(buffer
);
732 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
733 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
734 /* Scan all Monitor-Registry-Keys */
735 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
736 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
737 dllsize
= sizeof(dllname
);
740 /* The Monitor must have a Driver-DLL */
741 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
742 if (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
743 /* We found a valid DLL for this Monitor. */
744 TRACE("using Driver: %s\n", debugstr_w(dllname
));
749 /* Windows returns only Port-Monitors here, but to simplify our code,
750 we do no filtering for Language-Monitors */
754 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
756 /* we install and return only monitors for "Windows NT x86" */
757 needed
+= (lstrlenW(envname_x86W
) +1) * sizeof(WCHAR
);
761 /* required size is calculated. Now fill the user-buffer */
762 if (pMonitors
&& (cbBuf
>= needed
)){
763 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
764 pMonitors
+= entrysize
;
766 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
768 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
769 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
771 mi
->pEnvironment
= ptr
;
772 lstrcpyW(ptr
, envname_x86W
); /* fixed to "Windows NT x86" */
773 ptr
+= (lstrlenW(envname_x86W
)+1);
776 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
777 ptr
+= (dllsize
/ sizeof(WCHAR
));
782 len
= sizeof(buffer
);
787 *lpreturned
= numentries
;
788 TRACE("need %d byte for %d entries\n", needed
, numentries
);
792 /******************************************************************
793 * monitor_unload [internal]
795 * release a printmonitor and unload it from memory, when needed
798 static void monitor_unload(monitor_t
* pm
)
800 if (pm
== NULL
) return;
801 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
803 EnterCriticalSection(&monitor_handles_cs
);
805 if (pm
->refcount
) pm
->refcount
--;
807 if (pm
->refcount
== 0) {
808 list_remove(&pm
->entry
);
809 FreeLibrary(pm
->hdll
);
810 HeapFree(GetProcessHeap(), 0, pm
->name
);
811 HeapFree(GetProcessHeap(), 0, pm
->dllname
);
812 HeapFree(GetProcessHeap(), 0, pm
);
814 LeaveCriticalSection(&monitor_handles_cs
);
817 /******************************************************************
818 * monitor_unloadall [internal]
820 * release all printmonitors and unload them from memory, when needed
823 static void monitor_unloadall(void)
828 EnterCriticalSection(&monitor_handles_cs
);
829 /* iterate through the list, with safety against removal */
830 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
834 LeaveCriticalSection(&monitor_handles_cs
);
837 /******************************************************************
838 * monitor_load [internal]
840 * load a printmonitor, get the dllname from the registry, when needed
841 * initialize the monitor and dump found function-pointers
843 * On failure, SetLastError() is called and NULL is returned
846 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
848 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
849 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
850 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
851 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
852 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
854 monitor_t
* pm
= NULL
;
856 LPWSTR regroot
= NULL
;
857 LPWSTR driver
= dllname
;
859 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
860 /* Is the Monitor already loaded? */
861 EnterCriticalSection(&monitor_handles_cs
);
864 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
866 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
874 pm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(monitor_t
));
875 if (pm
== NULL
) goto cleanup
;
876 list_add_tail(&monitor_handles
, &pm
->entry
);
880 if (pm
->name
== NULL
) {
881 /* Load the monitor */
882 LPMONITOREX pmonitorEx
;
886 len
= lstrlenW(MonitorsW
) + lstrlenW(name
) + 2;
887 regroot
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
891 lstrcpyW(regroot
, MonitorsW
);
892 lstrcatW(regroot
, name
);
893 /* Get the Driver from the Registry */
894 if (driver
== NULL
) {
897 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
898 if (RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, NULL
,
899 &namesize
) == ERROR_SUCCESS
) {
900 driver
= HeapAlloc(GetProcessHeap(), 0, namesize
);
901 RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
908 pm
->name
= strdupW(name
);
909 pm
->dllname
= strdupW(driver
);
911 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
913 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
918 pm
->hdll
= LoadLibraryW(driver
);
919 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
921 if (pm
->hdll
== NULL
) {
923 SetLastError(ERROR_MOD_NOT_FOUND
);
928 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
929 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
930 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
931 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
932 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
935 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
936 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
937 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
938 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
939 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
941 if (pInitializePrintMonitorUI
!= NULL
) {
942 pm
->monitorUI
= pInitializePrintMonitorUI();
943 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
945 TRACE( "0x%08x: dwMonitorSize (%d)\n",
946 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
951 if (pInitializePrintMonitor
&& regroot
) {
952 pmonitorEx
= pInitializePrintMonitor(regroot
);
953 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
954 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
957 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
958 pm
->monitor
= &(pmonitorEx
->Monitor
);
963 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
967 if (!pm
->monitor
&& regroot
) {
968 if (pInitializePrintMonitor2
!= NULL
) {
969 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
971 if (pInitializeMonitorEx
!= NULL
) {
972 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
974 if (pInitializeMonitor
!= NULL
) {
975 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
978 if (!pm
->monitor
&& !pm
->monitorUI
) {
980 SetLastError(ERROR_PROC_NOT_FOUND
);
985 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, LocalPortW
) == 0)) {
989 LeaveCriticalSection(&monitor_handles_cs
);
990 if (driver
!= dllname
) HeapFree(GetProcessHeap(), 0, driver
);
991 HeapFree(GetProcessHeap(), 0, regroot
);
992 TRACE("=> %p\n", pm
);
996 /******************************************************************
997 * monitor_loadall [internal]
999 * Load all registered monitors
1002 static DWORD
monitor_loadall(void)
1005 DWORD registered
= 0;
1008 WCHAR buffer
[MAX_PATH
];
1011 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
1012 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
1013 NULL
, NULL
, NULL
, NULL
, NULL
);
1015 TRACE("%d monitors registered\n", registered
);
1017 EnterCriticalSection(&monitor_handles_cs
);
1018 while (id
< registered
) {
1020 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
1021 pm
= monitor_load(buffer
, NULL
);
1025 LeaveCriticalSection(&monitor_handles_cs
);
1026 RegCloseKey(hmonitors
);
1028 TRACE("%d monitors loaded\n", loaded
);
1032 /******************************************************************
1033 * monitor_loadui [internal]
1035 * load the userinterface-dll for a given portmonitor
1037 * On failure, NULL is returned
1040 static monitor_t
* monitor_loadui(monitor_t
* pm
)
1042 monitor_t
* pui
= NULL
;
1043 LPWSTR buffer
[MAX_PATH
];
1048 if (pm
== NULL
) return NULL
;
1049 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
1051 /* Try the Portmonitor first; works for many monitors */
1052 if (pm
->monitorUI
) {
1053 EnterCriticalSection(&monitor_handles_cs
);
1055 LeaveCriticalSection(&monitor_handles_cs
);
1059 /* query the userinterface-dllname from the Portmonitor */
1060 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
1061 /* building (",XcvMonitor %s",pm->name) not needed yet */
1062 res
= pm
->monitor
->pfnXcvOpenPort(emptyStringW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
1063 TRACE("got %u with %p\n", res
, hXcv
);
1065 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, MonitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
1066 TRACE("got %u with %s\n", res
, debugstr_w((LPWSTR
) buffer
));
1067 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, (LPWSTR
) buffer
);
1068 pm
->monitor
->pfnXcvClosePort(hXcv
);
1075 /******************************************************************
1076 * monitor_load_by_port [internal]
1078 * load a printmonitor for a given port
1080 * On failure, NULL is returned
1083 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
1088 monitor_t
* pm
= NULL
;
1089 DWORD registered
= 0;
1093 TRACE("(%s)\n", debugstr_w(portname
));
1095 /* Try the Local Monitor first */
1096 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
) == ERROR_SUCCESS
) {
1097 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
1098 /* found the portname */
1100 return monitor_load(LocalPortW
, NULL
);
1105 len
= MAX_PATH
+ lstrlenW(bs_Ports_bsW
) + lstrlenW(portname
) + 1;
1106 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1107 if (buffer
== NULL
) return NULL
;
1109 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
1110 EnterCriticalSection(&monitor_handles_cs
);
1111 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1113 while ((pm
== NULL
) && (id
< registered
)) {
1115 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
1116 TRACE("testing %s\n", debugstr_w(buffer
));
1117 len
= lstrlenW(buffer
);
1118 lstrcatW(buffer
, bs_Ports_bsW
);
1119 lstrcatW(buffer
, portname
);
1120 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
1122 buffer
[len
] = '\0'; /* use only the Monitor-Name */
1123 pm
= monitor_load(buffer
, NULL
);
1127 LeaveCriticalSection(&monitor_handles_cs
);
1130 HeapFree(GetProcessHeap(), 0, buffer
);
1134 /******************************************************************
1135 * enumerate the local Ports from all loaded monitors (internal)
1137 * returns the needed size (in bytes) for pPorts
1138 * and *lpreturned is set to number of entries returned in pPorts
1141 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
1145 LPPORT_INFO_2W cache
;
1147 LPBYTE pi_buffer
= NULL
;
1148 DWORD pi_allocated
= 0;
1159 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
1160 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
1162 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1163 needed
= entrysize
* numentries
;
1164 ptr
= (LPWSTR
) &pPorts
[needed
];
1169 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
1171 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
1174 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1175 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
1176 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1177 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1178 pi_buffer
= HeapAlloc(GetProcessHeap(), 0, pi_needed
);
1179 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
1180 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1182 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1183 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
1185 numentries
+= pi_returned
;
1186 needed
+= pi_needed
;
1188 /* fill the output-buffer (pPorts), if we have one */
1189 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
1191 while (pi_returned
> pi_index
) {
1192 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
1193 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
1194 out
->pPortName
= ptr
;
1195 lstrcpyW(ptr
, cache
->pPortName
);
1196 ptr
+= (lstrlenW(ptr
)+1);
1198 out
->pMonitorName
= ptr
;
1199 lstrcpyW(ptr
, cache
->pMonitorName
);
1200 ptr
+= (lstrlenW(ptr
)+1);
1202 out
->pDescription
= ptr
;
1203 lstrcpyW(ptr
, cache
->pDescription
);
1204 ptr
+= (lstrlenW(ptr
)+1);
1205 out
->fPortType
= cache
->fPortType
;
1206 out
->Reserved
= cache
->Reserved
;
1214 /* the temporary portinfo-buffer is no longer needed */
1215 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1217 *lpreturned
= numentries
;
1218 TRACE("need %d byte for %d entries\n", needed
, numentries
);
1222 /******************************************************************
1223 * get_servername_from_name (internal)
1225 * for an external server, a copy of the serverpart from the full name is returned
1228 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1232 WCHAR buffer
[MAX_PATH
];
1235 if (name
== NULL
) return NULL
;
1236 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1238 server
= strdupW(&name
[2]); /* skip over both backslash */
1239 if (server
== NULL
) return NULL
;
1241 /* strip '\' and the printername */
1242 ptr
= strchrW(server
, '\\');
1243 if (ptr
) ptr
[0] = '\0';
1245 TRACE("found %s\n", debugstr_w(server
));
1247 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1248 if (GetComputerNameW(buffer
, &len
)) {
1249 if (lstrcmpW(buffer
, server
) == 0) {
1250 /* The requested Servername is our computername */
1251 HeapFree(GetProcessHeap(), 0, server
);
1258 /******************************************************************
1259 * get_basename_from_name (internal)
1261 * skip over the serverpart from the full name
1264 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1266 if (name
== NULL
) return NULL
;
1267 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1268 /* skip over the servername and search for the following '\' */
1269 name
= strchrW(&name
[2], '\\');
1270 if ((name
) && (name
[1])) {
1271 /* found a separator ('\') followed by a name:
1272 skip over the separator and return the rest */
1277 /* no basename present (we found only a servername) */
1284 /******************************************************************
1285 * get_opened_printer_entry
1286 * Get the first place empty in the opened printer table
1289 * - pDefault is ignored
1291 static HANDLE
get_opened_printer_entry(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1293 UINT_PTR handle
= nb_printer_handles
, i
;
1294 jobqueue_t
*queue
= NULL
;
1295 opened_printer_t
*printer
= NULL
;
1297 LPCWSTR printername
;
1302 servername
= get_servername_from_name(name
);
1304 FIXME("server %s not supported\n", debugstr_w(servername
));
1305 HeapFree(GetProcessHeap(), 0, servername
);
1306 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1310 printername
= get_basename_from_name(name
);
1311 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1313 /* an empty printername is invalid */
1314 if (printername
&& (!printername
[0])) {
1315 SetLastError(ERROR_INVALID_PARAMETER
);
1319 EnterCriticalSection(&printer_handles_cs
);
1321 for (i
= 0; i
< nb_printer_handles
; i
++)
1323 if (!printer_handles
[i
])
1325 if(handle
== nb_printer_handles
)
1330 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1331 queue
= printer_handles
[i
]->queue
;
1335 if (handle
>= nb_printer_handles
)
1337 opened_printer_t
**new_array
;
1338 if (printer_handles
)
1339 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1340 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1342 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1343 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1350 printer_handles
= new_array
;
1351 nb_printer_handles
+= 16;
1354 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1361 /* clone the base name. This is NULL for the printserver */
1362 printer
->printername
= strdupW(printername
);
1364 /* clone the full name */
1365 printer
->name
= strdupW(name
);
1366 if (name
&& (!printer
->name
)) {
1372 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1373 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1374 /* OpenPrinter(",XcvMonitor " detected */
1375 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1376 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1377 if (printer
->pm
== NULL
) {
1378 SetLastError(ERROR_UNKNOWN_PORT
);
1385 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1386 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1387 /* OpenPrinter(",XcvPort " detected */
1388 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1389 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1390 if (printer
->pm
== NULL
) {
1391 SetLastError(ERROR_UNKNOWN_PORT
);
1399 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1400 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1401 pDefault
? pDefault
->DesiredAccess
: 0,
1404 if (printer
->hXcv
== NULL
) {
1405 SetLastError(ERROR_INVALID_PARAMETER
);
1412 /* Does the Printer exist? */
1413 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1414 ERR("Can't create Printers key\n");
1418 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1419 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1420 RegCloseKey(hkeyPrinters
);
1421 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1425 RegCloseKey(hkeyPrinter
);
1426 RegCloseKey(hkeyPrinters
);
1431 TRACE("using the local printserver\n");
1435 printer
->queue
= queue
;
1438 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1439 if (!printer
->queue
) {
1443 list_init(&printer
->queue
->jobs
);
1444 printer
->queue
->ref
= 0;
1446 InterlockedIncrement(&printer
->queue
->ref
);
1448 printer_handles
[handle
] = printer
;
1451 LeaveCriticalSection(&printer_handles_cs
);
1452 if (!handle
&& printer
) {
1453 /* Something failed: Free all resources */
1454 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1455 monitor_unload(printer
->pm
);
1456 HeapFree(GetProcessHeap(), 0, printer
->printername
);
1457 HeapFree(GetProcessHeap(), 0, printer
->name
);
1458 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1459 HeapFree(GetProcessHeap(), 0, printer
);
1462 return (HANDLE
)handle
;
1465 /******************************************************************
1466 * get_opened_printer
1467 * Get the pointer to the opened printer referred by the handle
1469 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
1471 UINT_PTR idx
= (UINT_PTR
)hprn
;
1472 opened_printer_t
*ret
= NULL
;
1474 EnterCriticalSection(&printer_handles_cs
);
1476 if ((idx
<= 0) || (idx
> nb_printer_handles
))
1479 ret
= printer_handles
[idx
- 1];
1481 LeaveCriticalSection(&printer_handles_cs
);
1485 /******************************************************************
1486 * get_opened_printer_name
1487 * Get the pointer to the opened printer name referred by the handle
1489 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
1491 opened_printer_t
*printer
= get_opened_printer(hprn
);
1492 if(!printer
) return NULL
;
1493 return printer
->name
;
1496 /******************************************************************
1497 * WINSPOOL_GetOpenedPrinterRegKey
1500 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
1502 LPCWSTR name
= get_opened_printer_name(hPrinter
);
1506 if(!name
) return ERROR_INVALID_HANDLE
;
1508 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
1512 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
1514 ERR("Can't find opened printer %s in registry\n",
1516 RegCloseKey(hkeyPrinters
);
1517 return ERROR_INVALID_PRINTER_NAME
; /* ? */
1519 RegCloseKey(hkeyPrinters
);
1520 return ERROR_SUCCESS
;
1523 void WINSPOOL_LoadSystemPrinters(void)
1525 HKEY hkey
, hkeyPrinters
;
1527 DWORD needed
, num
, i
;
1528 WCHAR PrinterName
[256];
1531 /* This ensures that all printer entries have a valid Name value. If causes
1532 problems later if they don't. If one is found to be missed we create one
1533 and set it equal to the name of the key */
1534 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1535 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1536 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1537 for(i
= 0; i
< num
; i
++) {
1538 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) == ERROR_SUCCESS
) {
1539 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1540 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1541 set_reg_szW(hkey
, NameW
, PrinterName
);
1548 RegCloseKey(hkeyPrinters
);
1551 /* We want to avoid calling AddPrinter on printers as much as
1552 possible, because on cups printers this will (eventually) lead
1553 to a call to cupsGetPPD which takes forever, even with non-cups
1554 printers AddPrinter takes a while. So we'll tag all printers that
1555 were automatically added last time around, if they still exist
1556 we'll leave them be otherwise we'll delete them. */
1557 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1559 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1560 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1561 for(i
= 0; i
< num
; i
++) {
1562 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1563 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1564 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1566 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1574 HeapFree(GetProcessHeap(), 0, pi
);
1578 #ifdef SONAME_LIBCUPS
1579 done
= CUPS_LoadPrinters();
1582 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1583 PRINTCAP_LoadPrinters();
1585 /* Now enumerate the list again and delete any printers that a still tagged */
1586 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1588 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1589 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1590 for(i
= 0; i
< num
; i
++) {
1591 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1592 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1593 BOOL delete_driver
= FALSE
;
1594 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1595 DWORD dw
, type
, size
= sizeof(dw
);
1596 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1597 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1598 DeletePrinter(hprn
);
1599 delete_driver
= TRUE
;
1605 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1610 HeapFree(GetProcessHeap(), 0, pi
);
1617 /******************************************************************
1620 * Get the pointer to the specified job.
1621 * Should hold the printer_handles_cs before calling.
1623 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1625 opened_printer_t
*printer
= get_opened_printer(hprn
);
1628 if(!printer
) return NULL
;
1629 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1631 if(job
->job_id
== JobId
)
1637 /***********************************************************
1640 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1643 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1646 Formname
= (dmA
->dmSize
> off_formname
);
1647 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1648 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1649 dmW
->dmDeviceName
, CCHDEVICENAME
);
1651 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1652 dmA
->dmSize
- CCHDEVICENAME
);
1654 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1655 off_formname
- CCHDEVICENAME
);
1656 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1657 dmW
->dmFormName
, CCHFORMNAME
);
1658 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1659 (off_formname
+ CCHFORMNAME
));
1662 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1663 dmA
->dmDriverExtra
);
1667 /***********************************************************
1669 * Creates an ascii copy of supplied devmode on heap
1671 static LPDEVMODEA
DEVMODEdupWtoA(HANDLE heap
, const DEVMODEW
*dmW
)
1676 ptrdiff_t off_formname
= (const char *)dmW
->dmFormName
- (const char *)dmW
;
1678 if(!dmW
) return NULL
;
1679 Formname
= (dmW
->dmSize
> off_formname
);
1680 size
= dmW
->dmSize
- CCHDEVICENAME
- (Formname
? CCHFORMNAME
: 0);
1681 dmA
= HeapAlloc(heap
, HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1682 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1683 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1685 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1686 dmW
->dmSize
- CCHDEVICENAME
* sizeof(WCHAR
));
1688 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1689 off_formname
- CCHDEVICENAME
* sizeof(WCHAR
));
1690 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1691 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1692 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
-
1693 (off_formname
+ CCHFORMNAME
* sizeof(WCHAR
)));
1696 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
,
1697 dmW
->dmDriverExtra
);
1701 /***********************************************************
1702 * PRINTER_INFO_2AtoW
1703 * Creates a unicode copy of PRINTER_INFO_2A on heap
1705 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1707 LPPRINTER_INFO_2W piW
;
1708 UNICODE_STRING usBuffer
;
1710 if(!piA
) return NULL
;
1711 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1712 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1714 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1715 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1716 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1717 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1718 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1719 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1720 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1721 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1722 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1723 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1724 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1725 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1729 /***********************************************************
1730 * FREE_PRINTER_INFO_2W
1731 * Free PRINTER_INFO_2W and all strings
1733 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1737 HeapFree(heap
,0,piW
->pServerName
);
1738 HeapFree(heap
,0,piW
->pPrinterName
);
1739 HeapFree(heap
,0,piW
->pShareName
);
1740 HeapFree(heap
,0,piW
->pPortName
);
1741 HeapFree(heap
,0,piW
->pDriverName
);
1742 HeapFree(heap
,0,piW
->pComment
);
1743 HeapFree(heap
,0,piW
->pLocation
);
1744 HeapFree(heap
,0,piW
->pDevMode
);
1745 HeapFree(heap
,0,piW
->pSepFile
);
1746 HeapFree(heap
,0,piW
->pPrintProcessor
);
1747 HeapFree(heap
,0,piW
->pDatatype
);
1748 HeapFree(heap
,0,piW
->pParameters
);
1749 HeapFree(heap
,0,piW
);
1753 /******************************************************************
1754 * DeviceCapabilities [WINSPOOL.@]
1755 * DeviceCapabilitiesA [WINSPOOL.@]
1758 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1759 LPSTR pOutput
, LPDEVMODEA lpdm
)
1763 if (!GDI_CallDeviceCapabilities16
)
1765 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1767 if (!GDI_CallDeviceCapabilities16
) return -1;
1769 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1771 /* If DC_PAPERSIZE map POINT16s to POINTs */
1772 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1773 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1774 POINT
*pt
= (POINT
*)pOutput
;
1776 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1777 for(i
= 0; i
< ret
; i
++, pt
++)
1782 HeapFree( GetProcessHeap(), 0, tmp
);
1788 /*****************************************************************************
1789 * DeviceCapabilitiesW [WINSPOOL.@]
1791 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1794 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1795 WORD fwCapability
, LPWSTR pOutput
,
1796 const DEVMODEW
*pDevMode
)
1798 LPDEVMODEA dmA
= DEVMODEdupWtoA(GetProcessHeap(), pDevMode
);
1799 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1800 LPSTR pPortA
= strdupWtoA(pPort
);
1803 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1804 fwCapability
== DC_FILEDEPENDENCIES
||
1805 fwCapability
== DC_PAPERNAMES
)) {
1806 /* These need A -> W translation */
1809 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1813 switch(fwCapability
) {
1818 case DC_FILEDEPENDENCIES
:
1822 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1823 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1825 for(i
= 0; i
< ret
; i
++)
1826 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1827 pOutput
+ (i
* size
), size
);
1828 HeapFree(GetProcessHeap(), 0, pOutputA
);
1830 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1831 (LPSTR
)pOutput
, dmA
);
1833 HeapFree(GetProcessHeap(),0,pPortA
);
1834 HeapFree(GetProcessHeap(),0,pDeviceA
);
1835 HeapFree(GetProcessHeap(),0,dmA
);
1839 /******************************************************************
1840 * DocumentPropertiesA [WINSPOOL.@]
1842 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1844 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1845 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1846 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1848 LPSTR lpName
= pDeviceName
;
1849 static CHAR port
[] = "LPT1:";
1852 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1853 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1857 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1859 ERR("no name from hPrinter?\n");
1860 SetLastError(ERROR_INVALID_HANDLE
);
1863 lpName
= strdupWtoA(lpNameW
);
1866 if (!GDI_CallExtDeviceMode16
)
1868 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1870 if (!GDI_CallExtDeviceMode16
) {
1871 ERR("No CallExtDeviceMode16?\n");
1875 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1876 pDevModeInput
, NULL
, fMode
);
1879 HeapFree(GetProcessHeap(),0,lpName
);
1884 /*****************************************************************************
1885 * DocumentPropertiesW (WINSPOOL.@)
1887 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1889 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1891 LPDEVMODEW pDevModeOutput
,
1892 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1895 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1896 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput
);
1897 LPDEVMODEA pDevModeOutputA
= NULL
;
1900 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1901 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1903 if(pDevModeOutput
) {
1904 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1905 if(ret
< 0) return ret
;
1906 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1908 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1909 pDevModeInputA
, fMode
);
1910 if(pDevModeOutput
) {
1911 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1912 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1914 if(fMode
== 0 && ret
> 0)
1915 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1916 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1917 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1921 /******************************************************************
1922 * OpenPrinterA [WINSPOOL.@]
1927 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1928 LPPRINTER_DEFAULTSA pDefault
)
1930 UNICODE_STRING lpPrinterNameW
;
1931 UNICODE_STRING usBuffer
;
1932 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1933 PWSTR pwstrPrinterNameW
;
1936 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1939 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1940 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1941 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1942 pDefaultW
= &DefaultW
;
1944 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1946 RtlFreeUnicodeString(&usBuffer
);
1947 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1949 RtlFreeUnicodeString(&lpPrinterNameW
);
1953 /******************************************************************
1954 * OpenPrinterW [WINSPOOL.@]
1956 * Open a Printer / Printserver or a Printer-Object
1959 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1960 * phPrinter [O] The resulting Handle is stored here
1961 * pDefault [I] PTR to Default Printer Settings or NULL
1968 * lpPrinterName is one of:
1969 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1970 *| Printer: "PrinterName"
1971 *| Printer-Object: "PrinterName,Job xxx"
1972 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1973 *| XcvPort: "Servername,XcvPort PortName"
1976 *| Printer-Object not supported
1977 *| pDefaults is ignored
1980 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1983 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
1985 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1986 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
1990 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1991 SetLastError(ERROR_INVALID_PARAMETER
);
1995 /* Get the unique handle of the printer or Printserver */
1996 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
1997 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
1998 return (*phPrinter
!= 0);
2001 /******************************************************************
2002 * AddMonitorA [WINSPOOL.@]
2007 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2009 LPWSTR nameW
= NULL
;
2012 LPMONITOR_INFO_2A mi2a
;
2013 MONITOR_INFO_2W mi2w
;
2015 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2016 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2017 mi2a
? debugstr_a(mi2a
->pName
) : NULL
,
2018 mi2a
? debugstr_a(mi2a
->pEnvironment
) : NULL
,
2019 mi2a
? debugstr_a(mi2a
->pDLLName
) : NULL
);
2022 SetLastError(ERROR_INVALID_LEVEL
);
2026 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2032 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2033 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2034 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2037 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2039 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2040 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2041 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2043 if (mi2a
->pEnvironment
) {
2044 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2045 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2046 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2048 if (mi2a
->pDLLName
) {
2049 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2050 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2051 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2054 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2056 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2057 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2058 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2060 HeapFree(GetProcessHeap(), 0, nameW
);
2064 /******************************************************************************
2065 * AddMonitorW [WINSPOOL.@]
2067 * Install a Printmonitor
2070 * pName [I] Servername or NULL (local Computer)
2071 * Level [I] Structure-Level (Must be 2)
2072 * pMonitors [I] PTR to MONITOR_INFO_2
2079 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2082 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2084 monitor_t
* pm
= NULL
;
2085 LPMONITOR_INFO_2W mi2w
;
2091 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2092 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2093 mi2w
? debugstr_w(mi2w
->pName
) : NULL
,
2094 mi2w
? debugstr_w(mi2w
->pEnvironment
) : NULL
,
2095 mi2w
? debugstr_w(mi2w
->pDLLName
) : NULL
);
2098 SetLastError(ERROR_INVALID_LEVEL
);
2102 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2107 if (pName
&& (pName
[0])) {
2108 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2109 SetLastError(ERROR_ACCESS_DENIED
);
2114 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
2115 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
2116 SetLastError(ERROR_INVALID_PARAMETER
);
2119 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, envname_x86W
)) {
2120 WARN("Environment %s requested (we support only %s)\n",
2121 debugstr_w(mi2w
->pEnvironment
), debugstr_w(envname_x86W
));
2122 SetLastError(ERROR_INVALID_ENVIRONMENT
);
2126 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
2127 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
2128 SetLastError(ERROR_INVALID_PARAMETER
);
2132 /* Load and initialize the monitor. SetLastError() is called on failure */
2133 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
2138 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2139 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2143 if(RegCreateKeyExW( hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2144 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
2145 &disposition
) == ERROR_SUCCESS
) {
2147 /* Some installers set options for the port before calling AddMonitor.
2148 We query the "Driver" entry to verify that the monitor is installed,
2149 before we return an error.
2150 When a user installs two print monitors at the same time with the
2151 same name but with a different driver DLL and a task switch comes
2152 between RegQueryValueExW and RegSetValueExW, a race condition
2153 is possible but silently ignored. */
2157 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
2158 (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, NULL
,
2159 &namesize
) == ERROR_SUCCESS
)) {
2160 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
2161 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2162 9x: ERROR_ALREADY_EXISTS (183) */
2163 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
2168 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
2169 res
= (RegSetValueExW(hentry
, DriverW
, 0,
2170 REG_SZ
, (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
2172 RegCloseKey(hentry
);
2179 /******************************************************************
2180 * DeletePrinterDriverA [WINSPOOL.@]
2183 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2185 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2188 /******************************************************************
2189 * DeletePrinterDriverW [WINSPOOL.@]
2192 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2194 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2197 /******************************************************************
2198 * DeleteMonitorA [WINSPOOL.@]
2200 * See DeleteMonitorW.
2203 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2205 LPWSTR nameW
= NULL
;
2206 LPWSTR EnvironmentW
= NULL
;
2207 LPWSTR MonitorNameW
= NULL
;
2212 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2213 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2214 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2218 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2219 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2220 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2223 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2224 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2225 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2228 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2230 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2231 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2232 HeapFree(GetProcessHeap(), 0, nameW
);
2236 /******************************************************************
2237 * DeleteMonitorW [WINSPOOL.@]
2239 * Delete a specific Printmonitor from a Printing-Environment
2242 * pName [I] Servername or NULL (local Computer)
2243 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2244 * pMonitorName [I] Name of the Monitor, that should be deleted
2251 * pEnvironment is ignored in Windows for the local Computer.
2255 BOOL WINAPI
DeleteMonitorW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2259 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2260 debugstr_w(pMonitorName
));
2262 if (pName
&& (pName
[0])) {
2263 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2264 SetLastError(ERROR_ACCESS_DENIED
);
2268 /* pEnvironment is ignored in Windows for the local Computer */
2270 if (!pMonitorName
|| !pMonitorName
[0]) {
2271 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
2272 SetLastError(ERROR_INVALID_PARAMETER
);
2276 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2277 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2281 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
2282 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName
));
2287 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName
));
2290 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2291 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
2295 /******************************************************************
2296 * DeletePortA [WINSPOOL.@]
2301 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2303 LPWSTR nameW
= NULL
;
2304 LPWSTR portW
= NULL
;
2308 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2310 /* convert servername to unicode */
2312 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2313 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2314 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2317 /* convert portname to unicode */
2319 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2320 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2321 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2324 res
= DeletePortW(nameW
, hWnd
, portW
);
2325 HeapFree(GetProcessHeap(), 0, nameW
);
2326 HeapFree(GetProcessHeap(), 0, portW
);
2330 /******************************************************************
2331 * DeletePortW [WINSPOOL.@]
2333 * Delete a specific Port
2336 * pName [I] Servername or NULL (local Computer)
2337 * hWnd [I] Handle to parent Window for the Dialog-Box
2338 * pPortName [I] Name of the Port, that should be deleted
2345 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2351 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2353 if (pName
&& pName
[0]) {
2354 SetLastError(ERROR_INVALID_PARAMETER
);
2359 SetLastError(RPC_X_NULL_REF_POINTER
);
2363 /* an empty Portname is Invalid */
2364 if (!pPortName
[0]) {
2365 SetLastError(ERROR_NOT_SUPPORTED
);
2369 pm
= monitor_load_by_port(pPortName
);
2370 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
2371 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2372 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
2373 TRACE("got %d with %u\n", res
, GetLastError());
2377 pui
= monitor_loadui(pm
);
2378 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2379 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2380 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2381 TRACE("got %d with %u\n", res
, GetLastError());
2385 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
2386 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
2388 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2389 SetLastError(ERROR_NOT_SUPPORTED
);
2392 monitor_unload(pui
);
2396 TRACE("returning %d with %u\n", res
, GetLastError());
2400 /******************************************************************************
2401 * SetPrinterW [WINSPOOL.@]
2403 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2405 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2406 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2410 /******************************************************************************
2411 * WritePrinter [WINSPOOL.@]
2413 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2415 opened_printer_t
*printer
;
2418 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2420 EnterCriticalSection(&printer_handles_cs
);
2421 printer
= get_opened_printer(hPrinter
);
2424 SetLastError(ERROR_INVALID_HANDLE
);
2430 SetLastError(ERROR_SPL_NO_STARTDOC
);
2434 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2436 LeaveCriticalSection(&printer_handles_cs
);
2440 /*****************************************************************************
2441 * AddFormA [WINSPOOL.@]
2443 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2445 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2449 /*****************************************************************************
2450 * AddFormW [WINSPOOL.@]
2452 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2454 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2458 /*****************************************************************************
2459 * AddJobA [WINSPOOL.@]
2461 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2464 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2468 SetLastError(ERROR_INVALID_LEVEL
);
2472 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2475 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2476 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2477 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2478 if(*pcbNeeded
> cbBuf
) {
2479 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2482 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2483 addjobA
->JobId
= addjobW
->JobId
;
2484 addjobA
->Path
= (char *)(addjobA
+ 1);
2485 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2491 /*****************************************************************************
2492 * AddJobW [WINSPOOL.@]
2494 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2496 opened_printer_t
*printer
;
2499 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2500 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2501 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2503 ADDJOB_INFO_1W
*addjob
;
2505 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2507 EnterCriticalSection(&printer_handles_cs
);
2509 printer
= get_opened_printer(hPrinter
);
2512 SetLastError(ERROR_INVALID_HANDLE
);
2517 SetLastError(ERROR_INVALID_LEVEL
);
2521 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2525 job
->job_id
= InterlockedIncrement(&next_job_id
);
2527 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2528 if(path
[len
- 1] != '\\')
2530 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2531 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2533 len
= strlenW(filename
);
2534 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2535 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2536 job
->document_title
= strdupW(default_doc_title
);
2537 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2539 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2540 if(*pcbNeeded
<= cbBuf
) {
2541 addjob
= (ADDJOB_INFO_1W
*)pData
;
2542 addjob
->JobId
= job
->job_id
;
2543 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2544 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2547 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2550 LeaveCriticalSection(&printer_handles_cs
);
2554 /*****************************************************************************
2555 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2557 * Return the PATH for the Print-Processors
2559 * See GetPrintProcessorDirectoryW.
2563 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2564 DWORD level
, LPBYTE Info
,
2565 DWORD cbBuf
, LPDWORD pcbNeeded
)
2567 LPWSTR serverW
= NULL
;
2572 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2573 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2577 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2578 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2579 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2583 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2584 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2585 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2588 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2589 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2591 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2594 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2595 cbBuf
, NULL
, NULL
) > 0;
2598 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2599 HeapFree(GetProcessHeap(), 0, envW
);
2600 HeapFree(GetProcessHeap(), 0, serverW
);
2604 /*****************************************************************************
2605 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2607 * Return the PATH for the Print-Processors
2610 * server [I] Servername (NT only) or NULL (local Computer)
2611 * env [I] Printing-Environment (see below) or NULL (Default)
2612 * level [I] Structure-Level (must be 1)
2613 * Info [O] PTR to Buffer that receives the Result
2614 * cbBuf [I] Size of Buffer at "Info"
2615 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2616 * required for the Buffer at "Info"
2619 * Success: TRUE and in pcbNeeded the Bytes used in Info
2620 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2621 * if cbBuf is too small
2623 * Native Values returned in Info on Success:
2624 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2625 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2626 *| win9x(Windows 4.0): "%winsysdir%"
2628 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2631 * Only NULL or "" is supported for server
2634 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2635 DWORD level
, LPBYTE Info
,
2636 DWORD cbBuf
, LPDWORD pcbNeeded
)
2639 const printenv_t
* env_t
;
2641 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
),
2642 debugstr_w(env
), level
, Info
, cbBuf
, pcbNeeded
);
2644 if(server
!= NULL
&& server
[0]) {
2645 FIXME("server not supported: %s\n", debugstr_w(server
));
2646 SetLastError(ERROR_INVALID_PARAMETER
);
2650 env_t
= validate_envW(env
);
2651 if(!env_t
) return FALSE
; /* environment invalid or unsupported */
2654 WARN("(Level: %d) is ignored in win9x\n", level
);
2655 SetLastError(ERROR_INVALID_LEVEL
);
2659 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2660 needed
= GetSystemDirectoryW(NULL
, 0);
2661 /* add the Size for the Subdirectories */
2662 needed
+= lstrlenW(spoolprtprocsW
);
2663 needed
+= lstrlenW(env_t
->subdir
);
2664 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2666 if(pcbNeeded
) *pcbNeeded
= needed
;
2667 TRACE ("required: 0x%x/%d\n", needed
, needed
);
2668 if (needed
> cbBuf
) {
2669 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2672 if(pcbNeeded
== NULL
) {
2673 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2674 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2675 SetLastError(RPC_X_NULL_REF_POINTER
);
2679 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2680 SetLastError(RPC_X_NULL_REF_POINTER
);
2684 GetSystemDirectoryW((LPWSTR
) Info
, cbBuf
/sizeof(WCHAR
));
2685 /* add the Subdirectories */
2686 lstrcatW((LPWSTR
) Info
, spoolprtprocsW
);
2687 lstrcatW((LPWSTR
) Info
, env_t
->subdir
);
2688 TRACE(" => %s\n", debugstr_w((LPWSTR
) Info
));
2692 /*****************************************************************************
2693 * WINSPOOL_OpenDriverReg [internal]
2695 * opens the registry for the printer drivers depending on the given input
2696 * variable pEnvironment
2699 * the opened hkey on success
2702 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
, BOOL unicode
)
2706 const printenv_t
* env
;
2709 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
), unicode
);
2711 if (!pEnvironment
|| unicode
) {
2712 /* pEnvironment was NULL or an Unicode-String: use it direct */
2713 env
= validate_envW(pEnvironment
);
2717 /* pEnvironment was an ANSI-String: convert to unicode first */
2719 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
2720 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2721 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
2722 env
= validate_envW(buffer
);
2723 HeapFree(GetProcessHeap(), 0, buffer
);
2725 if (!env
) return NULL
;
2727 buffer
= HeapAlloc( GetProcessHeap(), 0,
2728 (strlenW(DriversW
) + strlenW(env
->envname
) +
2729 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2731 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2732 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2733 HeapFree(GetProcessHeap(), 0, buffer
);
2738 /*****************************************************************************
2739 * AddPrinterW [WINSPOOL.@]
2741 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2743 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2747 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2749 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2750 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2751 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2752 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2753 statusW
[] = {'S','t','a','t','u','s',0},
2754 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2756 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2759 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2760 SetLastError(ERROR_INVALID_PARAMETER
);
2764 ERR("Level = %d, unsupported!\n", Level
);
2765 SetLastError(ERROR_INVALID_LEVEL
);
2769 SetLastError(ERROR_INVALID_PARAMETER
);
2772 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2774 ERR("Can't create Printers key\n");
2777 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2778 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2779 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2780 RegCloseKey(hkeyPrinter
);
2781 RegCloseKey(hkeyPrinters
);
2784 RegCloseKey(hkeyPrinter
);
2786 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
2788 ERR("Can't create Drivers key\n");
2789 RegCloseKey(hkeyPrinters
);
2792 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2794 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2795 RegCloseKey(hkeyPrinters
);
2796 RegCloseKey(hkeyDrivers
);
2797 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2800 RegCloseKey(hkeyDriver
);
2801 RegCloseKey(hkeyDrivers
);
2803 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2804 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2805 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2806 RegCloseKey(hkeyPrinters
);
2810 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2812 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2813 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2814 RegCloseKey(hkeyPrinters
);
2817 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2818 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2819 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2821 /* See if we can load the driver. We may need the devmode structure anyway
2824 * Note that DocumentPropertiesW will briefly try to open the printer we
2825 * just create to find a DEVMODEA struct (it will use the WINEPS default
2826 * one in case it is not there, so we are ok).
2828 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2831 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2832 size
= sizeof(DEVMODEW
);
2838 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2840 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2842 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2843 HeapFree(GetProcessHeap(),0,dmW
);
2848 /* set devmode to printer name */
2849 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2853 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2854 and we support these drivers. NT writes DEVMODEW so somehow
2855 we'll need to distinguish between these when we support NT
2859 dmA
= DEVMODEdupWtoA(GetProcessHeap(), dmW
);
2860 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2861 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2862 HeapFree(GetProcessHeap(), 0, dmA
);
2864 HeapFree(GetProcessHeap(), 0, dmW
);
2866 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2867 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2868 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2869 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2871 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2872 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2873 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2874 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2875 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2876 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2877 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2878 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2879 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2880 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2881 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2882 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2883 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2885 RegCloseKey(hkeyPrinter
);
2886 RegCloseKey(hkeyPrinters
);
2887 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2888 ERR("OpenPrinter failing\n");
2894 /*****************************************************************************
2895 * AddPrinterA [WINSPOOL.@]
2897 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2899 UNICODE_STRING pNameW
;
2901 PRINTER_INFO_2W
*piW
;
2902 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2905 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
2907 ERR("Level = %d, unsupported!\n", Level
);
2908 SetLastError(ERROR_INVALID_LEVEL
);
2911 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2912 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2914 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2916 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2917 RtlFreeUnicodeString(&pNameW
);
2922 /*****************************************************************************
2923 * ClosePrinter [WINSPOOL.@]
2925 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2927 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2928 opened_printer_t
*printer
= NULL
;
2931 TRACE("(%p)\n", hPrinter
);
2933 EnterCriticalSection(&printer_handles_cs
);
2935 if ((i
> 0) && (i
<= nb_printer_handles
))
2936 printer
= printer_handles
[i
- 1];
2941 struct list
*cursor
, *cursor2
;
2943 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer
->pm
,
2944 debugstr_w(printer
->pm
? printer
->pm
->dllname
: NULL
),
2945 printer
->hXcv
, debugstr_w(printer
->name
), printer
->doc
);
2948 EndDocPrinter(hPrinter
);
2950 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2952 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2954 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2955 ScheduleJob(hPrinter
, job
->job_id
);
2957 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2959 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
2960 monitor_unload(printer
->pm
);
2961 HeapFree(GetProcessHeap(), 0, printer
->printername
);
2962 HeapFree(GetProcessHeap(), 0, printer
->name
);
2963 HeapFree(GetProcessHeap(), 0, printer
);
2964 printer_handles
[i
- 1] = NULL
;
2967 LeaveCriticalSection(&printer_handles_cs
);
2971 /*****************************************************************************
2972 * DeleteFormA [WINSPOOL.@]
2974 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2976 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2980 /*****************************************************************************
2981 * DeleteFormW [WINSPOOL.@]
2983 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2985 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2989 /*****************************************************************************
2990 * DeletePrinter [WINSPOOL.@]
2992 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2994 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2995 HKEY hkeyPrinters
, hkey
;
2998 SetLastError(ERROR_INVALID_HANDLE
);
3001 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3002 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3003 RegCloseKey(hkeyPrinters
);
3005 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3006 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3007 RegDeleteValueW(hkey
, lpNameW
);
3013 /*****************************************************************************
3014 * SetPrinterA [WINSPOOL.@]
3016 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3019 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
3023 /*****************************************************************************
3024 * SetJobA [WINSPOOL.@]
3026 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3027 LPBYTE pJob
, DWORD Command
)
3031 UNICODE_STRING usBuffer
;
3033 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3035 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3036 are all ignored by SetJob, so we don't bother copying them */
3044 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3045 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3047 JobW
= (LPBYTE
)info1W
;
3048 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3049 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3050 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3051 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3052 info1W
->Status
= info1A
->Status
;
3053 info1W
->Priority
= info1A
->Priority
;
3054 info1W
->Position
= info1A
->Position
;
3055 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3060 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3061 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3063 JobW
= (LPBYTE
)info2W
;
3064 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3065 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3066 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3067 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3068 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3069 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3070 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3071 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3072 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3073 info2W
->Status
= info2A
->Status
;
3074 info2W
->Priority
= info2A
->Priority
;
3075 info2W
->Position
= info2A
->Position
;
3076 info2W
->StartTime
= info2A
->StartTime
;
3077 info2W
->UntilTime
= info2A
->UntilTime
;
3078 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3082 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3083 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3086 SetLastError(ERROR_INVALID_LEVEL
);
3090 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3096 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3097 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3098 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3099 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3100 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3105 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3106 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3107 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3108 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3109 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3110 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3111 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3112 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3113 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3117 HeapFree(GetProcessHeap(), 0, JobW
);
3122 /*****************************************************************************
3123 * SetJobW [WINSPOOL.@]
3125 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3126 LPBYTE pJob
, DWORD Command
)
3131 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3132 FIXME("Ignoring everything other than document title\n");
3134 EnterCriticalSection(&printer_handles_cs
);
3135 job
= get_job(hPrinter
, JobId
);
3145 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3146 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3147 job
->document_title
= strdupW(info1
->pDocument
);
3152 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3153 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3154 job
->document_title
= strdupW(info2
->pDocument
);
3160 SetLastError(ERROR_INVALID_LEVEL
);
3165 LeaveCriticalSection(&printer_handles_cs
);
3169 /*****************************************************************************
3170 * EndDocPrinter [WINSPOOL.@]
3172 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3174 opened_printer_t
*printer
;
3176 TRACE("(%p)\n", hPrinter
);
3178 EnterCriticalSection(&printer_handles_cs
);
3180 printer
= get_opened_printer(hPrinter
);
3183 SetLastError(ERROR_INVALID_HANDLE
);
3189 SetLastError(ERROR_SPL_NO_STARTDOC
);
3193 CloseHandle(printer
->doc
->hf
);
3194 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3195 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3196 printer
->doc
= NULL
;
3199 LeaveCriticalSection(&printer_handles_cs
);
3203 /*****************************************************************************
3204 * EndPagePrinter [WINSPOOL.@]
3206 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3208 FIXME("(%p): stub\n", hPrinter
);
3212 /*****************************************************************************
3213 * StartDocPrinterA [WINSPOOL.@]
3215 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3217 UNICODE_STRING usBuffer
;
3219 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3222 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3223 or one (DOC_INFO_3) extra DWORDs */
3227 doc2W
.JobId
= doc2
->JobId
;
3230 doc2W
.dwMode
= doc2
->dwMode
;
3233 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3234 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3235 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3239 SetLastError(ERROR_INVALID_LEVEL
);
3243 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3245 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3246 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3247 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3252 /*****************************************************************************
3253 * StartDocPrinterW [WINSPOOL.@]
3255 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3257 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3258 opened_printer_t
*printer
;
3259 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3260 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3261 JOB_INFO_1W job_info
;
3262 DWORD needed
, ret
= 0;
3266 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3267 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3268 debugstr_w(doc
->pDatatype
));
3270 if(Level
< 1 || Level
> 3)
3272 SetLastError(ERROR_INVALID_LEVEL
);
3276 EnterCriticalSection(&printer_handles_cs
);
3277 printer
= get_opened_printer(hPrinter
);
3280 SetLastError(ERROR_INVALID_HANDLE
);
3286 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3290 /* Even if we're printing to a file we still add a print job, we'll
3291 just ignore the spool file name */
3293 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3295 ERR("AddJob failed gle %u\n", GetLastError());
3299 if(doc
->pOutputFile
)
3300 filename
= doc
->pOutputFile
;
3302 filename
= addjob
->Path
;
3304 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3305 if(hf
== INVALID_HANDLE_VALUE
)
3308 memset(&job_info
, 0, sizeof(job_info
));
3309 job_info
.pDocument
= doc
->pDocName
;
3310 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3312 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3313 printer
->doc
->hf
= hf
;
3314 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3316 LeaveCriticalSection(&printer_handles_cs
);
3321 /*****************************************************************************
3322 * StartPagePrinter [WINSPOOL.@]
3324 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3326 FIXME("(%p): stub\n", hPrinter
);
3330 /*****************************************************************************
3331 * GetFormA [WINSPOOL.@]
3333 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3334 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3336 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3337 Level
,pForm
,cbBuf
,pcbNeeded
);
3341 /*****************************************************************************
3342 * GetFormW [WINSPOOL.@]
3344 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3345 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3347 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3348 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3352 /*****************************************************************************
3353 * SetFormA [WINSPOOL.@]
3355 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3358 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3362 /*****************************************************************************
3363 * SetFormW [WINSPOOL.@]
3365 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3368 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3372 /*****************************************************************************
3373 * ReadPrinter [WINSPOOL.@]
3375 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3376 LPDWORD pNoBytesRead
)
3378 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3382 /*****************************************************************************
3383 * ResetPrinterA [WINSPOOL.@]
3385 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3387 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3391 /*****************************************************************************
3392 * ResetPrinterW [WINSPOOL.@]
3394 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3396 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3400 /*****************************************************************************
3401 * WINSPOOL_GetDWORDFromReg
3403 * Return DWORD associated with ValueName from hkey.
3405 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3407 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3410 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3412 if(ret
!= ERROR_SUCCESS
) {
3413 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3416 if(type
!= REG_DWORD
) {
3417 ERR("Got type %d\n", type
);
3424 /*****************************************************************************
3425 * get_filename_from_reg [internal]
3427 * Get ValueName from hkey storing result in out
3428 * when the Value in the registry has only a filename, use driverdir as prefix
3429 * outlen is space left in out
3430 * String is stored either as unicode or ascii
3434 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3435 LPBYTE out
, DWORD outlen
, LPDWORD needed
, BOOL unicode
)
3437 WCHAR filename
[MAX_PATH
];
3441 LPWSTR buffer
= filename
;
3445 size
= sizeof(filename
);
3447 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3448 if (ret
== ERROR_MORE_DATA
) {
3449 TRACE("need dynamic buffer: %u\n", size
);
3450 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3452 /* No Memory is bad */
3456 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3459 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3460 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3466 /* do we have a full path ? */
3467 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3468 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3471 /* we must build the full Path */
3473 if ((out
) && (outlen
> dirlen
)) {
3475 lstrcpyW((LPWSTR
)out
, driverdir
);
3479 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3488 /* write the filename */
3490 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3491 if ((out
) && (outlen
>= size
)) {
3492 lstrcpyW((LPWSTR
)out
, ptr
);
3501 size
= WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, NULL
, 0, NULL
, NULL
);
3502 if ((out
) && (outlen
>= size
)) {
3503 WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3511 ptr
+= lstrlenW(ptr
)+1;
3512 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3515 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3517 /* write the multisz-termination */
3518 if (type
== REG_MULTI_SZ
) {
3519 size
= (unicode
) ? sizeof(WCHAR
) : 1;
3522 if (out
&& (outlen
>= size
)) {
3523 memset (out
, 0, size
);
3529 /*****************************************************************************
3530 * WINSPOOL_GetStringFromReg
3532 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3533 * String is stored either as unicode or ascii.
3534 * Bit of a hack here to get the ValueName if we want ascii.
3536 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3537 DWORD buflen
, DWORD
*needed
,
3540 DWORD sz
= buflen
, type
;
3544 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3546 LPSTR ValueNameA
= strdupWtoA(ValueName
);
3547 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
3548 HeapFree(GetProcessHeap(),0,ValueNameA
);
3550 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3551 WARN("Got ret = %d\n", ret
);
3555 /* add space for terminating '\0' */
3556 sz
+= unicode
? sizeof(WCHAR
) : 1;
3560 TRACE("%s: %s\n", debugstr_w(ValueName
), unicode
? debugstr_w((LPCWSTR
)ptr
) : debugstr_a((LPCSTR
)ptr
));
3565 /*****************************************************************************
3566 * WINSPOOL_GetDefaultDevMode
3568 * Get a default DevMode values for wineps.
3572 static void WINSPOOL_GetDefaultDevMode(
3574 DWORD buflen
, DWORD
*needed
,
3578 static const char szwps
[] = "wineps.drv";
3580 /* fill default DEVMODE - should be read from ppd... */
3581 ZeroMemory( &dm
, sizeof(dm
) );
3582 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
3583 dm
.dmSpecVersion
= DM_SPECVERSION
;
3584 dm
.dmDriverVersion
= 1;
3585 dm
.dmSize
= sizeof(DEVMODEA
);
3586 dm
.dmDriverExtra
= 0;
3588 DM_ORIENTATION
| DM_PAPERSIZE
|
3589 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3592 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3593 DM_YRESOLUTION
| DM_TTOPTION
;
3595 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3596 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3597 dm
.u1
.s1
.dmPaperLength
= 2970;
3598 dm
.u1
.s1
.dmPaperWidth
= 2100;
3602 dm
.dmDefaultSource
= DMBIN_AUTO
;
3603 dm
.dmPrintQuality
= DMRES_MEDIUM
;
3606 dm
.dmYResolution
= 300; /* 300dpi */
3607 dm
.dmTTOption
= DMTT_BITMAP
;
3610 /* dm.dmLogPixels */
3611 /* dm.dmBitsPerPel */
3612 /* dm.dmPelsWidth */
3613 /* dm.dmPelsHeight */
3614 /* dm.dmDisplayFlags */
3615 /* dm.dmDisplayFrequency */
3616 /* dm.dmICMMethod */
3617 /* dm.dmICMIntent */
3618 /* dm.dmMediaType */
3619 /* dm.dmDitherType */
3620 /* dm.dmReserved1 */
3621 /* dm.dmReserved2 */
3622 /* dm.dmPanningWidth */
3623 /* dm.dmPanningHeight */
3626 if(buflen
>= sizeof(DEVMODEW
)) {
3627 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
3628 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
3629 HeapFree(GetProcessHeap(),0,pdmW
);
3631 *needed
= sizeof(DEVMODEW
);
3635 if(buflen
>= sizeof(DEVMODEA
)) {
3636 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
3638 *needed
= sizeof(DEVMODEA
);
3642 /*****************************************************************************
3643 * WINSPOOL_GetDevModeFromReg
3645 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3646 * DevMode is stored either as unicode or ascii.
3648 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3650 DWORD buflen
, DWORD
*needed
,
3653 DWORD sz
= buflen
, type
;
3656 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3657 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3658 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3659 if (sz
< sizeof(DEVMODEA
))
3661 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3664 /* ensures that dmSize is not erratically bogus if registry is invalid */
3665 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3666 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3668 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3670 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3671 memcpy(ptr
, dmW
, sz
);
3672 HeapFree(GetProcessHeap(),0,dmW
);
3679 /*********************************************************************
3680 * WINSPOOL_GetPrinter_1
3682 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3683 * The strings are either stored as unicode or ascii.
3685 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3686 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3689 DWORD size
, left
= cbBuf
;
3690 BOOL space
= (cbBuf
> 0);
3695 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3697 if(space
&& size
<= left
) {
3698 pi1
->pName
= (LPWSTR
)ptr
;
3706 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3707 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3709 if(space
&& size
<= left
) {
3710 pi1
->pDescription
= (LPWSTR
)ptr
;
3718 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3720 if(space
&& size
<= left
) {
3721 pi1
->pComment
= (LPWSTR
)ptr
;
3729 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3731 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3732 memset(pi1
, 0, sizeof(*pi1
));
3736 /*********************************************************************
3737 * WINSPOOL_GetPrinter_2
3739 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3740 * The strings are either stored as unicode or ascii.
3742 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3743 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3746 DWORD size
, left
= cbBuf
;
3747 BOOL space
= (cbBuf
> 0);
3752 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3754 if(space
&& size
<= left
) {
3755 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3762 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
3764 if(space
&& size
<= left
) {
3765 pi2
->pShareName
= (LPWSTR
)ptr
;
3772 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3774 if(space
&& size
<= left
) {
3775 pi2
->pPortName
= (LPWSTR
)ptr
;
3782 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
3784 if(space
&& size
<= left
) {
3785 pi2
->pDriverName
= (LPWSTR
)ptr
;
3792 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3794 if(space
&& size
<= left
) {
3795 pi2
->pComment
= (LPWSTR
)ptr
;
3802 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
3804 if(space
&& size
<= left
) {
3805 pi2
->pLocation
= (LPWSTR
)ptr
;
3812 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
3814 if(space
&& size
<= left
) {
3815 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3824 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
3825 if(space
&& size
<= left
) {
3826 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3833 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
3835 if(space
&& size
<= left
) {
3836 pi2
->pSepFile
= (LPWSTR
)ptr
;
3843 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
3845 if(space
&& size
<= left
) {
3846 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3853 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
3855 if(space
&& size
<= left
) {
3856 pi2
->pDatatype
= (LPWSTR
)ptr
;
3863 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
3865 if(space
&& size
<= left
) {
3866 pi2
->pParameters
= (LPWSTR
)ptr
;
3874 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3875 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3876 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3877 "Default Priority");
3878 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3879 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3882 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3883 memset(pi2
, 0, sizeof(*pi2
));
3888 /*********************************************************************
3889 * WINSPOOL_GetPrinter_4
3891 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3893 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3894 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3897 DWORD size
, left
= cbBuf
;
3898 BOOL space
= (cbBuf
> 0);
3903 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3905 if(space
&& size
<= left
) {
3906 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3914 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3917 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3918 memset(pi4
, 0, sizeof(*pi4
));
3923 /*********************************************************************
3924 * WINSPOOL_GetPrinter_5
3926 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3928 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3929 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3932 DWORD size
, left
= cbBuf
;
3933 BOOL space
= (cbBuf
> 0);
3938 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3940 if(space
&& size
<= left
) {
3941 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3948 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3950 if(space
&& size
<= left
) {
3951 pi5
->pPortName
= (LPWSTR
)ptr
;
3959 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3960 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3962 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3966 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3967 memset(pi5
, 0, sizeof(*pi5
));
3972 /*****************************************************************************
3973 * WINSPOOL_GetPrinter
3975 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3976 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3977 * just a collection of pointers to strings.
3979 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3980 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
3983 DWORD size
, needed
= 0;
3985 HKEY hkeyPrinter
, hkeyPrinters
;
3988 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3990 if (!(name
= get_opened_printer_name(hPrinter
))) {
3991 SetLastError(ERROR_INVALID_HANDLE
);
3995 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3997 ERR("Can't create Printers key\n");
4000 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
4002 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4003 RegCloseKey(hkeyPrinters
);
4004 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4011 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4013 size
= sizeof(PRINTER_INFO_2W
);
4015 ptr
= pPrinter
+ size
;
4017 memset(pPrinter
, 0, size
);
4022 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
4030 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4032 size
= sizeof(PRINTER_INFO_4W
);
4034 ptr
= pPrinter
+ size
;
4036 memset(pPrinter
, 0, size
);
4041 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
4050 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4052 size
= sizeof(PRINTER_INFO_5W
);
4054 ptr
= pPrinter
+ size
;
4056 memset(pPrinter
, 0, size
);
4062 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
4069 FIXME("Unimplemented level %d\n", Level
);
4070 SetLastError(ERROR_INVALID_LEVEL
);
4071 RegCloseKey(hkeyPrinters
);
4072 RegCloseKey(hkeyPrinter
);
4076 RegCloseKey(hkeyPrinter
);
4077 RegCloseKey(hkeyPrinters
);
4079 TRACE("returning %d needed = %d\n", ret
, needed
);
4080 if(pcbNeeded
) *pcbNeeded
= needed
;
4082 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4086 /*****************************************************************************
4087 * GetPrinterW [WINSPOOL.@]
4089 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4090 DWORD cbBuf
, LPDWORD pcbNeeded
)
4092 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4096 /*****************************************************************************
4097 * GetPrinterA [WINSPOOL.@]
4099 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4100 DWORD cbBuf
, LPDWORD pcbNeeded
)
4102 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4106 /*****************************************************************************
4107 * WINSPOOL_EnumPrinters
4109 * Implementation of EnumPrintersA|W
4111 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
4112 DWORD dwLevel
, LPBYTE lpbPrinters
,
4113 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4114 LPDWORD lpdwReturned
, BOOL unicode
)
4117 HKEY hkeyPrinters
, hkeyPrinter
;
4118 WCHAR PrinterName
[255];
4119 DWORD needed
= 0, number
= 0;
4120 DWORD used
, i
, left
;
4124 memset(lpbPrinters
, 0, cbBuf
);
4130 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4131 if(dwType
== PRINTER_ENUM_DEFAULT
)
4134 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4135 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4136 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4138 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4146 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4147 FIXME("dwType = %08x\n", dwType
);
4148 SetLastError(ERROR_INVALID_FLAGS
);
4152 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4154 ERR("Can't create Printers key\n");
4158 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4159 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4160 RegCloseKey(hkeyPrinters
);
4161 ERR("Can't query Printers key\n");
4164 TRACE("Found %d printers\n", number
);
4168 used
= number
* sizeof(PRINTER_INFO_1W
);
4171 used
= number
* sizeof(PRINTER_INFO_2W
);
4174 used
= number
* sizeof(PRINTER_INFO_4W
);
4177 used
= number
* sizeof(PRINTER_INFO_5W
);
4181 SetLastError(ERROR_INVALID_LEVEL
);
4182 RegCloseKey(hkeyPrinters
);
4185 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4187 for(i
= 0; i
< number
; i
++) {
4188 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) !=
4190 ERR("Can't enum key number %d\n", i
);
4191 RegCloseKey(hkeyPrinters
);
4194 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4195 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4197 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4198 RegCloseKey(hkeyPrinters
);
4203 buf
= lpbPrinters
+ used
;
4204 left
= cbBuf
- used
;
4212 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4213 left
, &needed
, unicode
);
4215 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4218 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4219 left
, &needed
, unicode
);
4221 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4224 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4225 left
, &needed
, unicode
);
4227 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4230 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4231 left
, &needed
, unicode
);
4233 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4236 ERR("Shouldn't be here!\n");
4237 RegCloseKey(hkeyPrinter
);
4238 RegCloseKey(hkeyPrinters
);
4241 RegCloseKey(hkeyPrinter
);
4243 RegCloseKey(hkeyPrinters
);
4250 memset(lpbPrinters
, 0, cbBuf
);
4251 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4255 *lpdwReturned
= number
;
4256 SetLastError(ERROR_SUCCESS
);
4261 /******************************************************************
4262 * EnumPrintersW [WINSPOOL.@]
4264 * Enumerates the available printers, print servers and print
4265 * providers, depending on the specified flags, name and level.
4269 * If level is set to 1:
4270 * Returns an array of PRINTER_INFO_1 data structures in the
4271 * lpbPrinters buffer.
4273 * If level is set to 2:
4274 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4275 * Returns an array of PRINTER_INFO_2 data structures in the
4276 * lpbPrinters buffer. Note that according to MSDN also an
4277 * OpenPrinter should be performed on every remote printer.
4279 * If level is set to 4 (officially WinNT only):
4280 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4281 * Fast: Only the registry is queried to retrieve printer names,
4282 * no connection to the driver is made.
4283 * Returns an array of PRINTER_INFO_4 data structures in the
4284 * lpbPrinters buffer.
4286 * If level is set to 5 (officially WinNT4/Win9x only):
4287 * Fast: Only the registry is queried to retrieve printer names,
4288 * no connection to the driver is made.
4289 * Returns an array of PRINTER_INFO_5 data structures in the
4290 * lpbPrinters buffer.
4292 * If level set to 3 or 6+:
4293 * returns zero (failure!)
4295 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4299 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4300 * - Only levels 2, 4 and 5 are implemented at the moment.
4301 * - 16-bit printer drivers are not enumerated.
4302 * - Returned amount of bytes used/needed does not match the real Windoze
4303 * implementation (as in this implementation, all strings are part
4304 * of the buffer, whereas Win32 keeps them somewhere else)
4305 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4308 * - In a regular Wine installation, no registry settings for printers
4309 * exist, which makes this function return an empty list.
4311 BOOL WINAPI
EnumPrintersW(
4312 DWORD dwType
, /* [in] Types of print objects to enumerate */
4313 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4314 DWORD dwLevel
, /* [in] type of printer info structure */
4315 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4316 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4317 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4318 LPDWORD lpdwReturned
/* [out] number of entries returned */
4321 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4322 lpdwNeeded
, lpdwReturned
, TRUE
);
4325 /******************************************************************
4326 * EnumPrintersA [WINSPOOL.@]
4329 BOOL WINAPI
EnumPrintersA(DWORD dwType
, LPSTR lpszName
,
4330 DWORD dwLevel
, LPBYTE lpbPrinters
,
4331 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4332 LPDWORD lpdwReturned
)
4334 BOOL ret
, unicode
= FALSE
;
4335 UNICODE_STRING lpszNameW
;
4338 pwstrNameW
= asciitounicode(&lpszNameW
,lpszName
);
4339 if(!cbBuf
) unicode
= TRUE
; /* return a buffer that's big enough for the unicode version */
4340 ret
= WINSPOOL_EnumPrinters(dwType
, pwstrNameW
, dwLevel
, lpbPrinters
, cbBuf
,
4341 lpdwNeeded
, lpdwReturned
, unicode
);
4342 RtlFreeUnicodeString(&lpszNameW
);
4346 /*****************************************************************************
4347 * WINSPOOL_GetDriverInfoFromReg [internal]
4349 * Enters the information from the registry into the DRIVER_INFO struct
4352 * zero if the printer driver does not exist in the registry
4353 * (only if Level > 1) otherwise nonzero
4355 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4358 const printenv_t
* env
,
4360 LPBYTE ptr
, /* DRIVER_INFO */
4361 LPBYTE pDriverStrings
, /* strings buffer */
4362 DWORD cbBuf
, /* size of string buffer */
4363 LPDWORD pcbNeeded
, /* space needed for str. */
4364 BOOL unicode
) /* type of strings */
4368 WCHAR driverdir
[MAX_PATH
];
4370 LPBYTE strPtr
= pDriverStrings
;
4371 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4373 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers
,
4374 debugstr_w(DriverName
), env
,
4375 Level
, di
, pDriverStrings
, cbBuf
, unicode
);
4377 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4380 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4381 if (*pcbNeeded
<= cbBuf
)
4382 strcpyW((LPWSTR
)strPtr
, DriverName
);
4386 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0, NULL
, NULL
);
4387 if (*pcbNeeded
<= cbBuf
)
4388 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
4391 /* pName for level 1 has a different offset! */
4393 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4397 /* .cVersion and .pName for level > 1 */
4399 di
->cVersion
= env
->driverversion
;
4400 di
->pName
= (LPWSTR
) strPtr
;
4401 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4404 /* Reserve Space for the largest subdir and a Backslash*/
4405 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4406 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4407 /* Should never Fail */
4410 lstrcatW(driverdir
, env
->versionsubdir
);
4411 lstrcatW(driverdir
, backslashW
);
4413 /* dirlen must not include the terminating zero */
4414 dirlen
= (unicode
) ? lstrlenW(driverdir
) * sizeof(WCHAR
) :
4415 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, NULL
, 0, NULL
, NULL
) -1;
4417 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4418 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4419 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4425 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4427 size
= WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, NULL
, 0, NULL
, NULL
);
4430 if (*pcbNeeded
<= cbBuf
) {
4432 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4436 WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, (LPSTR
)strPtr
, size
, NULL
, NULL
);
4438 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4439 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4442 /* .pDriverPath is the Graphics rendering engine.
4443 The full Path is required to avoid a crash in some apps */
4444 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
, unicode
)) {
4446 if (*pcbNeeded
<= cbBuf
)
4447 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
, unicode
);
4449 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4450 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4453 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4454 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
, unicode
)) {
4456 if (*pcbNeeded
<= cbBuf
)
4457 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
, unicode
);
4459 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4460 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4463 /* .pConfigFile is the Driver user Interface */
4464 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
, unicode
)) {
4466 if (*pcbNeeded
<= cbBuf
)
4467 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
, unicode
);
4469 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4470 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4474 RegCloseKey(hkeyDriver
);
4475 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4480 RegCloseKey(hkeyDriver
);
4481 FIXME("level 5: incomplete\n");
4486 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
, unicode
)) {
4488 if (*pcbNeeded
<= cbBuf
)
4489 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
, unicode
);
4491 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4492 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4495 /* .pDependentFiles */
4496 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
, unicode
)) {
4498 if (*pcbNeeded
<= cbBuf
)
4499 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
, unicode
);
4501 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4502 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4505 /* .pMonitorName is the optional Language Monitor */
4506 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
, unicode
)) {
4508 if (*pcbNeeded
<= cbBuf
)
4509 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
, unicode
);
4511 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4512 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4515 /* .pDefaultDataType */
4516 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
, unicode
)) {
4518 if(*pcbNeeded
<= cbBuf
)
4519 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
, unicode
);
4521 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4522 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4526 RegCloseKey(hkeyDriver
);
4527 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4531 /* .pszzPreviousNames */
4532 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
, unicode
)) {
4534 if(*pcbNeeded
<= cbBuf
)
4535 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
, unicode
);
4537 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4538 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4542 RegCloseKey(hkeyDriver
);
4543 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4547 /* support is missing, but not important enough for a FIXME */
4548 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4551 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
, unicode
)) {
4553 if(*pcbNeeded
<= cbBuf
)
4554 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
, unicode
);
4556 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4557 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4561 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
, unicode
)) {
4563 if(*pcbNeeded
<= cbBuf
)
4564 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
, unicode
);
4566 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4567 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4570 /* .pszHardwareID */
4571 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
, unicode
)) {
4573 if(*pcbNeeded
<= cbBuf
)
4574 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
, unicode
);
4576 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4577 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4581 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
, unicode
)) {
4583 if(*pcbNeeded
<= cbBuf
)
4584 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
, unicode
);
4586 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4587 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4591 RegCloseKey(hkeyDriver
);
4595 /* support is missing, but not important enough for a FIXME */
4596 TRACE("level 8: incomplete\n");
4598 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4599 RegCloseKey(hkeyDriver
);
4603 /*****************************************************************************
4604 * WINSPOOL_GetPrinterDriver
4606 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPCWSTR pEnvironment
,
4607 DWORD Level
, LPBYTE pDriverInfo
,
4608 DWORD cbBuf
, LPDWORD pcbNeeded
,
4612 WCHAR DriverName
[100];
4613 DWORD ret
, type
, size
, needed
= 0;
4615 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4616 const printenv_t
* env
;
4618 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4619 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4622 if (!(name
= get_opened_printer_name(hPrinter
))) {
4623 SetLastError(ERROR_INVALID_HANDLE
);
4627 if (Level
< 1 || Level
== 7 || Level
> 8) {
4628 SetLastError(ERROR_INVALID_LEVEL
);
4632 env
= validate_envW(pEnvironment
);
4633 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4635 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4637 ERR("Can't create Printers key\n");
4640 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4642 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4643 RegCloseKey(hkeyPrinters
);
4644 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4647 size
= sizeof(DriverName
);
4649 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4650 (LPBYTE
)DriverName
, &size
);
4651 RegCloseKey(hkeyPrinter
);
4652 RegCloseKey(hkeyPrinters
);
4653 if(ret
!= ERROR_SUCCESS
) {
4654 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4658 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
4660 ERR("Can't create Drivers key\n");
4664 size
= di_sizeof
[Level
];
4665 if ((size
<= cbBuf
) && pDriverInfo
)
4666 ptr
= pDriverInfo
+ size
;
4668 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4669 env
, Level
, pDriverInfo
, ptr
,
4670 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4671 &needed
, unicode
)) {
4672 RegCloseKey(hkeyDrivers
);
4676 RegCloseKey(hkeyDrivers
);
4678 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4679 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4680 if(cbBuf
>= needed
) return TRUE
;
4681 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4685 /*****************************************************************************
4686 * GetPrinterDriverA [WINSPOOL.@]
4688 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4689 DWORD Level
, LPBYTE pDriverInfo
,
4690 DWORD cbBuf
, LPDWORD pcbNeeded
)
4693 UNICODE_STRING pEnvW
;
4696 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4697 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
4698 cbBuf
, pcbNeeded
, FALSE
);
4699 RtlFreeUnicodeString(&pEnvW
);
4702 /*****************************************************************************
4703 * GetPrinterDriverW [WINSPOOL.@]
4705 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4706 DWORD Level
, LPBYTE pDriverInfo
,
4707 DWORD cbBuf
, LPDWORD pcbNeeded
)
4709 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
4710 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
4713 /*****************************************************************************
4714 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4716 * Return the PATH for the Printer-Drivers (UNICODE)
4719 * pName [I] Servername (NT only) or NULL (local Computer)
4720 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4721 * Level [I] Structure-Level (must be 1)
4722 * pDriverDirectory [O] PTR to Buffer that receives the Result
4723 * cbBuf [I] Size of Buffer at pDriverDirectory
4724 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4725 * required for pDriverDirectory
4728 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4729 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4730 * if cbBuf is too small
4732 * Native Values returned in pDriverDirectory on Success:
4733 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4734 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4735 *| win9x(Windows 4.0): "%winsysdir%"
4737 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4740 *- Only NULL or "" is supported for pName
4743 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4744 DWORD Level
, LPBYTE pDriverDirectory
,
4745 DWORD cbBuf
, LPDWORD pcbNeeded
)
4748 const printenv_t
* env
;
4750 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4751 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4752 if(pName
!= NULL
&& pName
[0]) {
4753 FIXME("pName unsupported: %s\n", debugstr_w(pName
));
4754 SetLastError(ERROR_INVALID_PARAMETER
);
4758 env
= validate_envW(pEnvironment
);
4759 if(!env
) return FALSE
; /* pEnvironment invalid or unsupported */
4762 WARN("(Level: %d) is ignored in win9x\n", Level
);
4763 SetLastError(ERROR_INVALID_LEVEL
);
4767 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4768 needed
= GetSystemDirectoryW(NULL
, 0);
4769 /* add the Size for the Subdirectories */
4770 needed
+= lstrlenW(spooldriversW
);
4771 needed
+= lstrlenW(env
->subdir
);
4772 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
4775 *pcbNeeded
= needed
;
4776 TRACE("required: 0x%x/%d\n", needed
, needed
);
4777 if(needed
> cbBuf
) {
4778 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4781 if(pcbNeeded
== NULL
) {
4782 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4783 SetLastError(RPC_X_NULL_REF_POINTER
);
4786 if(pDriverDirectory
== NULL
) {
4787 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4788 SetLastError(ERROR_INVALID_USER_BUFFER
);
4792 GetSystemDirectoryW((LPWSTR
) pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
4793 /* add the Subdirectories */
4794 lstrcatW((LPWSTR
) pDriverDirectory
, spooldriversW
);
4795 lstrcatW((LPWSTR
) pDriverDirectory
, env
->subdir
);
4796 TRACE(" => %s\n", debugstr_w((LPWSTR
) pDriverDirectory
));
4801 /*****************************************************************************
4802 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4804 * Return the PATH for the Printer-Drivers (ANSI)
4806 * See GetPrinterDriverDirectoryW.
4809 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4812 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4813 DWORD Level
, LPBYTE pDriverDirectory
,
4814 DWORD cbBuf
, LPDWORD pcbNeeded
)
4816 UNICODE_STRING nameW
, environmentW
;
4819 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4820 WCHAR
*driverDirectoryW
= NULL
;
4822 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4823 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4825 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4827 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4828 else nameW
.Buffer
= NULL
;
4829 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4830 else environmentW
.Buffer
= NULL
;
4832 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4833 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4836 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4837 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4839 *pcbNeeded
= needed
;
4840 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4842 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4844 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4846 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4847 RtlFreeUnicodeString(&environmentW
);
4848 RtlFreeUnicodeString(&nameW
);
4853 /*****************************************************************************
4854 * AddPrinterDriverA [WINSPOOL.@]
4856 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4859 HKEY hkeyDrivers
, hkeyName
;
4860 static CHAR empty
[] = "",
4863 TRACE("(%s,%d,%p)\n",debugstr_a(pName
),level
,pDriverInfo
);
4865 if(level
!= 2 && level
!= 3) {
4866 SetLastError(ERROR_INVALID_LEVEL
);
4869 if ((pName
) && (pName
[0])) {
4870 FIXME("pName= %s - unsupported\n", debugstr_a(pName
));
4871 SetLastError(ERROR_INVALID_PARAMETER
);
4875 WARN("pDriverInfo == NULL\n");
4876 SetLastError(ERROR_INVALID_PARAMETER
);
4881 di3
= *(DRIVER_INFO_3A
*)pDriverInfo
;
4883 memset(&di3
, 0, sizeof(di3
));
4884 memcpy(&di3
, pDriverInfo
, sizeof(DRIVER_INFO_2A
));
4887 if(!di3
.pName
|| !di3
.pDriverPath
|| !di3
.pConfigFile
||
4889 SetLastError(ERROR_INVALID_PARAMETER
);
4893 if(!di3
.pDefaultDataType
) di3
.pDefaultDataType
= empty
;
4894 if(!di3
.pDependentFiles
) di3
.pDependentFiles
= nullnull
;
4895 if(!di3
.pHelpFile
) di3
.pHelpFile
= empty
;
4896 if(!di3
.pMonitorName
) di3
.pMonitorName
= empty
;
4898 hkeyDrivers
= WINSPOOL_OpenDriverReg(di3
.pEnvironment
, FALSE
);
4901 ERR("Can't create Drivers key\n");
4905 if(level
== 2) { /* apparently can't overwrite with level2 */
4906 if(RegOpenKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) == ERROR_SUCCESS
) {
4907 RegCloseKey(hkeyName
);
4908 RegCloseKey(hkeyDrivers
);
4909 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3
.pName
));
4910 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
4914 if(RegCreateKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) != ERROR_SUCCESS
) {
4915 RegCloseKey(hkeyDrivers
);
4916 ERR("Can't create Name key\n");
4919 RegSetValueExA(hkeyName
, "Configuration File", 0, REG_SZ
, (LPBYTE
) di3
.pConfigFile
,
4920 lstrlenA(di3
.pConfigFile
) + 1);
4921 RegSetValueExA(hkeyName
, "Data File", 0, REG_SZ
, (LPBYTE
) di3
.pDataFile
, lstrlenA(di3
.pDataFile
) + 1);
4922 RegSetValueExA(hkeyName
, "Driver", 0, REG_SZ
, (LPBYTE
) di3
.pDriverPath
, lstrlenA(di3
.pDriverPath
) + 1);
4923 RegSetValueExA(hkeyName
, "Version", 0, REG_DWORD
, (LPBYTE
) &di3
.cVersion
,
4925 RegSetValueExA(hkeyName
, "Datatype", 0, REG_SZ
, (LPBYTE
) di3
.pDefaultDataType
, lstrlenA(di3
.pDefaultDataType
));
4926 RegSetValueExA(hkeyName
, "Dependent Files", 0, REG_MULTI_SZ
,
4927 (LPBYTE
) di3
.pDependentFiles
, multi_sz_lenA(di3
.pDependentFiles
));
4928 RegSetValueExA(hkeyName
, "Help File", 0, REG_SZ
, (LPBYTE
) di3
.pHelpFile
, lstrlenA(di3
.pHelpFile
) + 1);
4929 RegSetValueExA(hkeyName
, "Monitor", 0, REG_SZ
, (LPBYTE
) di3
.pMonitorName
, lstrlenA(di3
.pMonitorName
) + 1);
4930 RegCloseKey(hkeyName
);
4931 RegCloseKey(hkeyDrivers
);
4936 /*****************************************************************************
4937 * AddPrinterDriverW [WINSPOOL.@]
4939 BOOL WINAPI
AddPrinterDriverW(LPWSTR printerName
,DWORD level
,
4942 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName
),
4947 /*****************************************************************************
4948 * AddPrintProcessorA [WINSPOOL.@]
4950 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4951 LPSTR pPrintProcessorName
)
4953 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4954 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4958 /*****************************************************************************
4959 * AddPrintProcessorW [WINSPOOL.@]
4961 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4962 LPWSTR pPrintProcessorName
)
4964 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4965 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4969 /*****************************************************************************
4970 * AddPrintProvidorA [WINSPOOL.@]
4972 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4974 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4978 /*****************************************************************************
4979 * AddPrintProvidorW [WINSPOOL.@]
4981 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4983 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4987 /*****************************************************************************
4988 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4990 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4991 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4993 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4994 pDevModeOutput
, pDevModeInput
);
4998 /*****************************************************************************
4999 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5001 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5002 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5004 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5005 pDevModeOutput
, pDevModeInput
);
5009 /*****************************************************************************
5010 * PrinterProperties [WINSPOOL.@]
5012 * Displays a dialog to set the properties of the printer.
5015 * nonzero on success or zero on failure
5018 * implemented as stub only
5020 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5021 HANDLE hPrinter
/* [in] handle to printer object */
5023 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5024 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5028 /*****************************************************************************
5029 * EnumJobsA [WINSPOOL.@]
5032 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5033 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5036 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5037 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5039 if(pcbNeeded
) *pcbNeeded
= 0;
5040 if(pcReturned
) *pcReturned
= 0;
5045 /*****************************************************************************
5046 * EnumJobsW [WINSPOOL.@]
5049 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5050 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5053 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5054 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5056 if(pcbNeeded
) *pcbNeeded
= 0;
5057 if(pcReturned
) *pcReturned
= 0;
5061 /*****************************************************************************
5062 * WINSPOOL_EnumPrinterDrivers [internal]
5064 * Delivers information about all printer drivers installed on the
5065 * localhost or a given server
5068 * nonzero on success or zero on failure. If the buffer for the returned
5069 * information is too small the function will return an error
5072 * - only implemented for localhost, foreign hosts will return an error
5074 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5075 DWORD Level
, LPBYTE pDriverInfo
,
5076 DWORD cbBuf
, LPDWORD pcbNeeded
,
5077 LPDWORD pcReturned
, BOOL unicode
)
5080 DWORD i
, needed
, number
= 0, size
= 0;
5081 WCHAR DriverNameW
[255];
5083 const printenv_t
* env
;
5085 TRACE("%s,%s,%d,%p,%d,%d\n",
5086 debugstr_w(pName
), debugstr_w(pEnvironment
),
5087 Level
, pDriverInfo
, cbBuf
, unicode
);
5089 /* check for local drivers */
5090 if((pName
) && (pName
[0])) {
5091 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5092 SetLastError(ERROR_ACCESS_DENIED
);
5096 env
= validate_envW(pEnvironment
);
5097 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5099 /* check input parameter */
5100 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5101 SetLastError(ERROR_INVALID_LEVEL
);
5105 /* initialize return values */
5107 memset( pDriverInfo
, 0, cbBuf
);
5111 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
5113 ERR("Can't open Drivers key\n");
5117 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
5118 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5119 RegCloseKey(hkeyDrivers
);
5120 ERR("Can't query Drivers key\n");
5123 TRACE("Found %d Drivers\n", number
);
5125 /* get size of single struct
5126 * unicode and ascii structure have the same size
5128 size
= di_sizeof
[Level
];
5130 /* calculate required buffer size */
5131 *pcbNeeded
= size
* number
;
5133 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
5135 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
5136 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
))
5138 ERR("Can't enum key number %d\n", i
);
5139 RegCloseKey(hkeyDrivers
);
5142 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5144 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
5145 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5146 &needed
, unicode
)) {
5147 RegCloseKey(hkeyDrivers
);
5150 (*pcbNeeded
) += needed
;
5153 RegCloseKey(hkeyDrivers
);
5155 if(cbBuf
< *pcbNeeded
){
5156 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5160 *pcReturned
= number
;
5164 /*****************************************************************************
5165 * EnumPrinterDriversW [WINSPOOL.@]
5167 * see function EnumPrinterDrivers for RETURNS, BUGS
5169 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5170 LPBYTE pDriverInfo
, DWORD cbBuf
,
5171 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5173 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5174 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
5177 /*****************************************************************************
5178 * EnumPrinterDriversA [WINSPOOL.@]
5180 * see function EnumPrinterDrivers for RETURNS, BUGS
5182 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5183 LPBYTE pDriverInfo
, DWORD cbBuf
,
5184 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5186 UNICODE_STRING pNameW
, pEnvironmentW
;
5187 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5189 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5190 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5192 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
5193 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
5195 RtlFreeUnicodeString(&pNameW
);
5196 RtlFreeUnicodeString(&pEnvironmentW
);
5201 /******************************************************************************
5202 * EnumPortsA (WINSPOOL.@)
5207 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5208 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5211 LPBYTE bufferW
= NULL
;
5212 LPWSTR nameW
= NULL
;
5214 DWORD numentries
= 0;
5217 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5218 cbBuf
, pcbNeeded
, pcReturned
);
5220 /* convert servername to unicode */
5222 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5223 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5224 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5226 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5227 needed
= cbBuf
* sizeof(WCHAR
);
5228 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5229 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5231 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5232 if (pcbNeeded
) needed
= *pcbNeeded
;
5233 /* HeapReAlloc return NULL, when bufferW was NULL */
5234 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5235 HeapAlloc(GetProcessHeap(), 0, needed
);
5237 /* Try again with the large Buffer */
5238 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5240 needed
= pcbNeeded
? *pcbNeeded
: 0;
5241 numentries
= pcReturned
? *pcReturned
: 0;
5244 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5245 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5248 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5249 DWORD entrysize
= 0;
5252 LPPORT_INFO_2W pi2w
;
5253 LPPORT_INFO_2A pi2a
;
5256 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5258 /* First pass: calculate the size for all Entries */
5259 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5260 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5262 while (index
< numentries
) {
5264 needed
+= entrysize
; /* PORT_INFO_?A */
5265 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5267 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5268 NULL
, 0, NULL
, NULL
);
5270 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5271 NULL
, 0, NULL
, NULL
);
5272 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5273 NULL
, 0, NULL
, NULL
);
5275 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5276 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5277 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5280 /* check for errors and quit on failure */
5281 if (cbBuf
< needed
) {
5282 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5286 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5287 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5288 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5289 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5290 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5292 /* Second Pass: Fill the User Buffer (if we have one) */
5293 while ((index
< numentries
) && pPorts
) {
5295 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5296 pi2a
->pPortName
= ptr
;
5297 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5298 ptr
, cbBuf
, NULL
, NULL
);
5302 pi2a
->pMonitorName
= ptr
;
5303 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5304 ptr
, cbBuf
, NULL
, NULL
);
5308 pi2a
->pDescription
= ptr
;
5309 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5310 ptr
, cbBuf
, NULL
, NULL
);
5314 pi2a
->fPortType
= pi2w
->fPortType
;
5315 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5318 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5319 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5320 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5325 if (pcbNeeded
) *pcbNeeded
= needed
;
5326 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5328 HeapFree(GetProcessHeap(), 0, nameW
);
5329 HeapFree(GetProcessHeap(), 0, bufferW
);
5331 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5332 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5338 /******************************************************************************
5339 * EnumPortsW (WINSPOOL.@)
5341 * Enumerate available Ports
5344 * name [I] Servername or NULL (local Computer)
5345 * level [I] Structure-Level (1 or 2)
5346 * buffer [O] PTR to Buffer that receives the Result
5347 * bufsize [I] Size of Buffer at buffer
5348 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5349 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5353 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5357 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5360 DWORD numentries
= 0;
5363 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5364 cbBuf
, pcbNeeded
, pcReturned
);
5366 if (pName
&& (pName
[0])) {
5367 FIXME("not implemented for Server %s\n", debugstr_w(pName
));
5368 SetLastError(ERROR_ACCESS_DENIED
);
5372 /* Level is not checked in win9x */
5373 if (!Level
|| (Level
> 2)) {
5374 WARN("level (%d) is ignored in win9x\n", Level
);
5375 SetLastError(ERROR_INVALID_LEVEL
);
5379 SetLastError(RPC_X_NULL_REF_POINTER
);
5383 EnterCriticalSection(&monitor_handles_cs
);
5386 /* Scan all local Ports */
5388 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
5390 /* we calculated the needed buffersize. now do the error-checks */
5391 if (cbBuf
< needed
) {
5392 monitor_unloadall();
5393 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5394 goto emP_cleanup_cs
;
5396 else if (!pPorts
|| !pcReturned
) {
5397 monitor_unloadall();
5398 SetLastError(RPC_X_NULL_REF_POINTER
);
5399 goto emP_cleanup_cs
;
5402 /* Fill the Buffer */
5403 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
5405 monitor_unloadall();
5408 LeaveCriticalSection(&monitor_handles_cs
);
5411 if (pcbNeeded
) *pcbNeeded
= needed
;
5412 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5414 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5415 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5420 /******************************************************************************
5421 * GetDefaultPrinterW (WINSPOOL.@)
5424 * This function must read the value from data 'device' of key
5425 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5427 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5431 WCHAR
*buffer
, *ptr
;
5435 SetLastError(ERROR_INVALID_PARAMETER
);
5439 /* make the buffer big enough for the stuff from the profile/registry,
5440 * the content must fit into the local buffer to compute the correct
5441 * size even if the extern buffer is too small or not given.
5442 * (20 for ,driver,port) */
5444 len
= max(100, (insize
+ 20));
5445 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5447 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5449 SetLastError (ERROR_FILE_NOT_FOUND
);
5453 TRACE("%s\n", debugstr_w(buffer
));
5455 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5457 SetLastError(ERROR_INVALID_NAME
);
5463 *namesize
= strlenW(buffer
) + 1;
5464 if(!name
|| (*namesize
> insize
))
5466 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5470 strcpyW(name
, buffer
);
5473 HeapFree( GetProcessHeap(), 0, buffer
);
5478 /******************************************************************************
5479 * GetDefaultPrinterA (WINSPOOL.@)
5481 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5485 WCHAR
*bufferW
= NULL
;
5489 SetLastError(ERROR_INVALID_PARAMETER
);
5493 if(name
&& *namesize
) {
5495 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5498 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5503 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5507 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5510 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5513 HeapFree( GetProcessHeap(), 0, bufferW
);
5518 /******************************************************************************
5519 * SetDefaultPrinterW (WINSPOOL.204)
5521 * Set the Name of the Default Printer
5524 * pszPrinter [I] Name of the Printer or NULL
5531 * When the Parameter is NULL or points to an Empty String and
5532 * a Default Printer was already present, then this Function changes nothing.
5533 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5534 * the First enumerated local Printer is used.
5537 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5540 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5542 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5546 /******************************************************************************
5547 * SetDefaultPrinterA (WINSPOOL.202)
5549 * See SetDefaultPrinterW.
5552 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5555 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5557 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5562 /******************************************************************************
5563 * SetPrinterDataExA (WINSPOOL.@)
5565 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5566 LPCSTR pValueName
, DWORD Type
,
5567 LPBYTE pData
, DWORD cbData
)
5569 HKEY hkeyPrinter
, hkeySubkey
;
5572 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5573 debugstr_a(pValueName
), Type
, pData
, cbData
);
5575 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5579 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5581 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5582 RegCloseKey(hkeyPrinter
);
5585 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5586 RegCloseKey(hkeySubkey
);
5587 RegCloseKey(hkeyPrinter
);
5591 /******************************************************************************
5592 * SetPrinterDataExW (WINSPOOL.@)
5594 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5595 LPCWSTR pValueName
, DWORD Type
,
5596 LPBYTE pData
, DWORD cbData
)
5598 HKEY hkeyPrinter
, hkeySubkey
;
5601 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5602 debugstr_w(pValueName
), Type
, pData
, cbData
);
5604 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5608 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5610 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5611 RegCloseKey(hkeyPrinter
);
5614 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5615 RegCloseKey(hkeySubkey
);
5616 RegCloseKey(hkeyPrinter
);
5620 /******************************************************************************
5621 * SetPrinterDataA (WINSPOOL.@)
5623 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5624 LPBYTE pData
, DWORD cbData
)
5626 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5630 /******************************************************************************
5631 * SetPrinterDataW (WINSPOOL.@)
5633 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5634 LPBYTE pData
, DWORD cbData
)
5636 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5640 /******************************************************************************
5641 * GetPrinterDataExA (WINSPOOL.@)
5643 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5644 LPCSTR pValueName
, LPDWORD pType
,
5645 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5647 HKEY hkeyPrinter
, hkeySubkey
;
5650 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5651 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
5654 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5658 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5660 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
5661 RegCloseKey(hkeyPrinter
);
5665 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5666 RegCloseKey(hkeySubkey
);
5667 RegCloseKey(hkeyPrinter
);
5671 /******************************************************************************
5672 * GetPrinterDataExW (WINSPOOL.@)
5674 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5675 LPCWSTR pValueName
, LPDWORD pType
,
5676 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5678 HKEY hkeyPrinter
, hkeySubkey
;
5681 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5682 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
5685 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5689 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5691 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
5692 RegCloseKey(hkeyPrinter
);
5696 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5697 RegCloseKey(hkeySubkey
);
5698 RegCloseKey(hkeyPrinter
);
5702 /******************************************************************************
5703 * GetPrinterDataA (WINSPOOL.@)
5705 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5706 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5708 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5709 pData
, nSize
, pcbNeeded
);
5712 /******************************************************************************
5713 * GetPrinterDataW (WINSPOOL.@)
5715 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5716 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5718 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5719 pData
, nSize
, pcbNeeded
);
5722 /*******************************************************************************
5723 * EnumPrinterDataExW [WINSPOOL.@]
5725 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5726 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5727 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5729 HKEY hkPrinter
, hkSubKey
;
5730 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5731 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5736 PPRINTER_ENUM_VALUESW ppev
;
5738 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5740 if (pKeyName
== NULL
|| *pKeyName
== 0)
5741 return ERROR_INVALID_PARAMETER
;
5743 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5744 if (ret
!= ERROR_SUCCESS
)
5746 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5751 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5752 if (ret
!= ERROR_SUCCESS
)
5754 r
= RegCloseKey (hkPrinter
);
5755 if (r
!= ERROR_SUCCESS
)
5756 WARN ("RegCloseKey returned %i\n", r
);
5757 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5758 debugstr_w (pKeyName
), ret
);
5762 ret
= RegCloseKey (hkPrinter
);
5763 if (ret
!= ERROR_SUCCESS
)
5765 ERR ("RegCloseKey returned %i\n", ret
);
5766 r
= RegCloseKey (hkSubKey
);
5767 if (r
!= ERROR_SUCCESS
)
5768 WARN ("RegCloseKey returned %i\n", r
);
5772 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5773 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5774 if (ret
!= ERROR_SUCCESS
)
5776 r
= RegCloseKey (hkSubKey
);
5777 if (r
!= ERROR_SUCCESS
)
5778 WARN ("RegCloseKey returned %i\n", r
);
5779 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5783 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5784 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5786 if (cValues
== 0) /* empty key */
5788 r
= RegCloseKey (hkSubKey
);
5789 if (r
!= ERROR_SUCCESS
)
5790 WARN ("RegCloseKey returned %i\n", r
);
5791 *pcbEnumValues
= *pnEnumValues
= 0;
5792 return ERROR_SUCCESS
;
5795 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5797 hHeap
= GetProcessHeap ();
5800 ERR ("GetProcessHeap failed\n");
5801 r
= RegCloseKey (hkSubKey
);
5802 if (r
!= ERROR_SUCCESS
)
5803 WARN ("RegCloseKey returned %i\n", r
);
5804 return ERROR_OUTOFMEMORY
;
5807 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5808 if (lpValueName
== NULL
)
5810 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5811 r
= RegCloseKey (hkSubKey
);
5812 if (r
!= ERROR_SUCCESS
)
5813 WARN ("RegCloseKey returned %i\n", r
);
5814 return ERROR_OUTOFMEMORY
;
5817 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5818 if (lpValue
== NULL
)
5820 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5821 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5822 WARN ("HeapFree failed with code %i\n", GetLastError ());
5823 r
= RegCloseKey (hkSubKey
);
5824 if (r
!= ERROR_SUCCESS
)
5825 WARN ("RegCloseKey returned %i\n", r
);
5826 return ERROR_OUTOFMEMORY
;
5829 TRACE ("pass 1: calculating buffer required for all names and values\n");
5831 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5833 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5835 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5837 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5838 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5839 NULL
, NULL
, lpValue
, &cbValueLen
);
5840 if (ret
!= ERROR_SUCCESS
)
5842 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5843 WARN ("HeapFree failed with code %i\n", GetLastError ());
5844 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5845 WARN ("HeapFree failed with code %i\n", GetLastError ());
5846 r
= RegCloseKey (hkSubKey
);
5847 if (r
!= ERROR_SUCCESS
)
5848 WARN ("RegCloseKey returned %i\n", r
);
5849 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5853 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5854 debugstr_w (lpValueName
), dwIndex
,
5855 cbValueNameLen
+ 1, cbValueLen
);
5857 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5858 cbBufSize
+= cbValueLen
;
5861 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5863 *pcbEnumValues
= cbBufSize
;
5864 *pnEnumValues
= cValues
;
5866 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5868 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5869 WARN ("HeapFree failed with code %i\n", GetLastError ());
5870 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5871 WARN ("HeapFree failed with code %i\n", GetLastError ());
5872 r
= RegCloseKey (hkSubKey
);
5873 if (r
!= ERROR_SUCCESS
)
5874 WARN ("RegCloseKey returned %i\n", r
);
5875 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5876 return ERROR_MORE_DATA
;
5879 TRACE ("pass 2: copying all names and values to buffer\n");
5881 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5882 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5884 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5886 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5887 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5888 NULL
, &dwType
, lpValue
, &cbValueLen
);
5889 if (ret
!= ERROR_SUCCESS
)
5891 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5892 WARN ("HeapFree failed with code %i\n", GetLastError ());
5893 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5894 WARN ("HeapFree failed with code %i\n", GetLastError ());
5895 r
= RegCloseKey (hkSubKey
);
5896 if (r
!= ERROR_SUCCESS
)
5897 WARN ("RegCloseKey returned %i\n", r
);
5898 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5902 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5903 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5904 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5905 pEnumValues
+= cbValueNameLen
;
5907 /* return # of *bytes* (including trailing \0), not # of chars */
5908 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5910 ppev
[dwIndex
].dwType
= dwType
;
5912 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5913 ppev
[dwIndex
].pData
= pEnumValues
;
5914 pEnumValues
+= cbValueLen
;
5916 ppev
[dwIndex
].cbData
= cbValueLen
;
5918 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5919 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5922 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5924 ret
= GetLastError ();
5925 ERR ("HeapFree failed with code %i\n", ret
);
5926 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5927 WARN ("HeapFree failed with code %i\n", GetLastError ());
5928 r
= RegCloseKey (hkSubKey
);
5929 if (r
!= ERROR_SUCCESS
)
5930 WARN ("RegCloseKey returned %i\n", r
);
5934 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5936 ret
= GetLastError ();
5937 ERR ("HeapFree failed with code %i\n", ret
);
5938 r
= RegCloseKey (hkSubKey
);
5939 if (r
!= ERROR_SUCCESS
)
5940 WARN ("RegCloseKey returned %i\n", r
);
5944 ret
= RegCloseKey (hkSubKey
);
5945 if (ret
!= ERROR_SUCCESS
)
5947 ERR ("RegCloseKey returned %i\n", ret
);
5951 return ERROR_SUCCESS
;
5954 /*******************************************************************************
5955 * EnumPrinterDataExA [WINSPOOL.@]
5957 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5958 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5959 * what Windows 2000 SP1 does.
5962 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5963 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5964 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5968 DWORD ret
, dwIndex
, dwBufSize
;
5972 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5974 if (pKeyName
== NULL
|| *pKeyName
== 0)
5975 return ERROR_INVALID_PARAMETER
;
5977 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5980 ret
= GetLastError ();
5981 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5985 hHeap
= GetProcessHeap ();
5988 ERR ("GetProcessHeap failed\n");
5989 return ERROR_OUTOFMEMORY
;
5992 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5993 if (pKeyNameW
== NULL
)
5995 ERR ("Failed to allocate %i bytes from process heap\n",
5996 (LONG
)(len
* sizeof (WCHAR
)));
5997 return ERROR_OUTOFMEMORY
;
6000 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6002 ret
= GetLastError ();
6003 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6004 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6005 WARN ("HeapFree failed with code %i\n", GetLastError ());
6009 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6010 pcbEnumValues
, pnEnumValues
);
6011 if (ret
!= ERROR_SUCCESS
)
6013 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6014 WARN ("HeapFree failed with code %i\n", GetLastError ());
6015 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6019 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6021 ret
= GetLastError ();
6022 ERR ("HeapFree failed with code %i\n", ret
);
6026 if (*pnEnumValues
== 0) /* empty key */
6027 return ERROR_SUCCESS
;
6030 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6032 PPRINTER_ENUM_VALUESW ppev
=
6033 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6035 if (dwBufSize
< ppev
->cbValueName
)
6036 dwBufSize
= ppev
->cbValueName
;
6038 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6039 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6040 dwBufSize
= ppev
->cbData
;
6043 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6045 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6046 if (pBuffer
== NULL
)
6048 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6049 return ERROR_OUTOFMEMORY
;
6052 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6054 PPRINTER_ENUM_VALUESW ppev
=
6055 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6057 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6058 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6062 ret
= GetLastError ();
6063 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6064 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6065 WARN ("HeapFree failed with code %i\n", GetLastError ());
6069 memcpy (ppev
->pValueName
, pBuffer
, len
);
6071 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6073 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6074 ppev
->dwType
!= REG_MULTI_SZ
)
6077 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6078 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6081 ret
= GetLastError ();
6082 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6083 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6084 WARN ("HeapFree failed with code %i\n", GetLastError ());
6088 memcpy (ppev
->pData
, pBuffer
, len
);
6090 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6091 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6094 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6096 ret
= GetLastError ();
6097 ERR ("HeapFree failed with code %i\n", ret
);
6101 return ERROR_SUCCESS
;
6104 /******************************************************************************
6105 * AbortPrinter (WINSPOOL.@)
6107 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6109 FIXME("(%p), stub!\n", hPrinter
);
6113 /******************************************************************************
6114 * AddPortA (WINSPOOL.@)
6119 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6121 LPWSTR nameW
= NULL
;
6122 LPWSTR monitorW
= NULL
;
6126 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6129 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6130 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6131 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6135 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6136 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6137 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6139 res
= AddPortW(nameW
, hWnd
, monitorW
);
6140 HeapFree(GetProcessHeap(), 0, nameW
);
6141 HeapFree(GetProcessHeap(), 0, monitorW
);
6145 /******************************************************************************
6146 * AddPortW (WINSPOOL.@)
6148 * Add a Port for a specific Monitor
6151 * pName [I] Servername or NULL (local Computer)
6152 * hWnd [I] Handle to parent Window for the Dialog-Box
6153 * pMonitorName [I] Name of the Monitor that manage the Port
6160 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6166 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6168 if (pName
&& pName
[0]) {
6169 SetLastError(ERROR_INVALID_PARAMETER
);
6173 if (!pMonitorName
) {
6174 SetLastError(RPC_X_NULL_REF_POINTER
);
6178 /* an empty Monitorname is Invalid */
6179 if (!pMonitorName
[0]) {
6180 SetLastError(ERROR_NOT_SUPPORTED
);
6184 pm
= monitor_load(pMonitorName
, NULL
);
6185 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
6186 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
6187 TRACE("got %d with %u\n", res
, GetLastError());
6192 pui
= monitor_loadui(pm
);
6193 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
6194 TRACE("use %p: %s\n", pui
, debugstr_w(pui
->dllname
));
6195 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
6196 TRACE("got %d with %u\n", res
, GetLastError());
6201 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName
),
6202 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6204 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6205 SetLastError(ERROR_NOT_SUPPORTED
);
6208 monitor_unload(pui
);
6211 TRACE("returning %d with %u\n", res
, GetLastError());
6215 /******************************************************************************
6216 * AddPortExA (WINSPOOL.@)
6221 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6224 PORT_INFO_2A
* pi2A
;
6225 LPWSTR nameW
= NULL
;
6226 LPWSTR monitorW
= NULL
;
6230 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6232 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6233 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6235 if ((level
< 1) || (level
> 2)) {
6236 SetLastError(ERROR_INVALID_LEVEL
);
6241 SetLastError(ERROR_INVALID_PARAMETER
);
6246 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6247 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6248 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6252 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6253 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6254 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6257 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6259 if (pi2A
->pPortName
) {
6260 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6261 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6262 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6266 if (pi2A
->pMonitorName
) {
6267 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6268 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6269 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6272 if (pi2A
->pDescription
) {
6273 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6274 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6275 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6277 pi2W
.fPortType
= pi2A
->fPortType
;
6278 pi2W
.Reserved
= pi2A
->Reserved
;
6281 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6283 HeapFree(GetProcessHeap(), 0, nameW
);
6284 HeapFree(GetProcessHeap(), 0, monitorW
);
6285 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6286 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6287 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6292 /******************************************************************************
6293 * AddPortExW (WINSPOOL.@)
6295 * Add a Port for a specific Monitor, without presenting a user interface
6298 * pName [I] Servername or NULL (local Computer)
6299 * level [I] Structure-Level (1 or 2) for pBuffer
6300 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6301 * pMonitorName [I] Name of the Monitor that manage the Port
6308 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6314 pi2
= (PORT_INFO_2W
*) pBuffer
;
6316 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6317 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6318 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6319 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6322 if ((level
< 1) || (level
> 2)) {
6323 SetLastError(ERROR_INVALID_LEVEL
);
6327 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6328 SetLastError(ERROR_INVALID_PARAMETER
);
6332 /* load the Monitor */
6333 pm
= monitor_load(pMonitorName
, NULL
);
6335 SetLastError(ERROR_INVALID_PARAMETER
);
6339 if (pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
6340 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6341 TRACE("got %u with %u\n", res
, GetLastError());
6345 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName
), pm
->monitor
);
6351 /******************************************************************************
6352 * AddPrinterConnectionA (WINSPOOL.@)
6354 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6356 FIXME("%s\n", debugstr_a(pName
));
6360 /******************************************************************************
6361 * AddPrinterConnectionW (WINSPOOL.@)
6363 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6365 FIXME("%s\n", debugstr_w(pName
));
6369 /******************************************************************************
6370 * AddPrinterDriverExW (WINSPOOL.@)
6372 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD Level
,
6373 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6375 FIXME("%s %d %p %d\n", debugstr_w(pName
),
6376 Level
, pDriverInfo
, dwFileCopyFlags
);
6377 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
6381 /******************************************************************************
6382 * AddPrinterDriverExA (WINSPOOL.@)
6384 BOOL WINAPI
AddPrinterDriverExA( LPSTR pName
, DWORD Level
,
6385 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6387 FIXME("%s %d %p %d\n", debugstr_a(pName
),
6388 Level
, pDriverInfo
, dwFileCopyFlags
);
6389 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
6393 /******************************************************************************
6394 * ConfigurePortA (WINSPOOL.@)
6396 * See ConfigurePortW.
6399 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6401 LPWSTR nameW
= NULL
;
6402 LPWSTR portW
= NULL
;
6406 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6408 /* convert servername to unicode */
6410 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6411 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6412 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6415 /* convert portname to unicode */
6417 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6418 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6419 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6422 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6423 HeapFree(GetProcessHeap(), 0, nameW
);
6424 HeapFree(GetProcessHeap(), 0, portW
);
6428 /******************************************************************************
6429 * ConfigurePortW (WINSPOOL.@)
6431 * Display the Configuration-Dialog for a specific Port
6434 * pName [I] Servername or NULL (local Computer)
6435 * hWnd [I] Handle to parent Window for the Dialog-Box
6436 * pPortName [I] Name of the Port, that should be configured
6443 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6449 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6451 if (pName
&& pName
[0]) {
6452 SetLastError(ERROR_INVALID_PARAMETER
);
6457 SetLastError(RPC_X_NULL_REF_POINTER
);
6461 /* an empty Portname is Invalid, but can popup a Dialog */
6462 if (!pPortName
[0]) {
6463 SetLastError(ERROR_NOT_SUPPORTED
);
6467 pm
= monitor_load_by_port(pPortName
);
6468 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
6469 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
6470 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
6471 TRACE("got %d with %u\n", res
, GetLastError());
6475 pui
= monitor_loadui(pm
);
6476 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
6477 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
6478 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
6479 TRACE("got %d with %u\n", res
, GetLastError());
6483 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
6484 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6486 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6487 SetLastError(ERROR_NOT_SUPPORTED
);
6490 monitor_unload(pui
);
6494 TRACE("returning %d with %u\n", res
, GetLastError());
6498 /******************************************************************************
6499 * ConnectToPrinterDlg (WINSPOOL.@)
6501 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6503 FIXME("%p %x\n", hWnd
, Flags
);
6507 /******************************************************************************
6508 * DeletePrinterConnectionA (WINSPOOL.@)
6510 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6512 FIXME("%s\n", debugstr_a(pName
));
6516 /******************************************************************************
6517 * DeletePrinterConnectionW (WINSPOOL.@)
6519 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6521 FIXME("%s\n", debugstr_w(pName
));
6525 /******************************************************************************
6526 * DeletePrinterDriverExW (WINSPOOL.@)
6528 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6529 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6534 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6535 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6537 if(pName
&& pName
[0])
6539 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6540 SetLastError(ERROR_INVALID_PARAMETER
);
6546 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6547 SetLastError(ERROR_INVALID_PARAMETER
);
6551 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
6555 ERR("Can't open drivers key\n");
6559 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6562 RegCloseKey(hkey_drivers
);
6567 /******************************************************************************
6568 * DeletePrinterDriverExA (WINSPOOL.@)
6570 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6571 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6573 UNICODE_STRING NameW
, EnvW
, DriverW
;
6576 asciitounicode(&NameW
, pName
);
6577 asciitounicode(&EnvW
, pEnvironment
);
6578 asciitounicode(&DriverW
, pDriverName
);
6580 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6582 RtlFreeUnicodeString(&DriverW
);
6583 RtlFreeUnicodeString(&EnvW
);
6584 RtlFreeUnicodeString(&NameW
);
6589 /******************************************************************************
6590 * DeletePrinterDataExW (WINSPOOL.@)
6592 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6595 FIXME("%p %s %s\n", hPrinter
,
6596 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6597 return ERROR_INVALID_PARAMETER
;
6600 /******************************************************************************
6601 * DeletePrinterDataExA (WINSPOOL.@)
6603 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6606 FIXME("%p %s %s\n", hPrinter
,
6607 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6608 return ERROR_INVALID_PARAMETER
;
6611 /******************************************************************************
6612 * DeletePrintProcessorA (WINSPOOL.@)
6614 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6616 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6617 debugstr_a(pPrintProcessorName
));
6621 /******************************************************************************
6622 * DeletePrintProcessorW (WINSPOOL.@)
6624 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6626 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6627 debugstr_w(pPrintProcessorName
));
6631 /******************************************************************************
6632 * DeletePrintProvidorA (WINSPOOL.@)
6634 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6636 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6637 debugstr_a(pPrintProviderName
));
6641 /******************************************************************************
6642 * DeletePrintProvidorW (WINSPOOL.@)
6644 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6646 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6647 debugstr_w(pPrintProviderName
));
6651 /******************************************************************************
6652 * EnumFormsA (WINSPOOL.@)
6654 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6655 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6657 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6658 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6662 /******************************************************************************
6663 * EnumFormsW (WINSPOOL.@)
6665 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6666 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6668 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6669 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6673 /*****************************************************************************
6674 * EnumMonitorsA [WINSPOOL.@]
6676 * See EnumMonitorsW.
6679 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6680 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6683 LPBYTE bufferW
= NULL
;
6684 LPWSTR nameW
= NULL
;
6686 DWORD numentries
= 0;
6689 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6690 cbBuf
, pcbNeeded
, pcReturned
);
6692 /* convert servername to unicode */
6694 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6695 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6696 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6698 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6699 needed
= cbBuf
* sizeof(WCHAR
);
6700 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6701 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6703 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6704 if (pcbNeeded
) needed
= *pcbNeeded
;
6705 /* HeapReAlloc return NULL, when bufferW was NULL */
6706 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6707 HeapAlloc(GetProcessHeap(), 0, needed
);
6709 /* Try again with the large Buffer */
6710 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6712 numentries
= pcReturned
? *pcReturned
: 0;
6715 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6716 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6719 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6720 DWORD entrysize
= 0;
6723 LPMONITOR_INFO_2W mi2w
;
6724 LPMONITOR_INFO_2A mi2a
;
6726 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6727 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6729 /* First pass: calculate the size for all Entries */
6730 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6731 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6733 while (index
< numentries
) {
6735 needed
+= entrysize
; /* MONITOR_INFO_?A */
6736 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6738 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6739 NULL
, 0, NULL
, NULL
);
6741 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6742 NULL
, 0, NULL
, NULL
);
6743 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6744 NULL
, 0, NULL
, NULL
);
6746 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6747 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6748 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6751 /* check for errors and quit on failure */
6752 if (cbBuf
< needed
) {
6753 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6757 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6758 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6759 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6760 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6761 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6763 /* Second Pass: Fill the User Buffer (if we have one) */
6764 while ((index
< numentries
) && pMonitors
) {
6766 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6768 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6769 ptr
, cbBuf
, NULL
, NULL
);
6773 mi2a
->pEnvironment
= ptr
;
6774 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6775 ptr
, cbBuf
, NULL
, NULL
);
6779 mi2a
->pDLLName
= ptr
;
6780 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6781 ptr
, cbBuf
, NULL
, NULL
);
6785 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6786 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6787 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6791 if (pcbNeeded
) *pcbNeeded
= needed
;
6792 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6794 HeapFree(GetProcessHeap(), 0, nameW
);
6795 HeapFree(GetProcessHeap(), 0, bufferW
);
6797 TRACE("returning %d with %d (%d byte for %d entries)\n",
6798 (res
), GetLastError(), needed
, numentries
);
6804 /*****************************************************************************
6805 * EnumMonitorsW [WINSPOOL.@]
6807 * Enumerate available Port-Monitors
6810 * pName [I] Servername or NULL (local Computer)
6811 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6812 * pMonitors [O] PTR to Buffer that receives the Result
6813 * cbBuf [I] Size of Buffer at pMonitors
6814 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6815 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6819 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6822 * Windows reads the Registry once and cache the Results.
6824 *| Language-Monitors are also installed in the same Registry-Location but
6825 *| they are filtered in Windows (not returned by EnumMonitors).
6826 *| We do no filtering to simplify our Code.
6829 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6830 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6833 DWORD numentries
= 0;
6836 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6837 cbBuf
, pcbNeeded
, pcReturned
);
6839 if (pName
&& (lstrlenW(pName
))) {
6840 FIXME("for Server %s not implemented\n", debugstr_w(pName
));
6841 SetLastError(ERROR_ACCESS_DENIED
);
6845 /* Level is not checked in win9x */
6846 if (!Level
|| (Level
> 2)) {
6847 WARN("level (%d) is ignored in win9x\n", Level
);
6848 SetLastError(ERROR_INVALID_LEVEL
);
6852 SetLastError(RPC_X_NULL_REF_POINTER
);
6856 /* Scan all Monitor-Keys */
6858 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
6860 /* we calculated the needed buffersize. now do the error-checks */
6861 if (cbBuf
< needed
) {
6862 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6865 else if (!pMonitors
|| !pcReturned
) {
6866 SetLastError(RPC_X_NULL_REF_POINTER
);
6870 /* fill the Buffer with the Monitor-Keys */
6871 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
6875 if (pcbNeeded
) *pcbNeeded
= needed
;
6876 if (pcReturned
) *pcReturned
= numentries
;
6878 TRACE("returning %d with %d (%d byte for %d entries)\n",
6879 res
, GetLastError(), needed
, numentries
);
6884 /******************************************************************************
6885 * XcvDataW (WINSPOOL.@)
6887 * Execute commands in the Printmonitor DLL
6890 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6891 * pszDataName [i] Name of the command to execute
6892 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6893 * cbInputData [i] Size in Bytes of Buffer at pInputData
6894 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6895 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6896 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6897 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6904 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6905 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6907 * Minimal List of commands, that a Printmonitor DLL should support:
6909 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6910 *| "AddPort" : Add a Port
6911 *| "DeletePort": Delete a Port
6913 * Many Printmonitors support additional commands. Examples for localspl.dll:
6914 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6915 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6918 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6919 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6920 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6922 opened_printer_t
*printer
;
6924 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6925 pInputData
, cbInputData
, pOutputData
,
6926 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6928 printer
= get_opened_printer(hXcv
);
6929 if (!printer
|| (!printer
->hXcv
)) {
6930 SetLastError(ERROR_INVALID_HANDLE
);
6934 if (!pcbOutputNeeded
) {
6935 SetLastError(ERROR_INVALID_PARAMETER
);
6939 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6940 SetLastError(RPC_X_NULL_REF_POINTER
);
6944 *pcbOutputNeeded
= 0;
6946 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
6947 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
6952 /*****************************************************************************
6953 * EnumPrinterDataA [WINSPOOL.@]
6956 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6957 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6958 DWORD cbData
, LPDWORD pcbData
)
6960 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6961 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6962 return ERROR_NO_MORE_ITEMS
;
6965 /*****************************************************************************
6966 * EnumPrinterDataW [WINSPOOL.@]
6969 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
6970 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6971 DWORD cbData
, LPDWORD pcbData
)
6973 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6974 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6975 return ERROR_NO_MORE_ITEMS
;
6978 /*****************************************************************************
6979 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6982 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
6983 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6984 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6986 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
6987 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6988 pcbNeeded
, pcReturned
);
6992 /*****************************************************************************
6993 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6996 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
6997 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6998 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7000 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7001 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7002 pcbNeeded
, pcReturned
);
7006 /*****************************************************************************
7007 * EnumPrintProcessorsA [WINSPOOL.@]
7010 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7011 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7013 FIXME("Stub: %s %s %d %p %d %p %p\n", pName
, pEnvironment
, Level
,
7014 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
7018 /*****************************************************************************
7019 * EnumPrintProcessorsW [WINSPOOL.@]
7022 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7023 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7025 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7026 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
7027 cbBuf
, pcbNeeded
, pcbReturned
);
7031 /*****************************************************************************
7032 * ExtDeviceMode [WINSPOOL.@]
7035 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7036 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7039 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7040 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7041 debugstr_a(pProfile
), fMode
);
7045 /*****************************************************************************
7046 * FindClosePrinterChangeNotification [WINSPOOL.@]
7049 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7051 FIXME("Stub: %p\n", hChange
);
7055 /*****************************************************************************
7056 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7059 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7060 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7062 FIXME("Stub: %p %x %x %p\n",
7063 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7064 return INVALID_HANDLE_VALUE
;
7067 /*****************************************************************************
7068 * FindNextPrinterChangeNotification [WINSPOOL.@]
7071 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7072 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7074 FIXME("Stub: %p %p %p %p\n",
7075 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7079 /*****************************************************************************
7080 * FreePrinterNotifyInfo [WINSPOOL.@]
7083 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7085 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7089 /*****************************************************************************
7092 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7093 * ansi depending on the unicode parameter.
7095 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7105 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7108 memcpy(ptr
, str
, *size
);
7115 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7118 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7125 /*****************************************************************************
7128 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7129 LPDWORD pcbNeeded
, BOOL unicode
)
7131 DWORD size
, left
= cbBuf
;
7132 BOOL space
= (cbBuf
> 0);
7139 ji1
->JobId
= job
->job_id
;
7142 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7143 if(space
&& size
<= left
)
7145 ji1
->pDocument
= (LPWSTR
)ptr
;
7156 /*****************************************************************************
7159 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7160 LPDWORD pcbNeeded
, BOOL unicode
)
7162 DWORD size
, left
= cbBuf
;
7163 BOOL space
= (cbBuf
> 0);
7170 ji2
->JobId
= job
->job_id
;
7173 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7174 if(space
&& size
<= left
)
7176 ji2
->pDocument
= (LPWSTR
)ptr
;
7187 /*****************************************************************************
7190 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7191 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7194 DWORD needed
= 0, size
;
7198 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7200 EnterCriticalSection(&printer_handles_cs
);
7201 job
= get_job(hPrinter
, JobId
);
7208 size
= sizeof(JOB_INFO_1W
);
7213 memset(pJob
, 0, size
);
7217 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7222 size
= sizeof(JOB_INFO_2W
);
7227 memset(pJob
, 0, size
);
7231 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7236 size
= sizeof(JOB_INFO_3
);
7240 memset(pJob
, 0, size
);
7249 SetLastError(ERROR_INVALID_LEVEL
);
7253 *pcbNeeded
= needed
;
7255 LeaveCriticalSection(&printer_handles_cs
);
7259 /*****************************************************************************
7260 * GetJobA [WINSPOOL.@]
7263 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7264 DWORD cbBuf
, LPDWORD pcbNeeded
)
7266 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7269 /*****************************************************************************
7270 * GetJobW [WINSPOOL.@]
7273 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7274 DWORD cbBuf
, LPDWORD pcbNeeded
)
7276 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7279 /*****************************************************************************
7282 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7284 char *unixname
, *queue
, *cmd
;
7285 char fmt
[] = "lpr -P%s %s";
7288 if(!(unixname
= wine_get_unix_file_name(filename
)))
7291 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7292 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7293 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7295 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7296 sprintf(cmd
, fmt
, queue
, unixname
);
7298 TRACE("printing with: %s\n", cmd
);
7301 HeapFree(GetProcessHeap(), 0, cmd
);
7302 HeapFree(GetProcessHeap(), 0, queue
);
7303 HeapFree(GetProcessHeap(), 0, unixname
);
7307 /*****************************************************************************
7310 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7312 #ifdef SONAME_LIBCUPS
7315 char *unixname
, *queue
, *doc_titleA
;
7319 if(!(unixname
= wine_get_unix_file_name(filename
)))
7322 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7323 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7324 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7326 len
= WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7327 doc_titleA
= HeapAlloc(GetProcessHeap(), 0, len
);
7328 WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, doc_titleA
, len
, NULL
, NULL
);
7330 TRACE("printing via cups\n");
7331 ret
= pcupsPrintFile(queue
, unixname
, doc_titleA
, 0, NULL
);
7332 HeapFree(GetProcessHeap(), 0, doc_titleA
);
7333 HeapFree(GetProcessHeap(), 0, queue
);
7334 HeapFree(GetProcessHeap(), 0, unixname
);
7340 return schedule_lpr(printer_name
, filename
);
7344 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7351 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7355 if(HIWORD(wparam
) == BN_CLICKED
)
7357 if(LOWORD(wparam
) == IDOK
)
7360 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7363 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7364 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7366 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7368 WCHAR caption
[200], message
[200];
7371 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7372 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7373 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7374 if(mb_ret
== IDCANCEL
)
7376 HeapFree(GetProcessHeap(), 0, filename
);
7380 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7381 if(hf
== INVALID_HANDLE_VALUE
)
7383 WCHAR caption
[200], message
[200];
7385 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7386 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7387 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7388 HeapFree(GetProcessHeap(), 0, filename
);
7392 DeleteFileW(filename
);
7393 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7395 EndDialog(hwnd
, IDOK
);
7398 if(LOWORD(wparam
) == IDCANCEL
)
7400 EndDialog(hwnd
, IDCANCEL
);
7409 /*****************************************************************************
7412 static BOOL
get_filename(LPWSTR
*filename
)
7414 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7415 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7418 /*****************************************************************************
7421 static BOOL
schedule_file(LPCWSTR filename
)
7423 LPWSTR output
= NULL
;
7425 if(get_filename(&output
))
7427 TRACE("copy to %s\n", debugstr_w(output
));
7428 CopyFileW(filename
, output
, FALSE
);
7429 HeapFree(GetProcessHeap(), 0, output
);
7435 /*****************************************************************************
7438 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7441 char *unixname
, *cmdA
;
7443 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7447 if(!(unixname
= wine_get_unix_file_name(filename
)))
7450 len
= WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7451 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7452 WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7454 TRACE("printing with: %s\n", cmdA
);
7456 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7461 ERR("pipe() failed!\n");
7471 /* reset signals that we previously set to SIG_IGN */
7472 signal(SIGPIPE
, SIG_DFL
);
7473 signal(SIGCHLD
, SIG_DFL
);
7475 execl("/bin/sh", "/bin/sh", "-c", cmdA
, (char*)0);
7479 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7480 write(fds
[1], buf
, no_read
);
7485 if(file_fd
!= -1) close(file_fd
);
7486 if(fds
[0] != -1) close(fds
[0]);
7487 if(fds
[1] != -1) close(fds
[1]);
7489 HeapFree(GetProcessHeap(), 0, cmdA
);
7490 HeapFree(GetProcessHeap(), 0, unixname
);
7497 /*****************************************************************************
7500 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7502 int in_fd
, out_fd
, no_read
;
7505 char *unixname
, *outputA
;
7508 if(!(unixname
= wine_get_unix_file_name(filename
)))
7511 len
= WideCharToMultiByte(CP_ACP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7512 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7513 WideCharToMultiByte(CP_ACP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7515 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7516 in_fd
= open(unixname
, O_RDONLY
);
7517 if(out_fd
== -1 || in_fd
== -1)
7520 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7521 write(out_fd
, buf
, no_read
);
7525 if(in_fd
!= -1) close(in_fd
);
7526 if(out_fd
!= -1) close(out_fd
);
7527 HeapFree(GetProcessHeap(), 0, outputA
);
7528 HeapFree(GetProcessHeap(), 0, unixname
);
7532 /*****************************************************************************
7533 * ScheduleJob [WINSPOOL.@]
7536 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7538 opened_printer_t
*printer
;
7540 struct list
*cursor
, *cursor2
;
7542 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7543 EnterCriticalSection(&printer_handles_cs
);
7544 printer
= get_opened_printer(hPrinter
);
7548 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7550 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7553 if(job
->job_id
!= dwJobID
) continue;
7555 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7556 if(hf
!= INVALID_HANDLE_VALUE
)
7558 PRINTER_INFO_5W
*pi5
;
7562 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7563 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7565 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7566 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7567 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7568 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7569 debugstr_w(pi5
->pPortName
));
7573 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7574 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7576 DWORD type
, count
= sizeof(output
);
7577 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
7580 if(output
[0] == '|')
7582 schedule_pipe(output
+ 1, job
->filename
);
7586 schedule_unixfile(output
, job
->filename
);
7588 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
7590 schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
7592 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
7594 schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7596 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
7598 schedule_file(job
->filename
);
7602 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
7604 HeapFree(GetProcessHeap(), 0, pi5
);
7606 DeleteFileW(job
->filename
);
7608 list_remove(cursor
);
7609 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7610 HeapFree(GetProcessHeap(), 0, job
->filename
);
7611 HeapFree(GetProcessHeap(), 0, job
);
7616 LeaveCriticalSection(&printer_handles_cs
);
7620 /*****************************************************************************
7621 * StartDocDlgA [WINSPOOL.@]
7623 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7625 UNICODE_STRING usBuffer
;
7628 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7631 docW
.cbSize
= sizeof(docW
);
7632 if (doc
->lpszDocName
)
7634 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7635 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7637 if (doc
->lpszOutput
)
7639 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7640 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7642 if (doc
->lpszDatatype
)
7644 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7645 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7647 docW
.fwType
= doc
->fwType
;
7649 retW
= StartDocDlgW(hPrinter
, &docW
);
7653 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7654 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7655 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7656 HeapFree(GetProcessHeap(), 0, retW
);
7659 HeapFree(GetProcessHeap(), 0, datatypeW
);
7660 HeapFree(GetProcessHeap(), 0, outputW
);
7661 HeapFree(GetProcessHeap(), 0, docnameW
);
7666 /*****************************************************************************
7667 * StartDocDlgW [WINSPOOL.@]
7669 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7670 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7671 * port is "FILE:". Also returns the full path if passed a relative path.
7673 * The caller should free the returned string from the process heap.
7675 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7680 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7682 PRINTER_INFO_5W
*pi5
;
7683 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7684 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7686 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7687 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7688 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7690 HeapFree(GetProcessHeap(), 0, pi5
);
7693 HeapFree(GetProcessHeap(), 0, pi5
);
7696 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7700 if (get_filename(&name
))
7702 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7704 HeapFree(GetProcessHeap(), 0, name
);
7707 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7708 GetFullPathNameW(name
, len
, ret
, NULL
);
7709 HeapFree(GetProcessHeap(), 0, name
);
7714 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7717 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7718 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7720 attr
= GetFileAttributesW(ret
);
7721 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7723 HeapFree(GetProcessHeap(), 0, ret
);