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
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "wine/port.h"
34 #ifdef HAVE_CUPS_CUPS_H
35 # include <cups/cups.h>
36 # ifndef SONAME_LIBCUPS
37 # define SONAME_LIBCUPS "libcups.so"
41 #define NONAMELESSUNION
42 #define NONAMELESSSTRUCT
43 #include "wine/library.h"
52 #include "wine/windef16.h"
53 #include "wine/unicode.h"
54 #include "wine/debug.h"
55 #include "wine/list.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
61 static CRITICAL_SECTION printer_handles_cs
;
62 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
64 0, 0, &printer_handles_cs
,
65 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
66 0, 0, { 0, (DWORD
)(__FILE__
": printer_handles_cs") }
68 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
81 static opened_printer_t
**printer_handles
;
82 static int nb_printer_handles
;
83 static long next_job_id
= 1;
85 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
86 WORD fwCapability
, LPSTR lpszOutput
,
88 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
89 LPSTR lpszDevice
, LPSTR lpszPort
,
90 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
93 static const char Printers
[] =
94 "System\\CurrentControlSet\\control\\Print\\Printers\\";
96 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
97 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
98 'c','o','n','t','r','o','l','\\',
99 'P','r','i','n','t','\\',
100 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
101 '%','s','\\','D','r','i','v','e','r','s','\\',0 };
103 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
104 'M','i','c','r','o','s','o','f','t','\\',
105 'W','i','n','d','o','w','s',' ','N','T','\\',
106 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
107 'W','i','n','d','o','w','s',0};
109 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
110 'M','i','c','r','o','s','o','f','t','\\',
111 'W','i','n','d','o','w','s',' ','N','T','\\',
112 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
113 'D','e','v','i','c','e','s',0};
115 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
117 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
118 'i','o','n',' ','F','i','l','e',0};
119 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
120 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
121 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v',
123 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F',
125 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
126 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
127 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
128 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
129 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
130 static const WCHAR NameW
[] = {'N','a','m','e',0};
131 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
132 static const WCHAR PortW
[] = {'P','o','r','t',0};
133 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e',
135 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i',
137 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i',
138 'v','e','r','D','a','t','a',0};
139 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F',
141 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
142 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
143 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
144 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
145 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
146 static const WCHAR emptyStringW
[] = {0};
148 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
150 static HKEY
WINSPOOL_OpenDriverReg( LPVOID pEnvironment
, BOOL unicode
);
151 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPWSTR pEnvironment
,
152 DWORD Level
, LPBYTE pDriverInfo
,
153 DWORD cbBuf
, LPDWORD pcbNeeded
,
155 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
);
157 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
158 if passed a NULL string. This returns NULLs to the result.
160 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
164 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
165 return usBufferPtr
->Buffer
;
167 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
172 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
,BOOL force
) {
175 /* If forcing, or no profile string entry for device yet, set the entry
177 * The always change entry if not WINEPS yet is discussable.
180 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
182 !strstr(qbuf
,"WINEPS.DRV")
184 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
187 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
188 WriteProfileStringA("windows","device",buf
);
189 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
190 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, buf
, strlen(buf
) + 1);
193 HeapFree(GetProcessHeap(),0,buf
);
197 #ifdef HAVE_CUPS_CUPS_H
198 static BOOL
CUPS_LoadPrinters(void)
200 typeof(cupsGetDests
) *pcupsGetDests
= NULL
;
201 typeof(cupsGetPPD
) *pcupsGetPPD
= NULL
;
203 BOOL hadprinter
= FALSE
;
205 PRINTER_INFO_2A pinfo2a
;
206 void *cupshandle
= NULL
;
208 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
210 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, NULL
, 0);
213 TRACE("loaded %s\n", SONAME_LIBCUPS
);
216 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
217 if (!p##x) return FALSE;
220 DYNCUPS(cupsGetDests
);
223 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
225 ERR("Can't create Printers key\n");
229 nrofdests
= pcupsGetDests(&dests
);
230 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
231 for (i
=0;i
<nrofdests
;i
++) {
232 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests
[i
].name
)+1);
233 sprintf(port
,"LPR:%s",dests
[i
].name
);
234 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
235 sprintf(devline
,"WINEPS.DRV,%s",port
);
236 WriteProfileStringA("devices",dests
[i
].name
,devline
);
237 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
238 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, devline
, strlen(devline
) + 1);
241 HeapFree(GetProcessHeap(),0,devline
);
243 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
244 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
245 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
247 TRACE("Printer already exists\n");
248 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
249 RegCloseKey(hkeyPrinter
);
251 memset(&pinfo2a
,0,sizeof(pinfo2a
));
252 pinfo2a
.pPrinterName
= dests
[i
].name
;
253 pinfo2a
.pDatatype
= "RAW";
254 pinfo2a
.pPrintProcessor
= "WinPrint";
255 pinfo2a
.pDriverName
= "PS Driver";
256 pinfo2a
.pComment
= "WINEPS Printer using CUPS";
257 pinfo2a
.pLocation
= "<physical location of printer>";
258 pinfo2a
.pPortName
= port
;
259 pinfo2a
.pParameters
= "<parameters?>";
260 pinfo2a
.pShareName
= "<share name?>";
261 pinfo2a
.pSepFile
= "<sep file?>";
263 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
264 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
265 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests
[i
].name
,GetLastError());
268 HeapFree(GetProcessHeap(),0,port
);
271 if (dests
[i
].is_default
)
272 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
274 RegCloseKey(hkeyPrinters
);
275 wine_dlclose(cupshandle
, NULL
, 0);
281 PRINTCAP_ParseEntry(char *pent
,BOOL isfirst
) {
282 PRINTER_INFO_2A pinfo2a
;
283 char *e
,*s
,*name
,*prettyname
,*devname
;
284 BOOL ret
= FALSE
, set_default
= FALSE
;
285 char *port
,*devline
,*env_default
;
286 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
288 while (isspace(*pent
)) pent
++;
289 s
= strchr(pent
,':');
291 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
299 TRACE("name=%s entry=%s\n",name
, pent
);
301 if(ispunct(*name
)) { /* a tc entry, not a real printer */
302 TRACE("skipping tc entry\n");
306 if(strstr(pent
,":server")) { /* server only version so skip */
307 TRACE("skipping server entry\n");
311 /* Determine whether this is a postscript printer. */
314 env_default
= getenv("PRINTER");
316 /* Get longest name, usually the one at the right for later display. */
317 while((s
=strchr(prettyname
,'|'))) {
320 while(isspace(*--e
)) *e
= '\0';
321 TRACE("\t%s\n", debugstr_a(prettyname
));
322 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
323 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
326 e
= prettyname
+ strlen(prettyname
);
327 while(isspace(*--e
)) *e
= '\0';
328 TRACE("\t%s\n", debugstr_a(prettyname
));
329 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
331 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
332 * if it is too long, we use it as comment below. */
333 devname
= prettyname
;
334 if (strlen(devname
)>=CCHDEVICENAME
-1)
336 if (strlen(devname
)>=CCHDEVICENAME
-1) {
341 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
342 sprintf(port
,"LPR:%s",name
);
344 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
345 sprintf(devline
,"WINEPS.DRV,%s",port
);
346 WriteProfileStringA("devices",devname
,devline
);
347 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
348 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, devline
, strlen(devline
) + 1);
351 HeapFree(GetProcessHeap(),0,devline
);
353 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
355 ERR("Can't create Printers key\n");
359 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
360 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
362 TRACE("Printer already exists\n");
363 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
364 RegCloseKey(hkeyPrinter
);
366 memset(&pinfo2a
,0,sizeof(pinfo2a
));
367 pinfo2a
.pPrinterName
= devname
;
368 pinfo2a
.pDatatype
= "RAW";
369 pinfo2a
.pPrintProcessor
= "WinPrint";
370 pinfo2a
.pDriverName
= "PS Driver";
371 pinfo2a
.pComment
= "WINEPS Printer using LPR";
372 pinfo2a
.pLocation
= prettyname
;
373 pinfo2a
.pPortName
= port
;
374 pinfo2a
.pParameters
= "<parameters?>";
375 pinfo2a
.pShareName
= "<share name?>";
376 pinfo2a
.pSepFile
= "<sep file?>";
378 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
379 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
380 ERR("%s not added by AddPrinterA (%ld)\n",name
,GetLastError());
383 RegCloseKey(hkeyPrinters
);
385 if (isfirst
|| set_default
)
386 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
388 HeapFree(GetProcessHeap(), 0, port
);
390 HeapFree(GetProcessHeap(), 0, name
);
395 PRINTCAP_LoadPrinters(void) {
396 BOOL hadprinter
= FALSE
;
400 BOOL had_bash
= FALSE
;
402 f
= fopen("/etc/printcap","r");
406 while(fgets(buf
,sizeof(buf
),f
)) {
409 end
=strchr(buf
,'\n');
413 while(isspace(*start
)) start
++;
414 if(*start
== '#' || *start
== '\0')
417 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
418 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
419 HeapFree(GetProcessHeap(),0,pent
);
423 if (end
&& *--end
== '\\') {
430 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
433 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
439 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
440 HeapFree(GetProcessHeap(),0,pent
);
446 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
449 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
450 lstrlenW(value
) * sizeof(WCHAR
));
452 return ERROR_FILE_NOT_FOUND
;
455 void WINSPOOL_LoadSystemPrinters(void)
457 HKEY hkey
, hkeyPrinters
;
460 DWORD needed
, num
, i
;
461 WCHAR PrinterName
[256];
464 di3a
.cVersion
= 0x400;
465 di3a
.pName
= "PS Driver";
466 di3a
.pEnvironment
= NULL
; /* NULL means auto */
467 di3a
.pDriverPath
= "wineps16";
468 di3a
.pDataFile
= "<datafile?>";
469 di3a
.pConfigFile
= "wineps16";
470 di3a
.pHelpFile
= "<helpfile?>";
471 di3a
.pDependentFiles
= "<dependend files?>";
472 di3a
.pMonitorName
= "<monitor name?>";
473 di3a
.pDefaultDataType
= "RAW";
475 if (!AddPrinterDriverA(NULL
,3,(LPBYTE
)&di3a
)) {
476 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
480 /* This ensures that all printer entries have a valid Name value. If causes
481 problems later if they don't. If one is found to be missed we create one
482 and set it equal to the name of the key */
483 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) == ERROR_SUCCESS
) {
484 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
485 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
486 for(i
= 0; i
< num
; i
++) {
487 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) == ERROR_SUCCESS
) {
488 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
489 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
490 set_reg_szW(hkey
, NameW
, PrinterName
);
497 RegCloseKey(hkeyPrinters
);
500 /* We want to avoid calling AddPrinter on printers as much as
501 possible, because on cups printers this will (eventually) lead
502 to a call to cupsGetPPD which takes forever, even with non-cups
503 printers AddPrinter takes a while. So we'll tag all printers that
504 were automatically added last time around, if they still exist
505 we'll leave them be otherwise we'll delete them. */
506 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
508 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
509 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
510 for(i
= 0; i
< num
; i
++) {
511 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
512 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
513 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
515 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
523 HeapFree(GetProcessHeap(), 0, pi
);
527 #ifdef HAVE_CUPS_CUPS_H
528 done
= CUPS_LoadPrinters();
531 if(!done
) { /* If we have any CUPS based printers, skip looking for printcap printers */
532 /* Check for [ppd] section in config file before parsing /etc/printcap */
533 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
534 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Printing\\PPD Files",
535 &hkey
) == ERROR_SUCCESS
) {
537 PRINTCAP_LoadPrinters();
541 /* Now enumerate the list again and delete any printers that a still tagged */
542 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
544 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
545 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
546 for(i
= 0; i
< num
; i
++) {
547 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
548 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
549 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
550 DWORD dw
, type
, size
= sizeof(dw
);
551 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
552 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
562 HeapFree(GetProcessHeap(), 0, pi
);
570 /******************************************************************
571 * get_opened_printer_entry
572 * Get the first place empty in the opened printer table
574 static HANDLE
get_opened_printer_entry( LPCWSTR name
)
577 opened_printer_t
*printer
;
579 EnterCriticalSection(&printer_handles_cs
);
581 for (handle
= 0; handle
< nb_printer_handles
; handle
++)
582 if (!printer_handles
[handle
])
585 if (handle
>= nb_printer_handles
)
587 opened_printer_t
**new_array
;
589 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
590 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
592 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
593 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
600 printer_handles
= new_array
;
601 nb_printer_handles
+= 16;
604 if (!(printer
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
))))
610 printer
->name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(name
) + 1) * sizeof(WCHAR
));
611 strcpyW(printer
->name
, name
);
612 list_init(&printer
->jobs
);
614 printer_handles
[handle
] = printer
;
617 LeaveCriticalSection(&printer_handles_cs
);
619 return (HANDLE
)handle
;
622 /******************************************************************
624 * Get the pointer to the opened printer referred by the handle
626 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
629 opened_printer_t
*ret
= NULL
;
631 EnterCriticalSection(&printer_handles_cs
);
633 if ((idx
<= 0) || (idx
> nb_printer_handles
))
636 ret
= printer_handles
[idx
- 1];
638 LeaveCriticalSection(&printer_handles_cs
);
642 /******************************************************************
643 * get_opened_printer_name
644 * Get the pointer to the opened printer name referred by the handle
646 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
648 opened_printer_t
*printer
= get_opened_printer(hprn
);
649 if(!printer
) return NULL
;
650 return printer
->name
;
653 /******************************************************************
654 * WINSPOOL_GetOpenedPrinterRegKey
657 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
659 LPCWSTR name
= get_opened_printer_name(hPrinter
);
663 if(!name
) return ERROR_INVALID_HANDLE
;
665 if((ret
= RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
)) !=
669 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
671 ERR("Can't find opened printer %s in registry\n",
673 RegCloseKey(hkeyPrinters
);
674 return ERROR_INVALID_PRINTER_NAME
; /* ? */
676 RegCloseKey(hkeyPrinters
);
677 return ERROR_SUCCESS
;
680 /***********************************************************
683 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
686 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
689 Formname
= (dmA
->dmSize
> off_formname
);
690 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
691 MultiByteToWideChar(CP_ACP
, 0, dmA
->dmDeviceName
, -1, dmW
->dmDeviceName
,
694 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
695 dmA
->dmSize
- CCHDEVICENAME
);
697 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
698 off_formname
- CCHDEVICENAME
);
699 MultiByteToWideChar(CP_ACP
, 0, dmA
->dmFormName
, -1, dmW
->dmFormName
,
701 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
702 (off_formname
+ CCHFORMNAME
));
705 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
710 /***********************************************************
712 * Creates an ascii copy of supplied devmode on heap
714 static LPDEVMODEA
DEVMODEdupWtoA(HANDLE heap
, const DEVMODEW
*dmW
)
719 ptrdiff_t off_formname
= (const char *)dmW
->dmFormName
- (const char *)dmW
;
721 if(!dmW
) return NULL
;
722 Formname
= (dmW
->dmSize
> off_formname
);
723 size
= dmW
->dmSize
- CCHDEVICENAME
- (Formname
? CCHFORMNAME
: 0);
724 dmA
= HeapAlloc(heap
, HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
725 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1, dmA
->dmDeviceName
,
726 CCHDEVICENAME
, NULL
, NULL
);
728 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
729 dmW
->dmSize
- CCHDEVICENAME
* sizeof(WCHAR
));
731 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
732 off_formname
- CCHDEVICENAME
* sizeof(WCHAR
));
733 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1, dmA
->dmFormName
,
734 CCHFORMNAME
, NULL
, NULL
);
735 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
-
736 (off_formname
+ CCHFORMNAME
* sizeof(WCHAR
)));
739 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
,
744 /***********************************************************
746 * Creates a unicode copy of PRINTER_INFO_2A on heap
748 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
750 LPPRINTER_INFO_2W piW
;
751 UNICODE_STRING usBuffer
;
753 if(!piA
) return NULL
;
754 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
755 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
757 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
758 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
759 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
760 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
761 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
762 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
763 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
764 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
765 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
766 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
767 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
768 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
772 /***********************************************************
773 * FREE_PRINTER_INFO_2W
774 * Free PRINTER_INFO_2W and all strings
776 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
780 HeapFree(heap
,0,piW
->pServerName
);
781 HeapFree(heap
,0,piW
->pPrinterName
);
782 HeapFree(heap
,0,piW
->pShareName
);
783 HeapFree(heap
,0,piW
->pPortName
);
784 HeapFree(heap
,0,piW
->pDriverName
);
785 HeapFree(heap
,0,piW
->pComment
);
786 HeapFree(heap
,0,piW
->pLocation
);
787 HeapFree(heap
,0,piW
->pDevMode
);
788 HeapFree(heap
,0,piW
->pSepFile
);
789 HeapFree(heap
,0,piW
->pPrintProcessor
);
790 HeapFree(heap
,0,piW
->pDatatype
);
791 HeapFree(heap
,0,piW
->pParameters
);
792 HeapFree(heap
,0,piW
);
796 /******************************************************************
797 * DeviceCapabilities [WINSPOOL.@]
798 * DeviceCapabilitiesA [WINSPOOL.@]
801 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
802 LPSTR pOutput
, LPDEVMODEA lpdm
)
806 if (!GDI_CallDeviceCapabilities16
)
808 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
810 if (!GDI_CallDeviceCapabilities16
) return -1;
812 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
814 /* If DC_PAPERSIZE map POINT16s to POINTs */
815 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
816 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
817 POINT
*pt
= (POINT
*)pOutput
;
819 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
820 for(i
= 0; i
< ret
; i
++, pt
++)
825 HeapFree( GetProcessHeap(), 0, tmp
);
831 /*****************************************************************************
832 * DeviceCapabilitiesW [WINSPOOL.@]
834 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
837 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
838 WORD fwCapability
, LPWSTR pOutput
,
839 const DEVMODEW
*pDevMode
)
841 LPDEVMODEA dmA
= DEVMODEdupWtoA(GetProcessHeap(), pDevMode
);
842 LPSTR pDeviceA
= HEAP_strdupWtoA(GetProcessHeap(),0,pDevice
);
843 LPSTR pPortA
= HEAP_strdupWtoA(GetProcessHeap(),0,pPort
);
846 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
847 fwCapability
== DC_FILEDEPENDENCIES
||
848 fwCapability
== DC_PAPERNAMES
)) {
849 /* These need A -> W translation */
852 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
856 switch(fwCapability
) {
861 case DC_FILEDEPENDENCIES
:
865 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
866 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
868 for(i
= 0; i
< ret
; i
++)
869 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
870 pOutput
+ (i
* size
), size
);
871 HeapFree(GetProcessHeap(), 0, pOutputA
);
873 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
874 (LPSTR
)pOutput
, dmA
);
876 HeapFree(GetProcessHeap(),0,pPortA
);
877 HeapFree(GetProcessHeap(),0,pDeviceA
);
878 HeapFree(GetProcessHeap(),0,dmA
);
882 /******************************************************************
883 * DocumentPropertiesA [WINSPOOL.@]
885 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
887 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
888 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
889 LPDEVMODEA pDevModeInput
,DWORD fMode
)
891 LPSTR lpName
= pDeviceName
;
894 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
895 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
899 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
901 ERR("no name from hPrinter?\n");
902 SetLastError(ERROR_INVALID_HANDLE
);
905 lpName
= HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW
);
908 if (!GDI_CallExtDeviceMode16
)
910 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
912 if (!GDI_CallExtDeviceMode16
) {
913 ERR("No CallExtDeviceMode16?\n");
917 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, "LPT1:",
918 pDevModeInput
, NULL
, fMode
);
921 HeapFree(GetProcessHeap(),0,lpName
);
926 /*****************************************************************************
927 * DocumentPropertiesW (WINSPOOL.@)
929 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
931 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
933 LPDEVMODEW pDevModeOutput
,
934 LPDEVMODEW pDevModeInput
, DWORD fMode
)
937 LPSTR pDeviceNameA
= HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName
);
938 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput
);
939 LPDEVMODEA pDevModeOutputA
= NULL
;
942 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
943 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
946 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
947 if(ret
< 0) return ret
;
948 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
950 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
951 pDevModeInputA
, fMode
);
953 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
954 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
956 if(fMode
== 0 && ret
> 0)
957 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
958 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
959 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
963 /******************************************************************
964 * OpenPrinterA [WINSPOOL.@]
967 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
968 LPPRINTER_DEFAULTSA pDefault
)
970 UNICODE_STRING lpPrinterNameW
;
971 UNICODE_STRING usBuffer
;
972 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
973 PWSTR pwstrPrinterNameW
;
976 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
979 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
980 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
981 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
982 pDefaultW
= &DefaultW
;
984 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
986 RtlFreeUnicodeString(&usBuffer
);
987 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
989 RtlFreeUnicodeString(&lpPrinterNameW
);
993 /******************************************************************
994 * OpenPrinterW [WINSPOOL.@]
997 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
,
998 LPPRINTER_DEFAULTSW pDefault
)
1000 HKEY hkeyPrinters
, hkeyPrinter
;
1002 if (!lpPrinterName
) {
1003 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault
);
1004 SetLastError(ERROR_INVALID_PARAMETER
);
1008 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName
),
1011 /* Check Printer exists */
1012 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
1014 ERR("Can't create Printers key\n");
1015 SetLastError(ERROR_FILE_NOT_FOUND
); /* ?? */
1019 if(lpPrinterName
[0] == '\0' || /* explicitly exclude "" */
1020 RegOpenKeyW(hkeyPrinters
, lpPrinterName
, &hkeyPrinter
)
1022 TRACE("Can't find printer %s in registry\n",
1023 debugstr_w(lpPrinterName
));
1024 RegCloseKey(hkeyPrinters
);
1025 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1028 RegCloseKey(hkeyPrinter
);
1029 RegCloseKey(hkeyPrinters
);
1031 if(!phPrinter
) /* This seems to be what win95 does anyway */
1034 /* Get the unique handle of the printer*/
1035 *phPrinter
= get_opened_printer_entry( lpPrinterName
);
1037 if (pDefault
!= NULL
)
1038 FIXME("Not handling pDefault\n");
1043 /******************************************************************
1044 * AddMonitorA [WINSPOOL.@]
1047 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1049 FIXME("(%s,0x%08lx,%p), stub!\n", debugstr_a(pName
), Level
, pMonitors
);
1050 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1054 /******************************************************************************
1055 * AddMonitorW [WINSPOOL.@]
1057 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1059 FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName
), Level
, pMonitors
);
1060 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1064 /******************************************************************
1065 * DeletePrinterDriverA [WINSPOOL.@]
1069 DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
1071 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName
),debugstr_a(pEnvironment
),
1072 debugstr_a(pDriverName
));
1073 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1077 /******************************************************************
1078 * DeletePrinterDriverW [WINSPOOL.@]
1082 DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
1084 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1085 debugstr_w(pDriverName
));
1086 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1090 /******************************************************************
1091 * DeleteMonitorA [WINSPOOL.@]
1095 DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
1097 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName
),debugstr_a(pEnvironment
),
1098 debugstr_a(pMonitorName
));
1099 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1103 /******************************************************************
1104 * DeleteMonitorW [WINSPOOL.@]
1108 DeleteMonitorW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1110 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1111 debugstr_w(pMonitorName
));
1112 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1116 /******************************************************************
1117 * DeletePortA [WINSPOOL.@]
1121 DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
1123 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName
),hWnd
,
1124 debugstr_a(pPortName
));
1125 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1129 /******************************************************************
1130 * DeletePortW [WINSPOOL.@]
1134 DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1136 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName
),hWnd
,
1137 debugstr_w(pPortName
));
1138 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1142 /******************************************************************************
1143 * SetPrinterW [WINSPOOL.@]
1153 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1157 /******************************************************************************
1158 * WritePrinter [WINSPOOL.@]
1165 LPDWORD pcWritten
) {
1168 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1172 /*****************************************************************************
1173 * AddFormA [WINSPOOL.@]
1175 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
1177 FIXME("(%p,%ld,%p): stub\n", hPrinter
, Level
, pForm
);
1181 /*****************************************************************************
1182 * AddFormW [WINSPOOL.@]
1184 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
1186 FIXME("(%p,%ld,%p): stub\n", hPrinter
, Level
, pForm
);
1190 /*****************************************************************************
1191 * AddJobA [WINSPOOL.@]
1193 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1196 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
1200 SetLastError(ERROR_INVALID_LEVEL
);
1204 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
1207 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
1208 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
1209 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
1210 if(*pcbNeeded
> cbBuf
) {
1211 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1214 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
1215 addjobA
->JobId
= addjobW
->JobId
;
1216 addjobA
->Path
= (char *)(addjobA
+ 1);
1217 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
1223 /*****************************************************************************
1224 * AddJobW [WINSPOOL.@]
1226 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1228 opened_printer_t
*printer
;
1231 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1232 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
1233 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
1235 ADDJOB_INFO_1W
*addjob
;
1237 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
1239 EnterCriticalSection(&printer_handles_cs
);
1241 printer
= get_opened_printer(hPrinter
);
1244 SetLastError(ERROR_INVALID_HANDLE
);
1249 SetLastError(ERROR_INVALID_LEVEL
);
1253 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
1257 job
->job_id
= InterlockedIncrement(&next_job_id
);
1259 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
1260 if(path
[len
- 1] != '\\')
1262 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
1263 sprintfW(filename
, fmtW
, path
, job
->job_id
);
1265 len
= strlenW(filename
);
1266 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
1267 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
1268 list_add_tail(&printer
->jobs
, &job
->entry
);
1270 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
1271 if(*pcbNeeded
<= cbBuf
) {
1272 addjob
= (ADDJOB_INFO_1W
*)pData
;
1273 addjob
->JobId
= job
->job_id
;
1274 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
1275 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
1278 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1281 LeaveCriticalSection(&printer_handles_cs
);
1285 /*****************************************************************************
1286 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1288 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
1289 DWORD level
, LPBYTE Info
,
1290 DWORD cbBuf
, LPDWORD needed
)
1292 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server
), debugstr_a(env
),
1293 level
, Info
, cbBuf
);
1297 /*****************************************************************************
1298 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1300 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
1301 DWORD level
, LPBYTE Info
,
1302 DWORD cbBuf
, LPDWORD needed
)
1304 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server
), debugstr_w(env
),
1305 level
, Info
, cbBuf
);
1309 /*****************************************************************************
1310 * WINSPOOL_OpenDriverReg [internal]
1312 * opens the registry for the printer drivers depending on the given input
1313 * variable pEnvironment
1316 * the opened hkey on success
1319 static HKEY
WINSPOOL_OpenDriverReg( LPVOID pEnvironment
, BOOL unicode
)
1321 static const WCHAR WinNTW
[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1322 static const WCHAR Win40W
[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1324 LPWSTR lpKey
, buffer
= NULL
;
1328 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
));
1332 pEnvW
= pEnvironment
;
1334 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
1335 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1336 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
1341 ver
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOW
);
1343 if(!GetVersionExW( &ver
))
1346 switch (ver
.dwPlatformId
) {
1347 case VER_PLATFORM_WIN32s
:
1348 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1350 case VER_PLATFORM_WIN32_NT
:
1357 TRACE("set environment to %s\n", debugstr_w(pEnvW
));
1360 lpKey
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1361 (strlenW(pEnvW
) + strlenW(DriversW
) + 1) * sizeof(WCHAR
));
1362 wsprintfW( lpKey
, DriversW
, pEnvW
);
1364 TRACE("%s\n", debugstr_w(lpKey
));
1366 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, lpKey
, &retval
) != ERROR_SUCCESS
)
1369 HeapFree( GetProcessHeap(), 0, buffer
);
1370 HeapFree( GetProcessHeap(), 0, lpKey
);
1375 /*****************************************************************************
1376 * AddPrinterW [WINSPOOL.@]
1378 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
1380 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
1384 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
1387 TRACE("(%s,%ld,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
1390 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
1391 SetLastError(ERROR_INVALID_PARAMETER
);
1395 ERR("Level = %ld, unsupported!\n", Level
);
1396 SetLastError(ERROR_INVALID_LEVEL
);
1399 if (strlenW(pi
->pPrinterName
) >= CCHDEVICENAME
) {
1400 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1401 debugstr_w(pi
->pPrinterName
)
1403 SetLastError(ERROR_INVALID_LEVEL
);
1407 SetLastError(ERROR_INVALID_PARAMETER
);
1410 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
1412 ERR("Can't create Printers key\n");
1415 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
1416 if (!RegQueryValueA(hkeyPrinter
,"Attributes",NULL
,NULL
)) {
1417 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
1418 RegCloseKey(hkeyPrinter
);
1419 RegCloseKey(hkeyPrinters
);
1422 RegCloseKey(hkeyPrinter
);
1424 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
1426 ERR("Can't create Drivers key\n");
1427 RegCloseKey(hkeyPrinters
);
1430 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
1432 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
1433 RegCloseKey(hkeyPrinters
);
1434 RegCloseKey(hkeyDrivers
);
1435 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
1438 RegCloseKey(hkeyDriver
);
1439 RegCloseKey(hkeyDrivers
);
1441 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
1442 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
1443 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
1444 RegCloseKey(hkeyPrinters
);
1448 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
1450 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
1451 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1452 RegCloseKey(hkeyPrinters
);
1455 RegSetValueExA(hkeyPrinter
, "Attributes", 0, REG_DWORD
,
1456 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
1457 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
1459 /* See if we can load the driver. We may need the devmode structure anyway
1462 * Note that DocumentPropertiesW will briefly try to open the printer we
1463 * just create to find a DEVMODEA struct (it will use the WINEPS default
1464 * one in case it is not there, so we are ok).
1466 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
1469 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi
->pPrinterName
));
1470 size
= sizeof(DEVMODEW
);
1476 dmW
= HeapAlloc(GetProcessHeap(), 0, size
);
1477 ZeroMemory(dmW
,size
);
1479 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
1481 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi
->pPrinterName
));
1482 HeapFree(GetProcessHeap(),0,dmW
);
1487 /* set devmode to printer name */
1488 strcpyW(dmW
->dmDeviceName
,pi
->pPrinterName
);
1492 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1493 and we support these drivers. NT writes DEVMODEW so somehow
1494 we'll need to distinguish between these when we support NT
1498 dmA
= DEVMODEdupWtoA(GetProcessHeap(), dmW
);
1499 RegSetValueExA(hkeyPrinter
, "Default DevMode", 0, REG_BINARY
,
1500 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
1501 HeapFree(GetProcessHeap(), 0, dmA
);
1503 HeapFree(GetProcessHeap(), 0, dmW
);
1505 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
1506 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
1507 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
1508 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
1510 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
1511 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
1512 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
1513 RegSetValueExA(hkeyPrinter
, "Priority", 0, REG_DWORD
,
1514 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
1515 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
1516 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
1517 RegSetValueExA(hkeyPrinter
, "StartTime", 0, REG_DWORD
,
1518 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
1519 RegSetValueExA(hkeyPrinter
, "Status", 0, REG_DWORD
,
1520 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
1521 RegSetValueExA(hkeyPrinter
, "UntilTime", 0, REG_DWORD
,
1522 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
1524 RegCloseKey(hkeyPrinter
);
1525 RegCloseKey(hkeyPrinters
);
1526 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
1527 ERR("OpenPrinter failing\n");
1533 /*****************************************************************************
1534 * AddPrinterA [WINSPOOL.@]
1536 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
1538 UNICODE_STRING pNameW
;
1540 PRINTER_INFO_2W
*piW
;
1541 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
1544 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
1546 ERR("Level = %ld, unsupported!\n", Level
);
1547 SetLastError(ERROR_INVALID_LEVEL
);
1550 pwstrNameW
= asciitounicode(&pNameW
,pName
);
1551 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
1553 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
1555 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
1556 RtlFreeUnicodeString(&pNameW
);
1561 /*****************************************************************************
1562 * ClosePrinter [WINSPOOL.@]
1564 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
1566 int i
= (int)hPrinter
;
1567 opened_printer_t
*printer
= NULL
;
1570 TRACE("Handle %p\n", hPrinter
);
1572 EnterCriticalSection(&printer_handles_cs
);
1574 if ((i
> 0) && (i
<= nb_printer_handles
))
1575 printer
= printer_handles
[i
- 1];
1579 struct list
*cursor
, *cursor2
;
1580 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->jobs
)
1582 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
1583 ScheduleJob(hPrinter
, job
->job_id
);
1585 HeapFree(GetProcessHeap(), 0, printer
->name
);
1586 HeapFree(GetProcessHeap(), 0, printer
);
1587 printer_handles
[i
- 1] = NULL
;
1590 LeaveCriticalSection(&printer_handles_cs
);
1594 /*****************************************************************************
1595 * DeleteFormA [WINSPOOL.@]
1597 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
1599 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
1603 /*****************************************************************************
1604 * DeleteFormW [WINSPOOL.@]
1606 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
1608 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
1612 /*****************************************************************************
1613 * WINSPOOL_SHRegDeleteKey
1615 * Recursively delete subkeys.
1616 * Cut & paste from shlwapi.
1619 static DWORD
WINSPOOL_SHDeleteKeyW(HKEY hKey
, LPCWSTR lpszSubKey
)
1621 DWORD dwRet
, dwKeyCount
= 0, dwMaxSubkeyLen
= 0, dwSize
, i
;
1622 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1625 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1628 /* Find how many subkeys there are */
1629 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, &dwKeyCount
,
1630 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1634 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1635 /* Name too big: alloc a buffer for it */
1636 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
1639 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
1642 /* Recursively delete all the subkeys */
1643 for(i
= 0; i
< dwKeyCount
&& !dwRet
; i
++)
1645 dwSize
= dwMaxSubkeyLen
;
1646 dwRet
= RegEnumKeyExW(hSubKey
, i
, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
1648 dwRet
= WINSPOOL_SHDeleteKeyW(hSubKey
, lpszName
);
1651 if (lpszName
!= szNameBuf
)
1652 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
1656 RegCloseKey(hSubKey
);
1658 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
1663 /*****************************************************************************
1664 * DeletePrinter [WINSPOOL.@]
1666 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
1668 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1669 HKEY hkeyPrinters
, hkey
;
1672 SetLastError(ERROR_INVALID_HANDLE
);
1675 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1676 WINSPOOL_SHDeleteKeyW(hkeyPrinters
, lpNameW
);
1677 RegCloseKey(hkeyPrinters
);
1679 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
1680 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1681 RegDeleteValueW(hkey
, lpNameW
);
1687 /*****************************************************************************
1688 * SetPrinterA [WINSPOOL.@]
1690 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
1693 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter
,Level
,pPrinter
,Command
);
1697 /*****************************************************************************
1698 * SetJobA [WINSPOOL.@]
1700 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
1701 LPBYTE pJob
, DWORD Command
)
1703 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter
,JobId
,Level
,pJob
,
1708 /*****************************************************************************
1709 * SetJobW [WINSPOOL.@]
1711 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
1712 LPBYTE pJob
, DWORD Command
)
1714 FIXME("(%p,%ld,%ld,%p,%ld): stub\n",hPrinter
,JobId
,Level
,pJob
,
1719 /*****************************************************************************
1720 * EndDocPrinter [WINSPOOL.@]
1722 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
1724 FIXME("(hPrinter=%p): stub\n", hPrinter
);
1728 /*****************************************************************************
1729 * EndPagePrinter [WINSPOOL.@]
1731 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
1733 FIXME("(hPrinter=%p): stub\n", hPrinter
);
1737 /*****************************************************************************
1738 * StartDocPrinterA [WINSPOOL.@]
1740 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
1742 UNICODE_STRING usBuffer
;
1744 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
1747 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
1748 or one (DOC_INFO_3) extra DWORDs */
1752 doc2W
.JobId
= doc2
->JobId
;
1755 doc2W
.dwMode
= doc2
->dwMode
;
1758 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
1759 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
1760 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
1764 SetLastError(ERROR_INVALID_LEVEL
);
1768 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
1770 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
1771 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
1772 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
1777 /*****************************************************************************
1778 * StartDocPrinterW [WINSPOOL.@]
1780 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
1782 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
1784 FIXME("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}): stub\n",
1785 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
1786 debugstr_w(doc
->pDatatype
));
1790 /*****************************************************************************
1791 * StartPagePrinter [WINSPOOL.@]
1793 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
1795 FIXME("(hPrinter=%p): stub\n", hPrinter
);
1799 /*****************************************************************************
1800 * GetFormA [WINSPOOL.@]
1802 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
1803 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1805 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter
,pFormName
,
1806 Level
,pForm
,cbBuf
,pcbNeeded
);
1810 /*****************************************************************************
1811 * GetFormW [WINSPOOL.@]
1813 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
1814 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1816 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter
,
1817 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
1821 /*****************************************************************************
1822 * SetFormA [WINSPOOL.@]
1824 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
1827 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
1831 /*****************************************************************************
1832 * SetFormW [WINSPOOL.@]
1834 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
1837 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
1841 /*****************************************************************************
1842 * ReadPrinter [WINSPOOL.@]
1844 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
1845 LPDWORD pNoBytesRead
)
1847 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
1851 /*****************************************************************************
1852 * ResetPrinterA [WINSPOOL.@]
1854 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
1856 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
1860 /*****************************************************************************
1861 * ResetPrinterW [WINSPOOL.@]
1863 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1865 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
1869 /*****************************************************************************
1870 * WINSPOOL_GetDWORDFromReg
1872 * Return DWORD associated with ValueName from hkey.
1874 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
1876 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
1879 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
1881 if(ret
!= ERROR_SUCCESS
) {
1882 WARN("Got ret = %ld on name %s\n", ret
, ValueName
);
1885 if(type
!= REG_DWORD
) {
1886 ERR("Got type %ld\n", type
);
1892 /*****************************************************************************
1893 * WINSPOOL_GetStringFromReg
1895 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
1896 * String is stored either as unicode or ascii.
1897 * Bit of a hack here to get the ValueName if we want ascii.
1899 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
1900 DWORD buflen
, DWORD
*needed
,
1903 DWORD sz
= buflen
, type
;
1907 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
1909 LPSTR ValueNameA
= HEAP_strdupWtoA(GetProcessHeap(),0,ValueName
);
1910 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
1911 HeapFree(GetProcessHeap(),0,ValueNameA
);
1913 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
1914 WARN("Got ret = %ld\n", ret
);
1922 /*****************************************************************************
1923 * WINSPOOL_GetDefaultDevMode
1925 * Get a default DevMode values for wineps.
1929 static void WINSPOOL_GetDefaultDevMode(
1931 DWORD buflen
, DWORD
*needed
,
1936 /* fill default DEVMODE - should be read from ppd... */
1937 ZeroMemory( &dm
, sizeof(dm
) );
1938 strcpy(dm
.dmDeviceName
,"wineps.drv");
1939 dm
.dmSpecVersion
= DM_SPECVERSION
;
1940 dm
.dmDriverVersion
= 1;
1941 dm
.dmSize
= sizeof(DEVMODEA
);
1942 dm
.dmDriverExtra
= 0;
1944 DM_ORIENTATION
| DM_PAPERSIZE
|
1945 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
1948 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
1949 DM_YRESOLUTION
| DM_TTOPTION
;
1951 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
1952 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
1953 dm
.u1
.s1
.dmPaperLength
= 2970;
1954 dm
.u1
.s1
.dmPaperWidth
= 2100;
1958 dm
.dmDefaultSource
= DMBIN_AUTO
;
1959 dm
.dmPrintQuality
= DMRES_MEDIUM
;
1962 dm
.dmYResolution
= 300; /* 300dpi */
1963 dm
.dmTTOption
= DMTT_BITMAP
;
1966 /* dm.dmLogPixels */
1967 /* dm.dmBitsPerPel */
1968 /* dm.dmPelsWidth */
1969 /* dm.dmPelsHeight */
1970 /* dm.dmDisplayFlags */
1971 /* dm.dmDisplayFrequency */
1972 /* dm.dmICMMethod */
1973 /* dm.dmICMIntent */
1974 /* dm.dmMediaType */
1975 /* dm.dmDitherType */
1976 /* dm.dmReserved1 */
1977 /* dm.dmReserved2 */
1978 /* dm.dmPanningWidth */
1979 /* dm.dmPanningHeight */
1982 if(buflen
>= sizeof(DEVMODEW
)) {
1983 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
1984 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
1985 HeapFree(GetProcessHeap(),0,pdmW
);
1987 *needed
= sizeof(DEVMODEW
);
1991 if(buflen
>= sizeof(DEVMODEA
)) {
1992 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
1994 *needed
= sizeof(DEVMODEA
);
1998 /*****************************************************************************
1999 * WINSPOOL_GetDevModeFromReg
2001 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2002 * DevMode is stored either as unicode or ascii.
2004 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
2006 DWORD buflen
, DWORD
*needed
,
2009 DWORD sz
= buflen
, type
;
2012 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
2013 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
2014 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
2015 if (sz
< sizeof(DEVMODEA
))
2017 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName
),sz
);
2020 /* ensures that dmSize is not erratically bogus if registry is invalid */
2021 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
2022 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
2024 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2026 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
2027 memcpy(ptr
, dmW
, sz
);
2028 HeapFree(GetProcessHeap(),0,dmW
);
2035 /*********************************************************************
2036 * WINSPOOL_GetPrinter_2
2038 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2039 * The strings are either stored as unicode or ascii.
2041 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
2042 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2045 DWORD size
, left
= cbBuf
;
2046 BOOL space
= (cbBuf
> 0);
2051 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2053 if(space
&& size
<= left
) {
2054 pi2
->pPrinterName
= (LPWSTR
)ptr
;
2061 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
2063 if(space
&& size
<= left
) {
2064 pi2
->pShareName
= (LPWSTR
)ptr
;
2071 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
2073 if(space
&& size
<= left
) {
2074 pi2
->pPortName
= (LPWSTR
)ptr
;
2081 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
2083 if(space
&& size
<= left
) {
2084 pi2
->pDriverName
= (LPWSTR
)ptr
;
2091 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
2093 if(space
&& size
<= left
) {
2094 pi2
->pComment
= (LPWSTR
)ptr
;
2101 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
2103 if(space
&& size
<= left
) {
2104 pi2
->pLocation
= (LPWSTR
)ptr
;
2111 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
2113 if(space
&& size
<= left
) {
2114 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
2123 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
2124 if(space
&& size
<= left
) {
2125 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
2132 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
2134 if(space
&& size
<= left
) {
2135 pi2
->pSepFile
= (LPWSTR
)ptr
;
2142 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
2144 if(space
&& size
<= left
) {
2145 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
2152 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
2154 if(space
&& size
<= left
) {
2155 pi2
->pDatatype
= (LPWSTR
)ptr
;
2162 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
2164 if(space
&& size
<= left
) {
2165 pi2
->pParameters
= (LPWSTR
)ptr
;
2173 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2174 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
2175 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2176 "Default Priority");
2177 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
2178 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
2181 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
2182 memset(pi2
, 0, sizeof(*pi2
));
2187 /*********************************************************************
2188 * WINSPOOL_GetPrinter_4
2190 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2192 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
2193 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2196 DWORD size
, left
= cbBuf
;
2197 BOOL space
= (cbBuf
> 0);
2202 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2204 if(space
&& size
<= left
) {
2205 pi4
->pPrinterName
= (LPWSTR
)ptr
;
2213 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2216 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
2217 memset(pi4
, 0, sizeof(*pi4
));
2222 /*********************************************************************
2223 * WINSPOOL_GetPrinter_5
2225 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2227 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
2228 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
2231 DWORD size
, left
= cbBuf
;
2232 BOOL space
= (cbBuf
> 0);
2237 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
2239 if(space
&& size
<= left
) {
2240 pi5
->pPrinterName
= (LPWSTR
)ptr
;
2247 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
2249 if(space
&& size
<= left
) {
2250 pi5
->pPortName
= (LPWSTR
)ptr
;
2258 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
2259 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2261 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
2265 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
2266 memset(pi5
, 0, sizeof(*pi5
));
2271 /*****************************************************************************
2272 * WINSPOOL_GetPrinter
2274 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2275 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2276 * just a collection of pointers to strings.
2278 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2279 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
2282 DWORD size
, needed
= 0;
2284 HKEY hkeyPrinter
, hkeyPrinters
;
2287 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
2289 if (!(name
= get_opened_printer_name(hPrinter
))) {
2290 SetLastError(ERROR_INVALID_HANDLE
);
2294 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
2296 ERR("Can't create Printers key\n");
2299 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
2301 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
2302 RegCloseKey(hkeyPrinters
);
2303 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
2310 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
2312 size
= sizeof(PRINTER_INFO_2W
);
2314 ptr
= pPrinter
+ size
;
2316 memset(pPrinter
, 0, size
);
2321 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
2329 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
2331 size
= sizeof(PRINTER_INFO_4W
);
2333 ptr
= pPrinter
+ size
;
2335 memset(pPrinter
, 0, size
);
2340 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
2349 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
2351 size
= sizeof(PRINTER_INFO_5W
);
2353 ptr
= pPrinter
+ size
;
2355 memset(pPrinter
, 0, size
);
2361 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
2368 FIXME("Unimplemented level %ld\n", Level
);
2369 SetLastError(ERROR_INVALID_LEVEL
);
2370 RegCloseKey(hkeyPrinters
);
2371 RegCloseKey(hkeyPrinter
);
2375 RegCloseKey(hkeyPrinter
);
2376 RegCloseKey(hkeyPrinters
);
2378 TRACE("returning %d needed = %ld\n", ret
, needed
);
2379 if(pcbNeeded
) *pcbNeeded
= needed
;
2381 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2385 /*****************************************************************************
2386 * GetPrinterW [WINSPOOL.@]
2388 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2389 DWORD cbBuf
, LPDWORD pcbNeeded
)
2391 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
2395 /*****************************************************************************
2396 * GetPrinterA [WINSPOOL.@]
2398 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2399 DWORD cbBuf
, LPDWORD pcbNeeded
)
2401 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
2405 /*****************************************************************************
2406 * WINSPOOL_EnumPrinters
2408 * Implementation of EnumPrintersA|W
2410 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
2411 DWORD dwLevel
, LPBYTE lpbPrinters
,
2412 DWORD cbBuf
, LPDWORD lpdwNeeded
,
2413 LPDWORD lpdwReturned
, BOOL unicode
)
2416 HKEY hkeyPrinters
, hkeyPrinter
;
2417 WCHAR PrinterName
[255];
2418 DWORD needed
= 0, number
= 0;
2419 DWORD used
, i
, left
;
2423 memset(lpbPrinters
, 0, cbBuf
);
2429 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2430 if(dwType
== PRINTER_ENUM_DEFAULT
)
2433 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
2434 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2435 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
2436 if(!dwType
) return TRUE
;
2439 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
2440 FIXME("dwType = %08lx\n", dwType
);
2441 SetLastError(ERROR_INVALID_FLAGS
);
2445 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
2447 ERR("Can't create Printers key\n");
2451 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
2452 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
2453 RegCloseKey(hkeyPrinters
);
2454 ERR("Can't query Printers key\n");
2457 TRACE("Found %ld printers\n", number
);
2461 RegCloseKey(hkeyPrinters
);
2463 *lpdwReturned
= number
;
2467 used
= number
* sizeof(PRINTER_INFO_2W
);
2470 used
= number
* sizeof(PRINTER_INFO_4W
);
2473 used
= number
* sizeof(PRINTER_INFO_5W
);
2477 SetLastError(ERROR_INVALID_LEVEL
);
2478 RegCloseKey(hkeyPrinters
);
2481 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
2483 for(i
= 0; i
< number
; i
++) {
2484 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) !=
2486 ERR("Can't enum key number %ld\n", i
);
2487 RegCloseKey(hkeyPrinters
);
2490 TRACE("Printer %ld is %s\n", i
, debugstr_w(PrinterName
));
2491 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
2493 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
2494 RegCloseKey(hkeyPrinters
);
2499 buf
= lpbPrinters
+ used
;
2500 left
= cbBuf
- used
;
2508 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
2509 left
, &needed
, unicode
);
2511 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
2514 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
2515 left
, &needed
, unicode
);
2517 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
2520 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
2521 left
, &needed
, unicode
);
2523 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
2526 ERR("Shouldn't be here!\n");
2527 RegCloseKey(hkeyPrinter
);
2528 RegCloseKey(hkeyPrinters
);
2531 RegCloseKey(hkeyPrinter
);
2533 RegCloseKey(hkeyPrinters
);
2540 memset(lpbPrinters
, 0, cbBuf
);
2541 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2545 *lpdwReturned
= number
;
2546 SetLastError(ERROR_SUCCESS
);
2551 /******************************************************************
2552 * EnumPrintersW [WINSPOOL.@]
2554 * Enumerates the available printers, print servers and print
2555 * providers, depending on the specified flags, name and level.
2559 * If level is set to 1:
2560 * Not implemented yet!
2561 * Returns TRUE with an empty list.
2563 * If level is set to 2:
2564 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2565 * Returns an array of PRINTER_INFO_2 data structures in the
2566 * lpbPrinters buffer. Note that according to MSDN also an
2567 * OpenPrinter should be performed on every remote printer.
2569 * If level is set to 4 (officially WinNT only):
2570 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2571 * Fast: Only the registry is queried to retrieve printer names,
2572 * no connection to the driver is made.
2573 * Returns an array of PRINTER_INFO_4 data structures in the
2574 * lpbPrinters buffer.
2576 * If level is set to 5 (officially WinNT4/Win9x only):
2577 * Fast: Only the registry is queried to retrieve printer names,
2578 * no connection to the driver is made.
2579 * Returns an array of PRINTER_INFO_5 data structures in the
2580 * lpbPrinters buffer.
2582 * If level set to 3 or 6+:
2583 * returns zero (failure!)
2585 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2589 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2590 * - Only levels 2, 4 and 5 are implemented at the moment.
2591 * - 16-bit printer drivers are not enumerated.
2592 * - Returned amount of bytes used/needed does not match the real Windoze
2593 * implementation (as in this implementation, all strings are part
2594 * of the buffer, whereas Win32 keeps them somewhere else)
2595 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2598 * - In a regular Wine installation, no registry settings for printers
2599 * exist, which makes this function return an empty list.
2601 BOOL WINAPI
EnumPrintersW(
2602 DWORD dwType
, /* [in] Types of print objects to enumerate */
2603 LPWSTR lpszName
, /* [in] name of objects to enumerate */
2604 DWORD dwLevel
, /* [in] type of printer info structure */
2605 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
2606 DWORD cbBuf
, /* [in] max size of buffer in bytes */
2607 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
2608 LPDWORD lpdwReturned
/* [out] number of entries returned */
2611 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
2612 lpdwNeeded
, lpdwReturned
, TRUE
);
2615 /******************************************************************
2616 * EnumPrintersA [WINSPOOL.@]
2619 BOOL WINAPI
EnumPrintersA(DWORD dwType
, LPSTR lpszName
,
2620 DWORD dwLevel
, LPBYTE lpbPrinters
,
2621 DWORD cbBuf
, LPDWORD lpdwNeeded
,
2622 LPDWORD lpdwReturned
)
2625 UNICODE_STRING lpszNameW
;
2628 pwstrNameW
= asciitounicode(&lpszNameW
,lpszName
);
2629 ret
= WINSPOOL_EnumPrinters(dwType
, pwstrNameW
, dwLevel
, lpbPrinters
, cbBuf
,
2630 lpdwNeeded
, lpdwReturned
, FALSE
);
2631 RtlFreeUnicodeString(&lpszNameW
);
2635 /*****************************************************************************
2636 * WINSPOOL_GetDriverInfoFromReg [internal]
2638 * Enters the information from the registry into the DRIVER_INFO struct
2641 * zero if the printer driver does not exist in the registry
2642 * (only if Level > 1) otherwise nonzero
2644 static BOOL
WINSPOOL_GetDriverInfoFromReg(
2647 LPWSTR pEnvironment
,
2649 LPBYTE ptr
, /* DRIVER_INFO */
2650 LPBYTE pDriverStrings
, /* strings buffer */
2651 DWORD cbBuf
, /* size of string buffer */
2652 LPDWORD pcbNeeded
, /* space needed for str. */
2653 BOOL unicode
) /* type of strings */
2654 { DWORD dw
, size
, tmp
, type
;
2656 LPBYTE strPtr
= pDriverStrings
;
2658 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2659 debugstr_w(DriverName
), debugstr_w(pEnvironment
),
2660 Level
, ptr
, pDriverStrings
, cbBuf
, unicode
);
2663 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
2664 if (*pcbNeeded
<= cbBuf
)
2665 strcpyW((LPWSTR
)strPtr
, DriverName
);
2667 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0,
2669 if(*pcbNeeded
<= cbBuf
)
2670 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, strPtr
, *pcbNeeded
,
2675 ((PDRIVER_INFO_1W
) ptr
)->pName
= (LPWSTR
) strPtr
;
2679 ((PDRIVER_INFO_3W
) ptr
)->pName
= (LPWSTR
) strPtr
;
2680 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
2683 if(!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
2684 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName
));
2685 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
2690 if(RegQueryValueExA(hkeyDriver
, "Version", 0, &type
, (PBYTE
)&dw
, &size
) !=
2692 WARN("Can't get Version\n");
2694 ((PDRIVER_INFO_3A
) ptr
)->cVersion
= dw
;
2697 pEnvironment
= (LPWSTR
)DefaultEnvironmentW
;
2699 size
= (lstrlenW(pEnvironment
) + 1) * sizeof(WCHAR
);
2701 size
= WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0,
2704 if(*pcbNeeded
<= cbBuf
) {
2706 strcpyW((LPWSTR
)strPtr
, pEnvironment
);
2708 WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1, strPtr
, size
,
2711 ((PDRIVER_INFO_3W
) ptr
)->pEnvironment
= (LPWSTR
)strPtr
;
2712 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
2715 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, 0, &size
,
2718 if(*pcbNeeded
<= cbBuf
)
2719 WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, size
, &tmp
,
2722 ((PDRIVER_INFO_3W
) ptr
)->pDriverPath
= (LPWSTR
)strPtr
;
2723 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
2726 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, 0, &size
,
2729 if(*pcbNeeded
<= cbBuf
)
2730 WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, size
,
2733 ((PDRIVER_INFO_3W
) ptr
)->pDataFile
= (LPWSTR
)strPtr
;
2734 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
2737 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
2738 0, &size
, unicode
)) {
2740 if(*pcbNeeded
<= cbBuf
)
2741 WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
2742 size
, &tmp
, unicode
);
2744 ((PDRIVER_INFO_3W
) ptr
)->pConfigFile
= (LPWSTR
)strPtr
;
2745 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
2749 RegCloseKey(hkeyDriver
);
2750 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
2754 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
, 0, &size
,
2757 if(*pcbNeeded
<= cbBuf
)
2758 WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
,
2759 size
, &tmp
, unicode
);
2761 ((PDRIVER_INFO_3W
) ptr
)->pHelpFile
= (LPWSTR
)strPtr
;
2762 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
2765 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
, 0,
2768 if(*pcbNeeded
<= cbBuf
)
2769 WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
,
2770 size
, &tmp
, unicode
);
2772 ((PDRIVER_INFO_3W
) ptr
)->pDependentFiles
= (LPWSTR
)strPtr
;
2773 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
2776 if(WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
,
2779 if(*pcbNeeded
<= cbBuf
)
2780 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
,
2781 size
, &tmp
, unicode
);
2783 ((PDRIVER_INFO_3W
) ptr
)->pMonitorName
= (LPWSTR
)strPtr
;
2784 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
2787 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
,
2790 if(*pcbNeeded
<= cbBuf
)
2791 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
,
2792 size
, &tmp
, unicode
);
2794 ((PDRIVER_INFO_3W
) ptr
)->pDefaultDataType
= (LPWSTR
)strPtr
;
2795 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
2798 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
2799 RegCloseKey(hkeyDriver
);
2803 /*****************************************************************************
2804 * WINSPOOL_GetPrinterDriver
2806 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPWSTR pEnvironment
,
2807 DWORD Level
, LPBYTE pDriverInfo
,
2808 DWORD cbBuf
, LPDWORD pcbNeeded
,
2812 WCHAR DriverName
[100];
2813 DWORD ret
, type
, size
, needed
= 0;
2815 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
2817 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
2818 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
2820 ZeroMemory(pDriverInfo
, cbBuf
);
2822 if (!(name
= get_opened_printer_name(hPrinter
))) {
2823 SetLastError(ERROR_INVALID_HANDLE
);
2826 if(Level
< 1 || Level
> 3) {
2827 SetLastError(ERROR_INVALID_LEVEL
);
2830 if(RegCreateKeyA(HKEY_LOCAL_MACHINE
, Printers
, &hkeyPrinters
) !=
2832 ERR("Can't create Printers key\n");
2835 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
2837 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
2838 RegCloseKey(hkeyPrinters
);
2839 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
2842 size
= sizeof(DriverName
);
2844 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
2845 (LPBYTE
)DriverName
, &size
);
2846 RegCloseKey(hkeyPrinter
);
2847 RegCloseKey(hkeyPrinters
);
2848 if(ret
!= ERROR_SUCCESS
) {
2849 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
2853 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
2855 ERR("Can't create Drivers key\n");
2861 size
= sizeof(DRIVER_INFO_1W
);
2864 size
= sizeof(DRIVER_INFO_2W
);
2867 size
= sizeof(DRIVER_INFO_3W
);
2870 ERR("Invalid level\n");
2875 ptr
= pDriverInfo
+ size
;
2877 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
2878 pEnvironment
, Level
, pDriverInfo
,
2879 (cbBuf
< size
) ? NULL
: ptr
,
2880 (cbBuf
< size
) ? 0 : cbBuf
- size
,
2881 &needed
, unicode
)) {
2882 RegCloseKey(hkeyDrivers
);
2886 RegCloseKey(hkeyDrivers
);
2888 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
2889 TRACE("buffer space %ld required %ld\n", cbBuf
, *pcbNeeded
);
2890 if(cbBuf
>= needed
) return TRUE
;
2891 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2895 /*****************************************************************************
2896 * GetPrinterDriverA [WINSPOOL.@]
2898 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
2899 DWORD Level
, LPBYTE pDriverInfo
,
2900 DWORD cbBuf
, LPDWORD pcbNeeded
)
2903 UNICODE_STRING pEnvW
;
2906 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
2907 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
2908 cbBuf
, pcbNeeded
, FALSE
);
2909 RtlFreeUnicodeString(&pEnvW
);
2912 /*****************************************************************************
2913 * GetPrinterDriverW [WINSPOOL.@]
2915 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
2916 DWORD Level
, LPBYTE pDriverInfo
,
2917 DWORD cbBuf
, LPDWORD pcbNeeded
)
2919 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
2920 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
2923 /*****************************************************************************
2924 * GetPrinterDriverDirectoryW [WINSPOOL.@]
2926 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
2927 DWORD Level
, LPBYTE pDriverDirectory
,
2928 DWORD cbBuf
, LPDWORD pcbNeeded
)
2932 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName
),
2933 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
2935 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName
));
2936 SetLastError(ERROR_INVALID_PARAMETER
);
2939 if(pEnvironment
!= NULL
) {
2940 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment
));
2941 SetLastError(ERROR_INVALID_ENVIRONMENT
);
2944 if(Level
!= 1) /* win95 ignores this so we just carry on */
2945 WARN("Level = %ld - assuming 1\n", Level
);
2947 /* FIXME should read from registry */
2948 needed
= GetSystemDirectoryW( (LPWSTR
)pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
2949 /* GetSystemDirectoryW returns number of TCHAR without '\0'
2953 needed
*=sizeof(WCHAR
);
2956 *pcbNeeded
= needed
;
2957 TRACE("required <%08lx>\n", *pcbNeeded
);
2958 if(needed
> cbBuf
) {
2959 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2966 /*****************************************************************************
2967 * GetPrinterDriverDirectoryA [WINSPOOL.@]
2969 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
2970 DWORD Level
, LPBYTE pDriverDirectory
,
2971 DWORD cbBuf
, LPDWORD pcbNeeded
)
2973 UNICODE_STRING nameW
, environmentW
;
2976 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
2977 WCHAR
*driverDirectoryW
= NULL
;
2979 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
2981 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
2982 else nameW
.Buffer
= NULL
;
2983 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
2984 else environmentW
.Buffer
= NULL
;
2986 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
2987 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
2990 needed
= 1 + WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
2991 pDriverDirectory
, cbBuf
, NULL
, NULL
);
2993 *pcbNeeded
= needed
;
2994 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
2996 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
2998 TRACE("provided<%ld> required <%ld>\n", cbBuf
, *pcbNeeded
);
3000 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
3001 RtlFreeUnicodeString(&environmentW
);
3002 RtlFreeUnicodeString(&nameW
);
3007 /*****************************************************************************
3008 * AddPrinterDriverA [WINSPOOL.@]
3010 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
3013 HKEY hkeyDrivers
, hkeyName
;
3015 TRACE("(%s,%ld,%p)\n",debugstr_a(pName
),level
,pDriverInfo
);
3017 if(level
!= 2 && level
!= 3) {
3018 SetLastError(ERROR_INVALID_LEVEL
);
3022 FIXME("pName= %s - unsupported\n", debugstr_a(pName
));
3023 SetLastError(ERROR_INVALID_PARAMETER
);
3027 WARN("pDriverInfo == NULL\n");
3028 SetLastError(ERROR_INVALID_PARAMETER
);
3033 di3
= *(DRIVER_INFO_3A
*)pDriverInfo
;
3035 memset(&di3
, 0, sizeof(di3
));
3036 memcpy(&di3
, pDriverInfo
, sizeof(DRIVER_INFO_2A
));
3039 if(!di3
.pName
|| !di3
.pDriverPath
|| !di3
.pConfigFile
||
3041 SetLastError(ERROR_INVALID_PARAMETER
);
3044 if(!di3
.pDefaultDataType
) di3
.pDefaultDataType
= "";
3045 if(!di3
.pDependentFiles
) di3
.pDependentFiles
= "\0";
3046 if(!di3
.pHelpFile
) di3
.pHelpFile
= "";
3047 if(!di3
.pMonitorName
) di3
.pMonitorName
= "";
3049 hkeyDrivers
= WINSPOOL_OpenDriverReg(di3
.pEnvironment
, FALSE
);
3052 ERR("Can't create Drivers key\n");
3056 if(level
== 2) { /* apparently can't overwrite with level2 */
3057 if(RegOpenKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) == ERROR_SUCCESS
) {
3058 RegCloseKey(hkeyName
);
3059 RegCloseKey(hkeyDrivers
);
3060 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3
.pName
));
3061 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
3065 if(RegCreateKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) != ERROR_SUCCESS
) {
3066 RegCloseKey(hkeyDrivers
);
3067 ERR("Can't create Name key\n");
3070 RegSetValueExA(hkeyName
, "Configuration File", 0, REG_SZ
, di3
.pConfigFile
,
3072 RegSetValueExA(hkeyName
, "Data File", 0, REG_SZ
, di3
.pDataFile
, 0);
3073 RegSetValueExA(hkeyName
, "Driver", 0, REG_SZ
, di3
.pDriverPath
, 0);
3074 RegSetValueExA(hkeyName
, "Version", 0, REG_DWORD
, (LPSTR
)&di3
.cVersion
,
3076 RegSetValueExA(hkeyName
, "Datatype", 0, REG_SZ
, di3
.pDefaultDataType
, 0);
3077 RegSetValueExA(hkeyName
, "Dependent Files", 0, REG_MULTI_SZ
,
3078 di3
.pDependentFiles
, 0);
3079 RegSetValueExA(hkeyName
, "Help File", 0, REG_SZ
, di3
.pHelpFile
, 0);
3080 RegSetValueExA(hkeyName
, "Monitor", 0, REG_SZ
, di3
.pMonitorName
, 0);
3081 RegCloseKey(hkeyName
);
3082 RegCloseKey(hkeyDrivers
);
3087 /*****************************************************************************
3088 * AddPrinterDriverW [WINSPOOL.@]
3090 BOOL WINAPI
AddPrinterDriverW(LPWSTR printerName
,DWORD level
,
3093 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName
),
3098 /*****************************************************************************
3099 * AddPrintProcessorA [WINSPOOL.@]
3101 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
3102 LPSTR pPrintProcessorName
)
3104 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
3105 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
3109 /*****************************************************************************
3110 * AddPrintProcessorW [WINSPOOL.@]
3112 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
3113 LPWSTR pPrintProcessorName
)
3115 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
3116 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
3120 /*****************************************************************************
3121 * AddPrintProvidorA [WINSPOOL.@]
3123 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
3125 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
3129 /*****************************************************************************
3130 * AddPrintProvidorW [WINSPOOL.@]
3132 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
3134 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
3138 /*****************************************************************************
3139 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3141 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
3142 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
3144 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
3145 pDevModeOutput
, pDevModeInput
);
3149 /*****************************************************************************
3150 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3152 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
3153 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
3155 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
3156 pDevModeOutput
, pDevModeInput
);
3160 /*****************************************************************************
3161 * PrinterProperties [WINSPOOL.@]
3163 * Displays a dialog to set the properties of the printer.
3166 * nonzero on success or zero on failure
3169 * implemented as stub only
3171 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
3172 HANDLE hPrinter
/* [in] handle to printer object */
3174 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
3175 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3179 /*****************************************************************************
3180 * EnumJobsA [WINSPOOL.@]
3183 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
3184 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3187 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3188 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
3190 if(pcbNeeded
) *pcbNeeded
= 0;
3191 if(pcReturned
) *pcReturned
= 0;
3196 /*****************************************************************************
3197 * EnumJobsW [WINSPOOL.@]
3200 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
3201 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3204 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3205 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
3207 if(pcbNeeded
) *pcbNeeded
= 0;
3208 if(pcReturned
) *pcReturned
= 0;
3212 /*****************************************************************************
3213 * WINSPOOL_EnumPrinterDrivers [internal]
3215 * Delivers information about all printer drivers installed on the
3216 * localhost or a given server
3219 * nonzero on success or zero on failure. If the buffer for the returned
3220 * information is too small the function will return an error
3223 * - only implemented for localhost, foreign hosts will return an error
3225 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPWSTR pEnvironment
,
3226 DWORD Level
, LPBYTE pDriverInfo
,
3227 DWORD cbBuf
, LPDWORD pcbNeeded
,
3228 LPDWORD pcReturned
, BOOL unicode
)
3231 DWORD i
, needed
, number
= 0, size
= 0;
3232 WCHAR DriverNameW
[255];
3235 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3236 debugstr_w(pName
), debugstr_w(pEnvironment
),
3237 Level
, pDriverInfo
, cbBuf
, unicode
);
3239 /* check for local drivers */
3241 ERR("remote drivers unsupported! Current remote host is %s\n",
3246 /* check input parameter */
3247 if((Level
< 1) || (Level
> 3)) {
3248 ERR("unsupported level %ld\n", Level
);
3249 SetLastError(ERROR_INVALID_LEVEL
);
3253 /* initialize return values */
3255 memset( pDriverInfo
, 0, cbBuf
);
3259 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
3261 ERR("Can't open Drivers key\n");
3265 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
3266 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
3267 RegCloseKey(hkeyDrivers
);
3268 ERR("Can't query Drivers key\n");
3271 TRACE("Found %ld Drivers\n", number
);
3273 /* get size of single struct
3274 * unicode and ascii structure have the same size
3278 size
= sizeof(DRIVER_INFO_1A
);
3281 size
= sizeof(DRIVER_INFO_2A
);
3284 size
= sizeof(DRIVER_INFO_3A
);
3288 /* calculate required buffer size */
3289 *pcbNeeded
= size
* number
;
3291 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
3293 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
3294 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
))
3296 ERR("Can't enum key number %ld\n", i
);
3297 RegCloseKey(hkeyDrivers
);
3300 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
3301 pEnvironment
, Level
, ptr
,
3302 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
3303 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
3304 &needed
, unicode
)) {
3305 RegCloseKey(hkeyDrivers
);
3308 (*pcbNeeded
) += needed
;
3311 RegCloseKey(hkeyDrivers
);
3313 if(cbBuf
< *pcbNeeded
){
3314 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3321 /*****************************************************************************
3322 * EnumPrinterDriversW [WINSPOOL.@]
3324 * see function EnumPrinterDrivers for RETURNS, BUGS
3326 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
3327 LPBYTE pDriverInfo
, DWORD cbBuf
,
3328 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
3330 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
3331 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
3334 /*****************************************************************************
3335 * EnumPrinterDriversA [WINSPOOL.@]
3337 * see function EnumPrinterDrivers for RETURNS, BUGS
3339 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
3340 LPBYTE pDriverInfo
, DWORD cbBuf
,
3341 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
3343 UNICODE_STRING pNameW
, pEnvironmentW
;
3344 PWSTR pwstrNameW
, pwstrEnvironmentW
;
3346 pwstrNameW
= asciitounicode(&pNameW
, pName
);
3347 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
3349 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
3350 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
3352 RtlFreeUnicodeString(&pNameW
);
3353 RtlFreeUnicodeString(&pEnvironmentW
);
3358 static CHAR PortMonitor
[] = "Wine Port Monitor";
3359 static CHAR PortDescription
[] = "Wine Port";
3361 static BOOL
WINSPOOL_ComPortExists( LPCSTR name
)
3365 handle
= CreateFileA( name
, 0, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3366 NULL
, OPEN_EXISTING
, 0, NULL
);
3367 if (handle
== INVALID_HANDLE_VALUE
)
3369 TRACE("Checking %s exists\n", name
);
3370 CloseHandle( handle
);
3374 static DWORD
WINSPOOL_CountSerialPorts(void)
3381 strcpy( name
, "COMx:" );
3383 if (WINSPOOL_ComPortExists( name
))
3390 /******************************************************************************
3391 * EnumPortsA (WINSPOOL.@)
3393 BOOL WINAPI
EnumPortsA(LPSTR name
,DWORD level
,LPBYTE buffer
,DWORD bufsize
,
3394 LPDWORD bufneeded
,LPDWORD bufreturned
)
3397 DWORD info_size
, ofs
, i
, printer_count
, serial_count
, count
, n
, r
;
3398 const LPCSTR szPrinterPortKey
= "Software\\Wine\\Wine\\Config\\spooler";
3402 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3403 debugstr_a(name
),level
,buffer
,bufsize
,bufneeded
,bufreturned
);
3408 info_size
= sizeof (PORT_INFO_1A
);
3411 info_size
= sizeof (PORT_INFO_2A
);
3414 SetLastError(ERROR_INVALID_LEVEL
);
3418 /* see how many exist */
3421 serial_count
= WINSPOOL_CountSerialPorts();
3424 r
= RegOpenKeyA( HKEY_LOCAL_MACHINE
, szPrinterPortKey
, &hkey_printer
);
3425 if ( r
== ERROR_SUCCESS
)
3427 RegQueryInfoKeyA( hkey_printer
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3428 &printer_count
, NULL
, NULL
, NULL
, NULL
);
3430 count
= serial_count
+ printer_count
;
3432 /* then fill in the structure info structure once
3433 we know the offset to the first string */
3435 memset( buffer
, 0, bufsize
);
3437 ofs
= info_size
*count
;
3438 for ( i
=0; i
<count
; i
++)
3440 DWORD vallen
= sizeof(portname
) - 1;
3442 /* get the serial port values, then the printer values */
3443 if ( i
< serial_count
)
3445 strcpy( portname
, "COMx:" );
3446 portname
[3] = '1' + i
;
3447 if (!WINSPOOL_ComPortExists( portname
))
3450 TRACE("Found %s\n", portname
);
3451 vallen
= strlen( portname
);
3455 r
= RegEnumValueA( hkey_printer
, i
-serial_count
,
3456 portname
, &vallen
, NULL
, NULL
, NULL
, 0 );
3461 /* add a colon if necessary, and make it upper case */
3462 CharUpperBuffA(portname
,vallen
);
3463 if (strcasecmp(portname
,"nul")!=0)
3464 if (vallen
&& (portname
[vallen
-1] != ':') )
3465 lstrcatA(portname
,":");
3467 /* add the port info structure if we can fit it */
3468 if ( info_size
*(n
+1) < bufsize
)
3472 PORT_INFO_1A
*info
= (PORT_INFO_1A
*) &buffer
[info_size
*n
];
3473 info
->pName
= (LPSTR
) &buffer
[ofs
];
3475 else if ( level
== 2)
3477 PORT_INFO_2A
*info
= (PORT_INFO_2A
*) &buffer
[info_size
*n
];
3478 info
->pPortName
= (LPSTR
) &buffer
[ofs
];
3479 /* FIXME: fill in more stuff here */
3480 info
->pMonitorName
= PortMonitor
;
3481 info
->pDescription
= PortDescription
;
3482 info
->fPortType
= PORT_TYPE_WRITE
|PORT_TYPE_READ
;
3485 /* add the name of the port if we can fit it */
3486 if ( ofs
< bufsize
)
3487 lstrcpynA(&buffer
[ofs
],portname
,bufsize
- ofs
);
3493 ofs
+= lstrlenA(portname
)+1;
3496 RegCloseKey(hkey_printer
);
3507 /******************************************************************************
3508 * EnumPortsW (WINSPOOL.@)
3510 BOOL WINAPI
EnumPortsW(LPWSTR name
,DWORD level
,LPBYTE buffer
,DWORD bufsize
,
3511 LPDWORD bufneeded
,LPDWORD bufreturned
)
3513 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
3514 debugstr_w(name
),level
,buffer
,bufsize
,bufneeded
,bufreturned
);
3518 /******************************************************************************
3519 * GetDefaultPrinterW (WINSPOOL.@)
3522 * This function must read the value from data 'device' of key
3523 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
3525 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
3529 WCHAR
*buffer
, *ptr
;
3533 SetLastError(ERROR_INVALID_PARAMETER
);
3537 /* make the buffer big enough for the stuff from the profile/registry,
3538 * the content must fit into the local buffer to compute the correct
3539 * size even if the extern buffer is too small or not given.
3540 * (20 for ,driver,port) */
3542 len
= max(100, (insize
+ 20));
3543 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3545 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
3547 SetLastError (ERROR_FILE_NOT_FOUND
);
3551 TRACE("%s\n", debugstr_w(buffer
));
3553 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
3555 SetLastError(ERROR_INVALID_NAME
);
3561 *namesize
= strlenW(buffer
) + 1;
3562 if(!name
|| (*namesize
> insize
))
3564 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3568 strcpyW(name
, buffer
);
3571 HeapFree( GetProcessHeap(), 0, buffer
);
3576 /******************************************************************************
3577 * GetDefaultPrinterA (WINSPOOL.@)
3579 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
3583 WCHAR
*bufferW
= NULL
;
3587 SetLastError(ERROR_INVALID_PARAMETER
);
3591 if(name
&& *namesize
) {
3593 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
3596 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
3601 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
3605 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
3608 TRACE("0x%08lx/0x%08lx:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
3611 HeapFree( GetProcessHeap(), 0, bufferW
);
3616 /******************************************************************************
3617 * SetPrinterDataExA (WINSPOOL.@)
3619 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
3620 LPCSTR pValueName
, DWORD Type
,
3621 LPBYTE pData
, DWORD cbData
)
3623 HKEY hkeyPrinter
, hkeySubkey
;
3626 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_a(pKeyName
),
3627 debugstr_a(pValueName
), Type
, pData
, cbData
);
3629 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
3633 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
3635 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
3636 RegCloseKey(hkeyPrinter
);
3639 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
3640 RegCloseKey(hkeySubkey
);
3641 RegCloseKey(hkeyPrinter
);
3645 /******************************************************************************
3646 * SetPrinterDataExW (WINSPOOL.@)
3648 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
3649 LPCWSTR pValueName
, DWORD Type
,
3650 LPBYTE pData
, DWORD cbData
)
3652 HKEY hkeyPrinter
, hkeySubkey
;
3655 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter
, debugstr_w(pKeyName
),
3656 debugstr_w(pValueName
), Type
, pData
, cbData
);
3658 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
3662 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
3664 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
3665 RegCloseKey(hkeyPrinter
);
3668 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
3669 RegCloseKey(hkeySubkey
);
3670 RegCloseKey(hkeyPrinter
);
3674 /******************************************************************************
3675 * SetPrinterDataA (WINSPOOL.@)
3677 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
3678 LPBYTE pData
, DWORD cbData
)
3680 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
3684 /******************************************************************************
3685 * SetPrinterDataW (WINSPOOL.@)
3687 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
3688 LPBYTE pData
, DWORD cbData
)
3690 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
3694 /******************************************************************************
3695 * GetPrinterDataExA (WINSPOOL.@)
3697 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
3698 LPCSTR pValueName
, LPDWORD pType
,
3699 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
3701 HKEY hkeyPrinter
, hkeySubkey
;
3704 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter
,
3705 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
3708 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
3712 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
3714 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
3715 RegCloseKey(hkeyPrinter
);
3719 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
3720 RegCloseKey(hkeySubkey
);
3721 RegCloseKey(hkeyPrinter
);
3725 /******************************************************************************
3726 * GetPrinterDataExW (WINSPOOL.@)
3728 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
3729 LPCWSTR pValueName
, LPDWORD pType
,
3730 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
3732 HKEY hkeyPrinter
, hkeySubkey
;
3735 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter
,
3736 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
3739 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
3743 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
3745 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
3746 RegCloseKey(hkeyPrinter
);
3750 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
3751 RegCloseKey(hkeySubkey
);
3752 RegCloseKey(hkeyPrinter
);
3756 /******************************************************************************
3757 * GetPrinterDataA (WINSPOOL.@)
3759 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
3760 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
3762 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
3763 pData
, nSize
, pcbNeeded
);
3766 /******************************************************************************
3767 * GetPrinterDataW (WINSPOOL.@)
3769 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
3770 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
3772 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
3773 pData
, nSize
, pcbNeeded
);
3776 /*******************************************************************************
3777 * EnumPrinterDataExW [WINSPOOL.@]
3779 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
3780 LPBYTE pEnumValues
, DWORD cbEnumValues
,
3781 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
3783 HKEY hkPrinter
, hkSubKey
;
3784 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
3785 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
3790 PPRINTER_ENUM_VALUESW ppev
;
3792 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
3794 if (pKeyName
== NULL
|| *pKeyName
== 0)
3795 return ERROR_INVALID_PARAMETER
;
3797 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
3798 if (ret
!= ERROR_SUCCESS
)
3800 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
3805 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
3806 if (ret
!= ERROR_SUCCESS
)
3808 r
= RegCloseKey (hkPrinter
);
3809 if (r
!= ERROR_SUCCESS
)
3810 WARN ("RegCloseKey returned %li\n", r
);
3811 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter
,
3812 debugstr_w (pKeyName
), ret
);
3816 ret
= RegCloseKey (hkPrinter
);
3817 if (ret
!= ERROR_SUCCESS
)
3819 ERR ("RegCloseKey returned %li\n", ret
);
3820 r
= RegCloseKey (hkSubKey
);
3821 if (r
!= ERROR_SUCCESS
)
3822 WARN ("RegCloseKey returned %li\n", r
);
3826 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3827 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
3828 if (ret
!= ERROR_SUCCESS
)
3830 r
= RegCloseKey (hkSubKey
);
3831 if (r
!= ERROR_SUCCESS
)
3832 WARN ("RegCloseKey returned %li\n", r
);
3833 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey
, ret
);
3837 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
3838 "cbMaxValueLen = %li\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
3840 if (cValues
== 0) /* empty key */
3842 r
= RegCloseKey (hkSubKey
);
3843 if (r
!= ERROR_SUCCESS
)
3844 WARN ("RegCloseKey returned %li\n", r
);
3845 *pcbEnumValues
= *pnEnumValues
= 0;
3846 return ERROR_SUCCESS
;
3849 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
3851 hHeap
= GetProcessHeap ();
3854 ERR ("GetProcessHeap failed\n");
3855 r
= RegCloseKey (hkSubKey
);
3856 if (r
!= ERROR_SUCCESS
)
3857 WARN ("RegCloseKey returned %li\n", r
);
3858 return ERROR_OUTOFMEMORY
;
3861 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
3862 if (lpValueName
== NULL
)
3864 ERR ("Failed to allocate %li bytes from process heap\n",
3865 cbMaxValueNameLen
* sizeof (WCHAR
));
3866 r
= RegCloseKey (hkSubKey
);
3867 if (r
!= ERROR_SUCCESS
)
3868 WARN ("RegCloseKey returned %li\n", r
);
3869 return ERROR_OUTOFMEMORY
;
3872 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
3873 if (lpValue
== NULL
)
3875 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen
);
3876 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
3877 WARN ("HeapFree failed with code %li\n", GetLastError ());
3878 r
= RegCloseKey (hkSubKey
);
3879 if (r
!= ERROR_SUCCESS
)
3880 WARN ("RegCloseKey returned %li\n", r
);
3881 return ERROR_OUTOFMEMORY
;
3884 TRACE ("pass 1: calculating buffer required for all names and values\n");
3886 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
3888 TRACE ("%li bytes required for %li headers\n", cbBufSize
, cValues
);
3890 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
3892 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
3893 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
3894 NULL
, NULL
, lpValue
, &cbValueLen
);
3895 if (ret
!= ERROR_SUCCESS
)
3897 if (HeapFree (hHeap
, 0, lpValue
) == 0)
3898 WARN ("HeapFree failed with code %li\n", GetLastError ());
3899 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
3900 WARN ("HeapFree failed with code %li\n", GetLastError ());
3901 r
= RegCloseKey (hkSubKey
);
3902 if (r
!= ERROR_SUCCESS
)
3903 WARN ("RegCloseKey returned %li\n", r
);
3904 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
3908 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
3909 debugstr_w (lpValueName
), dwIndex
,
3910 (cbValueNameLen
+ 1) * sizeof (WCHAR
), cbValueLen
);
3912 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
3913 cbBufSize
+= cbValueLen
;
3916 TRACE ("%li bytes required for all %li values\n", cbBufSize
, cValues
);
3918 *pcbEnumValues
= cbBufSize
;
3919 *pnEnumValues
= cValues
;
3921 if (cbEnumValues
< cbBufSize
) /* buffer too small */
3923 if (HeapFree (hHeap
, 0, lpValue
) == 0)
3924 WARN ("HeapFree failed with code %li\n", GetLastError ());
3925 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
3926 WARN ("HeapFree failed with code %li\n", GetLastError ());
3927 r
= RegCloseKey (hkSubKey
);
3928 if (r
!= ERROR_SUCCESS
)
3929 WARN ("RegCloseKey returned %li\n", r
);
3930 TRACE ("%li byte buffer is not large enough\n", cbEnumValues
);
3931 return ERROR_MORE_DATA
;
3934 TRACE ("pass 2: copying all names and values to buffer\n");
3936 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
3937 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
3939 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
3941 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
3942 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
3943 NULL
, &dwType
, lpValue
, &cbValueLen
);
3944 if (ret
!= ERROR_SUCCESS
)
3946 if (HeapFree (hHeap
, 0, lpValue
) == 0)
3947 WARN ("HeapFree failed with code %li\n", GetLastError ());
3948 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
3949 WARN ("HeapFree failed with code %li\n", GetLastError ());
3950 r
= RegCloseKey (hkSubKey
);
3951 if (r
!= ERROR_SUCCESS
)
3952 WARN ("RegCloseKey returned %li\n", r
);
3953 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex
, ret
);
3957 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
3958 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
3959 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
3960 pEnumValues
+= cbValueNameLen
;
3962 /* return # of *bytes* (including trailing \0), not # of chars */
3963 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
3965 ppev
[dwIndex
].dwType
= dwType
;
3967 memcpy (pEnumValues
, lpValue
, cbValueLen
);
3968 ppev
[dwIndex
].pData
= pEnumValues
;
3969 pEnumValues
+= cbValueLen
;
3971 ppev
[dwIndex
].cbData
= cbValueLen
;
3973 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
3974 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
3977 if (HeapFree (hHeap
, 0, lpValue
) == 0)
3979 ret
= GetLastError ();
3980 ERR ("HeapFree failed with code %li\n", ret
);
3981 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
3982 WARN ("HeapFree failed with code %li\n", GetLastError ());
3983 r
= RegCloseKey (hkSubKey
);
3984 if (r
!= ERROR_SUCCESS
)
3985 WARN ("RegCloseKey returned %li\n", r
);
3989 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
3991 ret
= GetLastError ();
3992 ERR ("HeapFree failed with code %li\n", ret
);
3993 r
= RegCloseKey (hkSubKey
);
3994 if (r
!= ERROR_SUCCESS
)
3995 WARN ("RegCloseKey returned %li\n", r
);
3999 ret
= RegCloseKey (hkSubKey
);
4000 if (ret
!= ERROR_SUCCESS
)
4002 ERR ("RegCloseKey returned %li\n", ret
);
4006 return ERROR_SUCCESS
;
4009 /*******************************************************************************
4010 * EnumPrinterDataExA [WINSPOOL.@]
4012 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4013 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4014 * what Windows 2000 SP1 does.
4017 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
4018 LPBYTE pEnumValues
, DWORD cbEnumValues
,
4019 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
4023 DWORD ret
, dwIndex
, dwBufSize
;
4027 TRACE ("%p %s\n", hPrinter
, pKeyName
);
4029 if (pKeyName
== NULL
|| *pKeyName
== 0)
4030 return ERROR_INVALID_PARAMETER
;
4032 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
4035 ret
= GetLastError ();
4036 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
4040 hHeap
= GetProcessHeap ();
4043 ERR ("GetProcessHeap failed\n");
4044 return ERROR_OUTOFMEMORY
;
4047 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
4048 if (pKeyNameW
== NULL
)
4050 ERR ("Failed to allocate %li bytes from process heap\n",
4051 (LONG
) len
* sizeof (WCHAR
));
4052 return ERROR_OUTOFMEMORY
;
4055 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
4057 ret
= GetLastError ();
4058 ERR ("MultiByteToWideChar failed with code %li\n", ret
);
4059 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4060 WARN ("HeapFree failed with code %li\n", GetLastError ());
4064 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
4065 pcbEnumValues
, pnEnumValues
);
4066 if (ret
!= ERROR_SUCCESS
)
4068 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4069 WARN ("HeapFree failed with code %li\n", GetLastError ());
4070 TRACE ("EnumPrinterDataExW returned %li\n", ret
);
4074 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
4076 ret
= GetLastError ();
4077 ERR ("HeapFree failed with code %li\n", ret
);
4081 if (*pnEnumValues
== 0) /* empty key */
4082 return ERROR_SUCCESS
;
4085 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
4087 PPRINTER_ENUM_VALUESW ppev
=
4088 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
4090 if (dwBufSize
< ppev
->cbValueName
)
4091 dwBufSize
= ppev
->cbValueName
;
4093 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
4094 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
4095 dwBufSize
= ppev
->cbData
;
4098 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize
);
4100 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
4101 if (pBuffer
== NULL
)
4103 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize
);
4104 return ERROR_OUTOFMEMORY
;
4107 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
4109 PPRINTER_ENUM_VALUESW ppev
=
4110 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
4112 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
4113 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
4117 ret
= GetLastError ();
4118 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
4119 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4120 WARN ("HeapFree failed with code %li\n", GetLastError ());
4124 memcpy (ppev
->pValueName
, pBuffer
, len
);
4126 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
4128 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
4129 ppev
->dwType
!= REG_MULTI_SZ
)
4132 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
4133 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
4136 ret
= GetLastError ();
4137 ERR ("WideCharToMultiByte failed with code %li\n", ret
);
4138 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4139 WARN ("HeapFree failed with code %li\n", GetLastError ());
4143 memcpy (ppev
->pData
, pBuffer
, len
);
4145 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
4146 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
4149 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
4151 ret
= GetLastError ();
4152 ERR ("HeapFree failed with code %li\n", ret
);
4156 return ERROR_SUCCESS
;
4159 /******************************************************************************
4160 * AbortPrinter (WINSPOOL.@)
4162 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
4164 FIXME("(%p), stub!\n", hPrinter
);
4168 /******************************************************************************
4169 * AddPortA (WINSPOOL.@)
4171 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
4173 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName
),hWnd
,debugstr_a(pMonitorName
));
4177 /******************************************************************************
4178 * AddPortW (WINSPOOL.@)
4180 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
4182 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName
),hWnd
,debugstr_w(pMonitorName
));
4186 /******************************************************************************
4187 * AddPortExA (WINSPOOL.@)
4189 * Adds a print spooler port without presenting a user interface.
4191 BOOL WINAPI
AddPortExA(HANDLE hMonitor
, LPSTR pName
, DWORD Level
, LPBYTE lpBuffer
, LPSTR lpMonitorName
)
4193 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor
, debugstr_a(pName
), Level
,
4194 lpBuffer
, debugstr_a(lpMonitorName
));
4198 /******************************************************************************
4199 * AddPortExW (WINSPOOL.@)
4203 BOOL WINAPI
AddPortExW(HANDLE hMonitor
, LPWSTR pName
, DWORD Level
, LPBYTE lpBuffer
, LPWSTR lpMonitorName
)
4205 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor
, debugstr_w(pName
), Level
,
4206 lpBuffer
, debugstr_w(lpMonitorName
));
4210 /******************************************************************************
4211 * AddPrinterConnectionA (WINSPOOL.@)
4213 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
4215 FIXME("%s\n", debugstr_a(pName
));
4219 /******************************************************************************
4220 * AddPrinterConnectionW (WINSPOOL.@)
4222 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
4224 FIXME("%s\n", debugstr_w(pName
));
4228 /******************************************************************************
4229 * AddPrinterDriverExW (WINSPOOL.@)
4231 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD Level
,
4232 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
4234 FIXME("%s %ld %p %ld\n", debugstr_w(pName
),
4235 Level
, pDriverInfo
, dwFileCopyFlags
);
4236 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
4240 /******************************************************************************
4241 * AddPrinterDriverExA (WINSPOOL.@)
4243 BOOL WINAPI
AddPrinterDriverExA( LPSTR pName
, DWORD Level
,
4244 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
4246 FIXME("%s %ld %p %ld\n", debugstr_a(pName
),
4247 Level
, pDriverInfo
, dwFileCopyFlags
);
4248 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
4252 /******************************************************************************
4253 * ConfigurePortA (WINSPOOL.@)
4255 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
4257 FIXME("%s %p %s\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
4261 /******************************************************************************
4262 * ConfigurePortW (WINSPOOL.@)
4264 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
4266 FIXME("%s %p %s\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
4270 /******************************************************************************
4271 * ConnectToPrinterDlg (WINSPOOL.@)
4273 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
4275 FIXME("%p %lx\n", hWnd
, Flags
);
4279 /******************************************************************************
4280 * DeletePrinterConnectionA (WINSPOOL.@)
4282 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
4284 FIXME("%s\n", debugstr_a(pName
));
4288 /******************************************************************************
4289 * DeletePrinterConnectionW (WINSPOOL.@)
4291 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
4293 FIXME("%s\n", debugstr_w(pName
));
4297 /******************************************************************************
4298 * DeletePrinterDriverExW (WINSPOOL.@)
4300 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
4301 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
4303 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4304 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
4308 /******************************************************************************
4309 * DeletePrinterDriverExA (WINSPOOL.@)
4311 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
4312 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
4314 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4315 debugstr_a(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
4319 /******************************************************************************
4320 * DeletePrinterDataExW (WINSPOOL.@)
4322 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
4325 FIXME("%p %s %s\n", hPrinter
,
4326 debugstr_w(pKeyName
), debugstr_w(pValueName
));
4327 return ERROR_INVALID_PARAMETER
;
4330 /******************************************************************************
4331 * DeletePrinterDataExA (WINSPOOL.@)
4333 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
4336 FIXME("%p %s %s\n", hPrinter
,
4337 debugstr_a(pKeyName
), debugstr_a(pValueName
));
4338 return ERROR_INVALID_PARAMETER
;
4341 /******************************************************************************
4342 * DeletePrintProcessorA (WINSPOOL.@)
4344 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
4346 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4347 debugstr_a(pPrintProcessorName
));
4351 /******************************************************************************
4352 * DeletePrintProcessorW (WINSPOOL.@)
4354 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
4356 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4357 debugstr_w(pPrintProcessorName
));
4361 /******************************************************************************
4362 * DeletePrintProvidorA (WINSPOOL.@)
4364 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
4366 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4367 debugstr_a(pPrintProviderName
));
4371 /******************************************************************************
4372 * DeletePrintProvidorW (WINSPOOL.@)
4374 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
4376 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4377 debugstr_w(pPrintProviderName
));
4381 /******************************************************************************
4382 * EnumFormsA (WINSPOOL.@)
4384 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
4385 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4387 FIXME("%p %lx %p %lx %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
4391 /******************************************************************************
4392 * EnumFormsW (WINSPOOL.@)
4394 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
4395 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4397 FIXME("%p %lx %p %lx %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
4401 /*****************************************************************************
4402 * EnumMonitorsA [WINSPOOL.@]
4405 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
4406 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4408 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName
), Level
, pMonitors
,
4409 cbBuf
, pcbNeeded
, pcReturned
);
4410 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4414 /*****************************************************************************
4415 * EnumMonitorsW [WINSPOOL.@]
4418 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
4419 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4421 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName
), Level
, pMonitors
,
4422 cbBuf
, pcbNeeded
, pcReturned
);
4423 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4427 /******************************************************************************
4428 * XcvDataW (WINSPOOL.@)
4431 * There doesn't seem to be an A version...
4433 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
4434 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
4435 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
4437 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv
, debugstr_w(pszDataName
),
4438 pInputData
, cbInputData
, pOutputData
,
4439 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
4443 /*****************************************************************************
4444 * EnumPrinterDataA [WINSPOOL.@]
4447 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
4448 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
4449 DWORD cbData
, LPDWORD pcbData
)
4451 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter
, dwIndex
, pValueName
,
4452 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
4453 return ERROR_NO_MORE_ITEMS
;
4456 /*****************************************************************************
4457 * EnumPrinterDataW [WINSPOOL.@]
4460 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
4461 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
4462 DWORD cbData
, LPDWORD pcbData
)
4464 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter
, dwIndex
, pValueName
,
4465 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
4466 return ERROR_NO_MORE_ITEMS
;
4469 /*****************************************************************************
4470 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
4473 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
4474 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
4475 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4477 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName
),
4478 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
4479 pcbNeeded
, pcReturned
);
4483 /*****************************************************************************
4484 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
4487 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
4488 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
4489 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4491 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName
),
4492 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
4493 pcbNeeded
, pcReturned
);
4497 /*****************************************************************************
4498 * EnumPrintProcessorsA [WINSPOOL.@]
4501 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
4502 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
4504 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName
, pEnvironment
, Level
,
4505 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
4509 /*****************************************************************************
4510 * EnumPrintProcessorsW [WINSPOOL.@]
4513 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
4514 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
4516 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName
),
4517 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
4518 cbBuf
, pcbNeeded
, pcbReturned
);
4522 /*****************************************************************************
4523 * ExtDeviceMode [WINSPOOL.@]
4526 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
4527 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
4530 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd
, hInst
, pDevModeOutput
,
4531 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
4532 debugstr_a(pProfile
), fMode
);
4536 /*****************************************************************************
4537 * FindClosePrinterChangeNotification [WINSPOOL.@]
4540 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
4542 FIXME("Stub: %p\n", hChange
);
4546 /*****************************************************************************
4547 * FindFirstPrinterChangeNotification [WINSPOOL.@]
4550 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
4551 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
4553 FIXME("Stub: %p %lx %lx %p\n",
4554 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
4555 return INVALID_HANDLE_VALUE
;
4558 /*****************************************************************************
4559 * FindNextPrinterChangeNotification [WINSPOOL.@]
4562 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
4563 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
4565 FIXME("Stub: %p %p %p %p\n",
4566 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
4570 /*****************************************************************************
4571 * FreePrinterNotifyInfo [WINSPOOL.@]
4574 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
4576 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
4580 /*****************************************************************************
4581 * GetJobA [WINSPOOL.@]
4584 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
4585 DWORD cbBuf
, LPDWORD pcbNeeded
)
4587 FIXME("Stub: %p %ld %ld %p %ld %p\n", hPrinter
, JobId
, Level
, pJob
,
4592 /*****************************************************************************
4593 * GetJobW [WINSPOOL.@]
4596 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
4597 DWORD cbBuf
, LPDWORD pcbNeeded
)
4599 FIXME("Stub: %p %ld %ld %p %ld %p\n", hPrinter
, JobId
, Level
, pJob
,
4604 /*****************************************************************************
4605 * ScheduleJob [WINSPOOL.@]
4608 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
4610 opened_printer_t
*printer
;
4612 struct list
*cursor
, *cursor2
;
4614 TRACE("(%p, %lx)\n", hPrinter
, dwJobID
);
4615 EnterCriticalSection(&printer_handles_cs
);
4616 printer
= get_opened_printer(hPrinter
);
4620 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->jobs
)
4622 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
4625 if(job
->job_id
!= dwJobID
) continue;
4627 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
4628 if(hf
!= INVALID_HANDLE_VALUE
)
4630 FIXME("need to schedule job %ld filename %s\n", job
->job_id
, debugstr_w(job
->filename
));
4632 DeleteFileW(job
->filename
);
4634 list_remove(cursor
);
4635 HeapFree(GetProcessHeap(), 0, job
->filename
);
4636 HeapFree(GetProcessHeap(), 0, job
);
4641 LeaveCriticalSection(&printer_handles_cs
);